From 274782b89e5c464ac4f4f446184247ffc38b7293 Mon Sep 17 00:00:00 2001 From: life Date: Sun, 9 Nov 2014 16:24:19 +0800 Subject: [PATCH 01/12] member center, blog redesign --- app/controllers/BlogController.go | 1034 +++- app/controllers/PreviewController.go | 101 + app/controllers/admin/AdminController.go | 4 +- app/controllers/admin/AdminUserController.go | 45 +- app/controllers/init.go | 7 +- .../member/MemberBaseController.go | 59 + .../member/MemberBlogController.go | 428 ++ .../member/MemberIndexController.go | 37 + .../member/MemberUserController.go | 45 + app/controllers/member/init.go | 133 + app/controllers/member/个人中心.md | 2 + app/db/Mgo.go | 70 +- app/info/BlogCustom.go | 45 + app/info/BlogInfo.go | 44 +- app/info/ThemeInfo.go | 26 + app/info/UserInfo.go | 41 + app/init.go | 14 +- app/lea/File.go | 122 +- app/lea/Vd.go | 25 + app/lea/archive/tar.go | 230 + app/lea/archive/zip.go | 192 + app/lea/blog/Template.go | 302 ++ app/lea/netutil/NetUtil.go | 10 + app/lea/route/Route.go | 6 +- app/service/BlogService.go | 470 +- app/service/NoteService.go | 44 +- app/service/ThemeService.go | 477 ++ app/service/UpgradeService.go | 31 +- app/service/UserService.go | 85 +- app/service/init.go | 5 +- app/views/member/blog/add_single.html | 101 + app/views/member/blog/base.html | 115 + app/views/member/blog/cate.html | 47 + app/views/member/blog/comment.html | 92 + app/views/member/blog/paging.html | 76 + app/views/member/blog/single.html | 70 + app/views/member/blog/theme.html | 221 + app/views/member/blog/update_theme.html | 334 ++ app/views/member/end.html | 3 + app/views/member/footer.html | 35 + app/views/member/index.html | 81 + app/views/member/nav.html | 137 + app/views/member/top.html | 118 + app/views/member/user/add_account.html | 80 + app/views/member/user/avatar.html | 53 + app/views/member/user/email.html | 117 + app/views/member/user/password.html | 74 + app/views/member/user/username.html | 57 + app/views/member/个人中心.md | 0 app/views/note/note-dev.html | 28 +- app/views/note/note.html | 28 +- .../share/note_notebook_share_user_infos.html | 8 +- conf/routes-default | 73 +- messages/msg.en | 9 + messages/msg.zh | 9 + public/blog/README.md | 5 + public/blog/css/share_comment.css | 325 ++ public/blog/js/bootstrap-dialog.min.js | 1 + public/blog/js/bootstrap-hover-dropdown.js | 111 + public/blog/js/ck/common-min.js | 1 + public/blog/js/common.js | 419 ++ public/blog/js/jquery-cookie-min.js | 1 + public/blog/js/jquery.qrcode.min.js | 28 + public/blog/js/jsrender.js | 1626 ++++++ public/blog/js/share_comment.js | 372 ++ public/blog/themes/README.md | 1 + public/blog/themes/default/404.html | 47 + public/blog/themes/default/archive.html | 30 + public/blog/themes/default/cate.html | 42 + public/blog/themes/default/footer.html | 51 + public/blog/themes/default/header.html | 120 + public/blog/themes/default/highlight.html | 6 + .../themes/default/images/leanote-icon.jpg | Bin 0 -> 25308 bytes .../blog/themes/default/images/loading-32.gif | Bin 0 -> 4769 bytes public/blog/themes/default/images/noise.png | Bin 0 -> 10791 bytes .../blog/themes/default/images/screenshot.png | Bin 0 -> 111868 bytes .../themes/default/images/triangle_2x.png | Bin 0 -> 629 bytes public/blog/themes/default/index.html | 39 + public/blog/themes/default/page.html | 1 + public/blog/themes/default/paging.html | 27 + public/blog/themes/default/post.html | 143 + public/blog/themes/default/search.html | 49 + public/blog/themes/default/share_comment.html | 172 + public/blog/themes/default/single.html | 53 + public/blog/themes/default/style.css | 505 ++ public/blog/themes/default/tag_posts.html | 47 + public/blog/themes/default/tags.html | 26 + public/blog/themes/default/theme.json | 27 + public/blog/themes/elegant/404.html | 47 + public/blog/themes/elegant/archive.html | 30 + public/blog/themes/elegant/cate.html | 42 + public/blog/themes/elegant/footer.html | 51 + public/blog/themes/elegant/header.html | 122 + public/blog/themes/elegant/highlight.html | 6 + .../blog/themes/elegant/images/loading-32.gif | Bin 0 -> 4769 bytes public/blog/themes/elegant/images/noise.png | Bin 0 -> 10791 bytes .../blog/themes/elegant/images/screenshot.png | Bin 0 -> 85060 bytes .../themes/elegant/images/triangle_2x.png | Bin 0 -> 629 bytes public/blog/themes/elegant/index.html | 39 + public/blog/themes/elegant/paging.html | 27 + public/blog/themes/elegant/post.html | 143 + public/blog/themes/elegant/search.html | 49 + public/blog/themes/elegant/share_comment.html | 172 + public/blog/themes/elegant/single.html | 53 + public/blog/themes/elegant/style.css | 519 ++ public/blog/themes/elegant/tag_posts.html | 47 + public/blog/themes/elegant/tags.html | 26 + public/blog/themes/elegant/theme.json | 31 + public/blog/themes/nav_fixed/404.html | 47 + public/blog/themes/nav_fixed/archive.html | 30 + public/blog/themes/nav_fixed/cate.html | 42 + public/blog/themes/nav_fixed/footer.html | 51 + public/blog/themes/nav_fixed/header.html | 120 + public/blog/themes/nav_fixed/highlight.html | 6 + .../themes/nav_fixed/images/loading-32.gif | Bin 0 -> 4769 bytes public/blog/themes/nav_fixed/images/noise.png | Bin 0 -> 10791 bytes .../themes/nav_fixed/images/screenshot.png | Bin 0 -> 139058 bytes .../themes/nav_fixed/images/triangle_2x.png | Bin 0 -> 629 bytes public/blog/themes/nav_fixed/index.html | 39 + public/blog/themes/nav_fixed/paging.html | 27 + public/blog/themes/nav_fixed/post.html | 143 + public/blog/themes/nav_fixed/search.html | 49 + .../blog/themes/nav_fixed/share_comment.html | 172 + public/blog/themes/nav_fixed/single.html | 53 + public/blog/themes/nav_fixed/style.css | 556 ++ public/blog/themes/nav_fixed/tag_posts.html | 47 + public/blog/themes/nav_fixed/tags.html | 26 + public/blog/themes/nav_fixed/theme.json | 27 + public/blog/themes/nav_fixed/view.html | 142 + public/js/app/import_theme.js | 114 + public/member/css/member.css | 4293 +++++++++++++++ public/member/css/member.less | 4825 +++++++++++++++++ public/member/js/ace/ace.js | 1 + public/member/js/ace/ext-beautify.js | 1 + public/member/js/ace/ext-chromevox.js | 1 + .../js/ace/ext-elastic_tabstops_lite.js | 1 + public/member/js/ace/ext-emmet.js | 1 + public/member/js/ace/ext-error_marker.js | 1 + public/member/js/ace/ext-keybinding_menu.js | 1 + public/member/js/ace/ext-language_tools.js | 1 + public/member/js/ace/ext-linking.js | 1 + public/member/js/ace/ext-modelist.js | 1 + public/member/js/ace/ext-old_ie.js | 1 + public/member/js/ace/ext-prompt.js | 1 + public/member/js/ace/ext-searchbox.js | 1 + public/member/js/ace/ext-settings_menu.js | 1 + public/member/js/ace/ext-spellcheck.js | 1 + public/member/js/ace/ext-split.js | 1 + public/member/js/ace/ext-static_highlight.js | 1 + public/member/js/ace/ext-statusbar.js | 1 + public/member/js/ace/ext-textarea.js | 1 + public/member/js/ace/ext-themelist.js | 1 + public/member/js/ace/ext-whitespace.js | 1 + public/member/js/ace/keybinding-emacs.js | 1 + public/member/js/ace/keybinding-vim.js | 1 + public/member/js/ace/mode-abap.js | 1 + public/member/js/ace/mode-actionscript.js | 1 + public/member/js/ace/mode-ada.js | 1 + public/member/js/ace/mode-apache_conf.js | 1 + public/member/js/ace/mode-applescript.js | 1 + public/member/js/ace/mode-asciidoc.js | 1 + public/member/js/ace/mode-assembly_x86.js | 1 + public/member/js/ace/mode-autohotkey.js | 1 + public/member/js/ace/mode-batchfile.js | 1 + public/member/js/ace/mode-c9search.js | 1 + public/member/js/ace/mode-c_cpp.js | 1 + public/member/js/ace/mode-cirru.js | 1 + public/member/js/ace/mode-clojure.js | 1 + public/member/js/ace/mode-cobol.js | 1 + public/member/js/ace/mode-coffee.js | 1 + public/member/js/ace/mode-coldfusion.js | 1 + public/member/js/ace/mode-csharp.js | 1 + public/member/js/ace/mode-css.js | 1 + public/member/js/ace/mode-curly.js | 1 + public/member/js/ace/mode-d.js | 1 + public/member/js/ace/mode-dart.js | 1 + public/member/js/ace/mode-diff.js | 1 + public/member/js/ace/mode-django.js | 1 + public/member/js/ace/mode-dockerfile.js | 1 + public/member/js/ace/mode-dot.js | 1 + public/member/js/ace/mode-ejs.js | 1 + public/member/js/ace/mode-erlang.js | 1 + public/member/js/ace/mode-forth.js | 1 + public/member/js/ace/mode-ftl.js | 1 + public/member/js/ace/mode-gherkin.js | 1 + public/member/js/ace/mode-glsl.js | 1 + public/member/js/ace/mode-golang.js | 1 + public/member/js/ace/mode-groovy.js | 1 + public/member/js/ace/mode-haml.js | 1 + public/member/js/ace/mode-handlebars.js | 1 + public/member/js/ace/mode-haskell.js | 1 + public/member/js/ace/mode-haxe.js | 1 + public/member/js/ace/mode-html.js | 1 + public/member/js/ace/mode-html_completions.js | 1 + public/member/js/ace/mode-html_ruby.js | 1 + public/member/js/ace/mode-ini.js | 1 + public/member/js/ace/mode-jack.js | 1 + public/member/js/ace/mode-jade.js | 1 + public/member/js/ace/mode-java.js | 1 + public/member/js/ace/mode-javascript.js | 1 + public/member/js/ace/mode-json.js | 1 + public/member/js/ace/mode-jsoniq.js | 1 + public/member/js/ace/mode-jsp.js | 1 + public/member/js/ace/mode-jsx.js | 1 + public/member/js/ace/mode-julia.js | 1 + public/member/js/ace/mode-latex.js | 1 + public/member/js/ace/mode-less.js | 1 + public/member/js/ace/mode-liquid.js | 1 + public/member/js/ace/mode-lisp.js | 1 + public/member/js/ace/mode-livescript.js | 1 + public/member/js/ace/mode-logiql.js | 1 + public/member/js/ace/mode-lsl.js | 1 + public/member/js/ace/mode-lua.js | 1 + public/member/js/ace/mode-luapage.js | 1 + public/member/js/ace/mode-lucene.js | 1 + public/member/js/ace/mode-makefile.js | 1 + public/member/js/ace/mode-markdown.js | 1 + public/member/js/ace/mode-matlab.js | 1 + public/member/js/ace/mode-mel.js | 1 + public/member/js/ace/mode-mushcode.js | 1 + .../member/js/ace/mode-mushcode_high_rules.js | 1 + public/member/js/ace/mode-mysql.js | 1 + public/member/js/ace/mode-nix.js | 1 + public/member/js/ace/mode-objectivec.js | 1 + public/member/js/ace/mode-ocaml.js | 1 + public/member/js/ace/mode-pascal.js | 1 + public/member/js/ace/mode-perl.js | 1 + public/member/js/ace/mode-pgsql.js | 1 + public/member/js/ace/mode-php.js | 1 + public/member/js/ace/mode-plain_text.js | 1 + public/member/js/ace/mode-powershell.js | 1 + public/member/js/ace/mode-prolog.js | 1 + public/member/js/ace/mode-properties.js | 1 + public/member/js/ace/mode-protobuf.js | 1 + public/member/js/ace/mode-python.js | 1 + public/member/js/ace/mode-r.js | 1 + public/member/js/ace/mode-rdoc.js | 1 + public/member/js/ace/mode-rhtml.js | 1 + public/member/js/ace/mode-ruby.js | 1 + public/member/js/ace/mode-rust.js | 1 + public/member/js/ace/mode-sass.js | 1 + public/member/js/ace/mode-scad.js | 1 + public/member/js/ace/mode-scala.js | 1 + public/member/js/ace/mode-scheme.js | 1 + public/member/js/ace/mode-scss.js | 1 + public/member/js/ace/mode-sh.js | 1 + public/member/js/ace/mode-sjs.js | 1 + public/member/js/ace/mode-smarty.js | 1 + public/member/js/ace/mode-snippets.js | 1 + public/member/js/ace/mode-soy_template.js | 1 + public/member/js/ace/mode-space.js | 1 + public/member/js/ace/mode-sql.js | 1 + public/member/js/ace/mode-stylus.js | 1 + public/member/js/ace/mode-svg.js | 1 + public/member/js/ace/mode-tcl.js | 1 + public/member/js/ace/mode-tex.js | 1 + public/member/js/ace/mode-text.js | 0 public/member/js/ace/mode-textile.js | 1 + public/member/js/ace/mode-toml.js | 1 + public/member/js/ace/mode-twig.js | 1 + public/member/js/ace/mode-typescript.js | 1 + public/member/js/ace/mode-vala.js | 1 + public/member/js/ace/mode-vbscript.js | 1 + public/member/js/ace/mode-velocity.js | 1 + public/member/js/ace/mode-verilog.js | 1 + public/member/js/ace/mode-vhdl.js | 1 + public/member/js/ace/mode-xml.js | 1 + public/member/js/ace/mode-xquery.js | 1 + public/member/js/ace/mode-yaml.js | 1 + public/member/js/ace/snippets/abap.js | 1 + public/member/js/ace/snippets/actionscript.js | 1 + public/member/js/ace/snippets/ada.js | 1 + public/member/js/ace/snippets/apache_conf.js | 1 + public/member/js/ace/snippets/applescript.js | 1 + public/member/js/ace/snippets/asciidoc.js | 1 + public/member/js/ace/snippets/assembly_x86.js | 1 + public/member/js/ace/snippets/autohotkey.js | 1 + public/member/js/ace/snippets/batchfile.js | 1 + public/member/js/ace/snippets/c9search.js | 1 + public/member/js/ace/snippets/c_cpp.js | 1 + public/member/js/ace/snippets/cirru.js | 1 + public/member/js/ace/snippets/clojure.js | 1 + public/member/js/ace/snippets/cobol.js | 1 + public/member/js/ace/snippets/coffee.js | 1 + public/member/js/ace/snippets/coldfusion.js | 1 + public/member/js/ace/snippets/csharp.js | 1 + public/member/js/ace/snippets/css.js | 1 + public/member/js/ace/snippets/curly.js | 1 + public/member/js/ace/snippets/d.js | 1 + public/member/js/ace/snippets/dart.js | 1 + public/member/js/ace/snippets/diff.js | 1 + public/member/js/ace/snippets/django.js | 1 + public/member/js/ace/snippets/dockerfile.js | 1 + public/member/js/ace/snippets/dot.js | 1 + public/member/js/ace/snippets/ejs.js | 1 + public/member/js/ace/snippets/erlang.js | 1 + public/member/js/ace/snippets/forth.js | 1 + public/member/js/ace/snippets/ftl.js | 1 + public/member/js/ace/snippets/gherkin.js | 1 + public/member/js/ace/snippets/glsl.js | 1 + public/member/js/ace/snippets/golang.js | 1 + public/member/js/ace/snippets/groovy.js | 1 + public/member/js/ace/snippets/haml.js | 1 + public/member/js/ace/snippets/handlebars.js | 1 + public/member/js/ace/snippets/haskell.js | 1 + public/member/js/ace/snippets/haxe.js | 1 + public/member/js/ace/snippets/html.js | 1 + .../js/ace/snippets/html_completions.js | 1 + public/member/js/ace/snippets/html_ruby.js | 1 + public/member/js/ace/snippets/ini.js | 1 + public/member/js/ace/snippets/jack.js | 1 + public/member/js/ace/snippets/jade.js | 1 + public/member/js/ace/snippets/java.js | 1 + public/member/js/ace/snippets/javascript.js | 1 + public/member/js/ace/snippets/json.js | 1 + public/member/js/ace/snippets/jsoniq.js | 1 + public/member/js/ace/snippets/jsp.js | 1 + public/member/js/ace/snippets/jsx.js | 1 + public/member/js/ace/snippets/julia.js | 1 + public/member/js/ace/snippets/latex.js | 1 + public/member/js/ace/snippets/less.js | 1 + public/member/js/ace/snippets/liquid.js | 1 + public/member/js/ace/snippets/lisp.js | 1 + public/member/js/ace/snippets/livescript.js | 1 + public/member/js/ace/snippets/logiql.js | 1 + public/member/js/ace/snippets/lsl.js | 1 + public/member/js/ace/snippets/lua.js | 1 + public/member/js/ace/snippets/luapage.js | 1 + public/member/js/ace/snippets/lucene.js | 1 + public/member/js/ace/snippets/makefile.js | 1 + public/member/js/ace/snippets/markdown.js | 1 + public/member/js/ace/snippets/matlab.js | 1 + public/member/js/ace/snippets/mel.js | 1 + public/member/js/ace/snippets/mushcode.js | 1 + .../js/ace/snippets/mushcode_high_rules.js | 1 + public/member/js/ace/snippets/mysql.js | 1 + public/member/js/ace/snippets/nix.js | 1 + public/member/js/ace/snippets/objectivec.js | 1 + public/member/js/ace/snippets/ocaml.js | 1 + public/member/js/ace/snippets/pascal.js | 1 + public/member/js/ace/snippets/perl.js | 1 + public/member/js/ace/snippets/pgsql.js | 1 + public/member/js/ace/snippets/php.js | 1 + public/member/js/ace/snippets/plain_text.js | 1 + public/member/js/ace/snippets/powershell.js | 1 + public/member/js/ace/snippets/prolog.js | 1 + public/member/js/ace/snippets/properties.js | 1 + public/member/js/ace/snippets/protobuf.js | 1 + public/member/js/ace/snippets/python.js | 1 + public/member/js/ace/snippets/r.js | 1 + public/member/js/ace/snippets/rdoc.js | 1 + public/member/js/ace/snippets/rhtml.js | 1 + public/member/js/ace/snippets/ruby.js | 1 + public/member/js/ace/snippets/rust.js | 1 + public/member/js/ace/snippets/sass.js | 1 + public/member/js/ace/snippets/scad.js | 1 + public/member/js/ace/snippets/scala.js | 1 + public/member/js/ace/snippets/scheme.js | 1 + public/member/js/ace/snippets/scss.js | 1 + public/member/js/ace/snippets/sh.js | 1 + public/member/js/ace/snippets/sjs.js | 1 + public/member/js/ace/snippets/smarty.js | 1 + public/member/js/ace/snippets/snippets.js | 1 + public/member/js/ace/snippets/soy_template.js | 1 + public/member/js/ace/snippets/space.js | 1 + public/member/js/ace/snippets/sql.js | 1 + public/member/js/ace/snippets/stylus.js | 1 + public/member/js/ace/snippets/svg.js | 1 + public/member/js/ace/snippets/tcl.js | 1 + public/member/js/ace/snippets/tex.js | 1 + public/member/js/ace/snippets/text.js | 1 + public/member/js/ace/snippets/textile.js | 1 + public/member/js/ace/snippets/toml.js | 1 + public/member/js/ace/snippets/twig.js | 1 + public/member/js/ace/snippets/typescript.js | 1 + public/member/js/ace/snippets/vala.js | 1 + public/member/js/ace/snippets/vbscript.js | 1 + public/member/js/ace/snippets/velocity.js | 1 + public/member/js/ace/snippets/verilog.js | 1 + public/member/js/ace/snippets/vhdl.js | 1 + public/member/js/ace/snippets/xml.js | 1 + public/member/js/ace/snippets/xquery.js | 1 + public/member/js/ace/snippets/yaml.js | 1 + public/member/js/ace/theme-ambiance.js | 1 + public/member/js/ace/theme-chaos.js | 1 + public/member/js/ace/theme-chrome.js | 1 + public/member/js/ace/theme-cloud9_day.js | 1 + public/member/js/ace/theme-cloud9_night.js | 1 + .../js/ace/theme-cloud9_night_low_color.js | 1 + public/member/js/ace/theme-clouds.js | 1 + public/member/js/ace/theme-clouds_midnight.js | 1 + public/member/js/ace/theme-cobalt.js | 1 + public/member/js/ace/theme-crimson_editor.js | 1 + public/member/js/ace/theme-dawn.js | 1 + public/member/js/ace/theme-dreamweaver.js | 1 + public/member/js/ace/theme-eclipse.js | 1 + public/member/js/ace/theme-github.js | 1 + public/member/js/ace/theme-idle_fingers.js | 1 + public/member/js/ace/theme-katzenmilch.js | 1 + public/member/js/ace/theme-kr.js | 1 + public/member/js/ace/theme-kuroir.js | 1 + public/member/js/ace/theme-merbivore.js | 1 + public/member/js/ace/theme-merbivore_soft.js | 1 + public/member/js/ace/theme-mono_industrial.js | 1 + public/member/js/ace/theme-monokai.js | 1 + public/member/js/ace/theme-pastel_on_dark.js | 1 + public/member/js/ace/theme-solarized_dark.js | 1 + public/member/js/ace/theme-solarized_light.js | 1 + public/member/js/ace/theme-terminal.js | 1 + public/member/js/ace/theme-textmate.js | 1 + public/member/js/ace/theme-tomorrow.js | 1 + public/member/js/ace/theme-tomorrow_night.js | 1 + .../js/ace/theme-tomorrow_night_blue.js | 1 + .../js/ace/theme-tomorrow_night_bright.js | 1 + .../js/ace/theme-tomorrow_night_eighties.js | 1 + public/member/js/ace/theme-twilight.js | 1 + public/member/js/ace/theme-vibrant_ink.js | 1 + public/member/js/ace/theme-xcode.js | 1 + public/member/js/ace/worker-coffee.js | 1 + public/member/js/ace/worker-css.js | 1 + public/member/js/ace/worker-html.js | 1 + public/member/js/ace/worker-javascript.js | 1 + public/member/js/ace/worker-json.js | 1 + public/member/js/ace/worker-lua.js | 1 + public/member/js/ace/worker-php.js | 1 + public/member/js/ace/worker-xquery.js | 1 + public/member/js/jquery.sortable.js | 85 + public/member/js/member.js | 568 ++ 428 files changed, 23054 insertions(+), 480 deletions(-) create mode 100644 app/controllers/PreviewController.go create mode 100644 app/controllers/member/MemberBaseController.go create mode 100644 app/controllers/member/MemberBlogController.go create mode 100644 app/controllers/member/MemberIndexController.go create mode 100644 app/controllers/member/MemberUserController.go create mode 100644 app/controllers/member/init.go create mode 100644 app/controllers/member/个人中心.md create mode 100644 app/info/BlogCustom.go create mode 100644 app/info/ThemeInfo.go create mode 100644 app/lea/archive/tar.go create mode 100644 app/lea/archive/zip.go create mode 100644 app/lea/blog/Template.go create mode 100644 app/service/ThemeService.go create mode 100644 app/views/member/blog/add_single.html create mode 100644 app/views/member/blog/base.html create mode 100644 app/views/member/blog/cate.html create mode 100644 app/views/member/blog/comment.html create mode 100644 app/views/member/blog/paging.html create mode 100644 app/views/member/blog/single.html create mode 100644 app/views/member/blog/theme.html create mode 100644 app/views/member/blog/update_theme.html create mode 100644 app/views/member/end.html create mode 100644 app/views/member/footer.html create mode 100644 app/views/member/index.html create mode 100644 app/views/member/nav.html create mode 100644 app/views/member/top.html create mode 100644 app/views/member/user/add_account.html create mode 100644 app/views/member/user/avatar.html create mode 100644 app/views/member/user/email.html create mode 100644 app/views/member/user/password.html create mode 100644 app/views/member/user/username.html create mode 100644 app/views/member/个人中心.md create mode 100644 public/blog/README.md create mode 100644 public/blog/css/share_comment.css create mode 100644 public/blog/js/bootstrap-dialog.min.js create mode 100644 public/blog/js/bootstrap-hover-dropdown.js create mode 100644 public/blog/js/ck/common-min.js create mode 100644 public/blog/js/common.js create mode 100644 public/blog/js/jquery-cookie-min.js create mode 100644 public/blog/js/jquery.qrcode.min.js create mode 100644 public/blog/js/jsrender.js create mode 100644 public/blog/js/share_comment.js create mode 100644 public/blog/themes/README.md create mode 100644 public/blog/themes/default/404.html create mode 100644 public/blog/themes/default/archive.html create mode 100644 public/blog/themes/default/cate.html create mode 100644 public/blog/themes/default/footer.html create mode 100644 public/blog/themes/default/header.html create mode 100644 public/blog/themes/default/highlight.html create mode 100644 public/blog/themes/default/images/leanote-icon.jpg create mode 100644 public/blog/themes/default/images/loading-32.gif create mode 100644 public/blog/themes/default/images/noise.png create mode 100644 public/blog/themes/default/images/screenshot.png create mode 100644 public/blog/themes/default/images/triangle_2x.png create mode 100644 public/blog/themes/default/index.html create mode 100644 public/blog/themes/default/page.html create mode 100644 public/blog/themes/default/paging.html create mode 100644 public/blog/themes/default/post.html create mode 100644 public/blog/themes/default/search.html create mode 100644 public/blog/themes/default/share_comment.html create mode 100644 public/blog/themes/default/single.html create mode 100644 public/blog/themes/default/style.css create mode 100644 public/blog/themes/default/tag_posts.html create mode 100644 public/blog/themes/default/tags.html create mode 100644 public/blog/themes/default/theme.json create mode 100644 public/blog/themes/elegant/404.html create mode 100644 public/blog/themes/elegant/archive.html create mode 100644 public/blog/themes/elegant/cate.html create mode 100644 public/blog/themes/elegant/footer.html create mode 100644 public/blog/themes/elegant/header.html create mode 100644 public/blog/themes/elegant/highlight.html create mode 100644 public/blog/themes/elegant/images/loading-32.gif create mode 100644 public/blog/themes/elegant/images/noise.png create mode 100644 public/blog/themes/elegant/images/screenshot.png create mode 100644 public/blog/themes/elegant/images/triangle_2x.png create mode 100644 public/blog/themes/elegant/index.html create mode 100644 public/blog/themes/elegant/paging.html create mode 100644 public/blog/themes/elegant/post.html create mode 100644 public/blog/themes/elegant/search.html create mode 100644 public/blog/themes/elegant/share_comment.html create mode 100644 public/blog/themes/elegant/single.html create mode 100644 public/blog/themes/elegant/style.css create mode 100644 public/blog/themes/elegant/tag_posts.html create mode 100644 public/blog/themes/elegant/tags.html create mode 100644 public/blog/themes/elegant/theme.json create mode 100644 public/blog/themes/nav_fixed/404.html create mode 100644 public/blog/themes/nav_fixed/archive.html create mode 100644 public/blog/themes/nav_fixed/cate.html create mode 100644 public/blog/themes/nav_fixed/footer.html create mode 100644 public/blog/themes/nav_fixed/header.html create mode 100644 public/blog/themes/nav_fixed/highlight.html create mode 100644 public/blog/themes/nav_fixed/images/loading-32.gif create mode 100644 public/blog/themes/nav_fixed/images/noise.png create mode 100644 public/blog/themes/nav_fixed/images/screenshot.png create mode 100644 public/blog/themes/nav_fixed/images/triangle_2x.png create mode 100644 public/blog/themes/nav_fixed/index.html create mode 100644 public/blog/themes/nav_fixed/paging.html create mode 100644 public/blog/themes/nav_fixed/post.html create mode 100644 public/blog/themes/nav_fixed/search.html create mode 100644 public/blog/themes/nav_fixed/share_comment.html create mode 100644 public/blog/themes/nav_fixed/single.html create mode 100644 public/blog/themes/nav_fixed/style.css create mode 100644 public/blog/themes/nav_fixed/tag_posts.html create mode 100644 public/blog/themes/nav_fixed/tags.html create mode 100644 public/blog/themes/nav_fixed/theme.json create mode 100644 public/blog/themes/nav_fixed/view.html create mode 100644 public/js/app/import_theme.js create mode 100644 public/member/css/member.css create mode 100644 public/member/css/member.less create mode 100644 public/member/js/ace/ace.js create mode 100644 public/member/js/ace/ext-beautify.js create mode 100644 public/member/js/ace/ext-chromevox.js create mode 100644 public/member/js/ace/ext-elastic_tabstops_lite.js create mode 100644 public/member/js/ace/ext-emmet.js create mode 100644 public/member/js/ace/ext-error_marker.js create mode 100644 public/member/js/ace/ext-keybinding_menu.js create mode 100644 public/member/js/ace/ext-language_tools.js create mode 100644 public/member/js/ace/ext-linking.js create mode 100644 public/member/js/ace/ext-modelist.js create mode 100644 public/member/js/ace/ext-old_ie.js create mode 100644 public/member/js/ace/ext-prompt.js create mode 100644 public/member/js/ace/ext-searchbox.js create mode 100644 public/member/js/ace/ext-settings_menu.js create mode 100644 public/member/js/ace/ext-spellcheck.js create mode 100644 public/member/js/ace/ext-split.js create mode 100644 public/member/js/ace/ext-static_highlight.js create mode 100644 public/member/js/ace/ext-statusbar.js create mode 100644 public/member/js/ace/ext-textarea.js create mode 100644 public/member/js/ace/ext-themelist.js create mode 100644 public/member/js/ace/ext-whitespace.js create mode 100644 public/member/js/ace/keybinding-emacs.js create mode 100644 public/member/js/ace/keybinding-vim.js create mode 100644 public/member/js/ace/mode-abap.js create mode 100644 public/member/js/ace/mode-actionscript.js create mode 100644 public/member/js/ace/mode-ada.js create mode 100644 public/member/js/ace/mode-apache_conf.js create mode 100644 public/member/js/ace/mode-applescript.js create mode 100644 public/member/js/ace/mode-asciidoc.js create mode 100644 public/member/js/ace/mode-assembly_x86.js create mode 100644 public/member/js/ace/mode-autohotkey.js create mode 100644 public/member/js/ace/mode-batchfile.js create mode 100644 public/member/js/ace/mode-c9search.js create mode 100644 public/member/js/ace/mode-c_cpp.js create mode 100644 public/member/js/ace/mode-cirru.js create mode 100644 public/member/js/ace/mode-clojure.js create mode 100644 public/member/js/ace/mode-cobol.js create mode 100644 public/member/js/ace/mode-coffee.js create mode 100644 public/member/js/ace/mode-coldfusion.js create mode 100644 public/member/js/ace/mode-csharp.js create mode 100644 public/member/js/ace/mode-css.js create mode 100644 public/member/js/ace/mode-curly.js create mode 100644 public/member/js/ace/mode-d.js create mode 100644 public/member/js/ace/mode-dart.js create mode 100644 public/member/js/ace/mode-diff.js create mode 100644 public/member/js/ace/mode-django.js create mode 100644 public/member/js/ace/mode-dockerfile.js create mode 100644 public/member/js/ace/mode-dot.js create mode 100644 public/member/js/ace/mode-ejs.js create mode 100644 public/member/js/ace/mode-erlang.js create mode 100644 public/member/js/ace/mode-forth.js create mode 100644 public/member/js/ace/mode-ftl.js create mode 100644 public/member/js/ace/mode-gherkin.js create mode 100644 public/member/js/ace/mode-glsl.js create mode 100644 public/member/js/ace/mode-golang.js create mode 100644 public/member/js/ace/mode-groovy.js create mode 100644 public/member/js/ace/mode-haml.js create mode 100644 public/member/js/ace/mode-handlebars.js create mode 100644 public/member/js/ace/mode-haskell.js create mode 100644 public/member/js/ace/mode-haxe.js create mode 100644 public/member/js/ace/mode-html.js create mode 100644 public/member/js/ace/mode-html_completions.js create mode 100644 public/member/js/ace/mode-html_ruby.js create mode 100644 public/member/js/ace/mode-ini.js create mode 100644 public/member/js/ace/mode-jack.js create mode 100644 public/member/js/ace/mode-jade.js create mode 100644 public/member/js/ace/mode-java.js create mode 100644 public/member/js/ace/mode-javascript.js create mode 100644 public/member/js/ace/mode-json.js create mode 100644 public/member/js/ace/mode-jsoniq.js create mode 100644 public/member/js/ace/mode-jsp.js create mode 100644 public/member/js/ace/mode-jsx.js create mode 100644 public/member/js/ace/mode-julia.js create mode 100644 public/member/js/ace/mode-latex.js create mode 100644 public/member/js/ace/mode-less.js create mode 100644 public/member/js/ace/mode-liquid.js create mode 100644 public/member/js/ace/mode-lisp.js create mode 100644 public/member/js/ace/mode-livescript.js create mode 100644 public/member/js/ace/mode-logiql.js create mode 100644 public/member/js/ace/mode-lsl.js create mode 100644 public/member/js/ace/mode-lua.js create mode 100644 public/member/js/ace/mode-luapage.js create mode 100644 public/member/js/ace/mode-lucene.js create mode 100644 public/member/js/ace/mode-makefile.js create mode 100644 public/member/js/ace/mode-markdown.js create mode 100644 public/member/js/ace/mode-matlab.js create mode 100644 public/member/js/ace/mode-mel.js create mode 100644 public/member/js/ace/mode-mushcode.js create mode 100644 public/member/js/ace/mode-mushcode_high_rules.js create mode 100644 public/member/js/ace/mode-mysql.js create mode 100644 public/member/js/ace/mode-nix.js create mode 100644 public/member/js/ace/mode-objectivec.js create mode 100644 public/member/js/ace/mode-ocaml.js create mode 100644 public/member/js/ace/mode-pascal.js create mode 100644 public/member/js/ace/mode-perl.js create mode 100644 public/member/js/ace/mode-pgsql.js create mode 100644 public/member/js/ace/mode-php.js create mode 100644 public/member/js/ace/mode-plain_text.js create mode 100644 public/member/js/ace/mode-powershell.js create mode 100644 public/member/js/ace/mode-prolog.js create mode 100644 public/member/js/ace/mode-properties.js create mode 100644 public/member/js/ace/mode-protobuf.js create mode 100644 public/member/js/ace/mode-python.js create mode 100644 public/member/js/ace/mode-r.js create mode 100644 public/member/js/ace/mode-rdoc.js create mode 100644 public/member/js/ace/mode-rhtml.js create mode 100644 public/member/js/ace/mode-ruby.js create mode 100644 public/member/js/ace/mode-rust.js create mode 100644 public/member/js/ace/mode-sass.js create mode 100644 public/member/js/ace/mode-scad.js create mode 100644 public/member/js/ace/mode-scala.js create mode 100644 public/member/js/ace/mode-scheme.js create mode 100644 public/member/js/ace/mode-scss.js create mode 100644 public/member/js/ace/mode-sh.js create mode 100644 public/member/js/ace/mode-sjs.js create mode 100644 public/member/js/ace/mode-smarty.js create mode 100644 public/member/js/ace/mode-snippets.js create mode 100644 public/member/js/ace/mode-soy_template.js create mode 100644 public/member/js/ace/mode-space.js create mode 100644 public/member/js/ace/mode-sql.js create mode 100644 public/member/js/ace/mode-stylus.js create mode 100644 public/member/js/ace/mode-svg.js create mode 100644 public/member/js/ace/mode-tcl.js create mode 100644 public/member/js/ace/mode-tex.js create mode 100644 public/member/js/ace/mode-text.js create mode 100644 public/member/js/ace/mode-textile.js create mode 100644 public/member/js/ace/mode-toml.js create mode 100644 public/member/js/ace/mode-twig.js create mode 100644 public/member/js/ace/mode-typescript.js create mode 100644 public/member/js/ace/mode-vala.js create mode 100644 public/member/js/ace/mode-vbscript.js create mode 100644 public/member/js/ace/mode-velocity.js create mode 100644 public/member/js/ace/mode-verilog.js create mode 100644 public/member/js/ace/mode-vhdl.js create mode 100644 public/member/js/ace/mode-xml.js create mode 100644 public/member/js/ace/mode-xquery.js create mode 100644 public/member/js/ace/mode-yaml.js create mode 100644 public/member/js/ace/snippets/abap.js create mode 100644 public/member/js/ace/snippets/actionscript.js create mode 100644 public/member/js/ace/snippets/ada.js create mode 100644 public/member/js/ace/snippets/apache_conf.js create mode 100644 public/member/js/ace/snippets/applescript.js create mode 100644 public/member/js/ace/snippets/asciidoc.js create mode 100644 public/member/js/ace/snippets/assembly_x86.js create mode 100644 public/member/js/ace/snippets/autohotkey.js create mode 100644 public/member/js/ace/snippets/batchfile.js create mode 100644 public/member/js/ace/snippets/c9search.js create mode 100644 public/member/js/ace/snippets/c_cpp.js create mode 100644 public/member/js/ace/snippets/cirru.js create mode 100644 public/member/js/ace/snippets/clojure.js create mode 100644 public/member/js/ace/snippets/cobol.js create mode 100644 public/member/js/ace/snippets/coffee.js create mode 100644 public/member/js/ace/snippets/coldfusion.js create mode 100644 public/member/js/ace/snippets/csharp.js create mode 100644 public/member/js/ace/snippets/css.js create mode 100644 public/member/js/ace/snippets/curly.js create mode 100644 public/member/js/ace/snippets/d.js create mode 100644 public/member/js/ace/snippets/dart.js create mode 100644 public/member/js/ace/snippets/diff.js create mode 100644 public/member/js/ace/snippets/django.js create mode 100644 public/member/js/ace/snippets/dockerfile.js create mode 100644 public/member/js/ace/snippets/dot.js create mode 100644 public/member/js/ace/snippets/ejs.js create mode 100644 public/member/js/ace/snippets/erlang.js create mode 100644 public/member/js/ace/snippets/forth.js create mode 100644 public/member/js/ace/snippets/ftl.js create mode 100644 public/member/js/ace/snippets/gherkin.js create mode 100644 public/member/js/ace/snippets/glsl.js create mode 100644 public/member/js/ace/snippets/golang.js create mode 100644 public/member/js/ace/snippets/groovy.js create mode 100644 public/member/js/ace/snippets/haml.js create mode 100644 public/member/js/ace/snippets/handlebars.js create mode 100644 public/member/js/ace/snippets/haskell.js create mode 100644 public/member/js/ace/snippets/haxe.js create mode 100644 public/member/js/ace/snippets/html.js create mode 100644 public/member/js/ace/snippets/html_completions.js create mode 100644 public/member/js/ace/snippets/html_ruby.js create mode 100644 public/member/js/ace/snippets/ini.js create mode 100644 public/member/js/ace/snippets/jack.js create mode 100644 public/member/js/ace/snippets/jade.js create mode 100644 public/member/js/ace/snippets/java.js create mode 100644 public/member/js/ace/snippets/javascript.js create mode 100644 public/member/js/ace/snippets/json.js create mode 100644 public/member/js/ace/snippets/jsoniq.js create mode 100644 public/member/js/ace/snippets/jsp.js create mode 100644 public/member/js/ace/snippets/jsx.js create mode 100644 public/member/js/ace/snippets/julia.js create mode 100644 public/member/js/ace/snippets/latex.js create mode 100644 public/member/js/ace/snippets/less.js create mode 100644 public/member/js/ace/snippets/liquid.js create mode 100644 public/member/js/ace/snippets/lisp.js create mode 100644 public/member/js/ace/snippets/livescript.js create mode 100644 public/member/js/ace/snippets/logiql.js create mode 100644 public/member/js/ace/snippets/lsl.js create mode 100644 public/member/js/ace/snippets/lua.js create mode 100644 public/member/js/ace/snippets/luapage.js create mode 100644 public/member/js/ace/snippets/lucene.js create mode 100644 public/member/js/ace/snippets/makefile.js create mode 100644 public/member/js/ace/snippets/markdown.js create mode 100644 public/member/js/ace/snippets/matlab.js create mode 100644 public/member/js/ace/snippets/mel.js create mode 100644 public/member/js/ace/snippets/mushcode.js create mode 100644 public/member/js/ace/snippets/mushcode_high_rules.js create mode 100644 public/member/js/ace/snippets/mysql.js create mode 100644 public/member/js/ace/snippets/nix.js create mode 100644 public/member/js/ace/snippets/objectivec.js create mode 100644 public/member/js/ace/snippets/ocaml.js create mode 100644 public/member/js/ace/snippets/pascal.js create mode 100644 public/member/js/ace/snippets/perl.js create mode 100644 public/member/js/ace/snippets/pgsql.js create mode 100644 public/member/js/ace/snippets/php.js create mode 100644 public/member/js/ace/snippets/plain_text.js create mode 100644 public/member/js/ace/snippets/powershell.js create mode 100644 public/member/js/ace/snippets/prolog.js create mode 100644 public/member/js/ace/snippets/properties.js create mode 100644 public/member/js/ace/snippets/protobuf.js create mode 100644 public/member/js/ace/snippets/python.js create mode 100644 public/member/js/ace/snippets/r.js create mode 100644 public/member/js/ace/snippets/rdoc.js create mode 100644 public/member/js/ace/snippets/rhtml.js create mode 100644 public/member/js/ace/snippets/ruby.js create mode 100644 public/member/js/ace/snippets/rust.js create mode 100644 public/member/js/ace/snippets/sass.js create mode 100644 public/member/js/ace/snippets/scad.js create mode 100644 public/member/js/ace/snippets/scala.js create mode 100644 public/member/js/ace/snippets/scheme.js create mode 100644 public/member/js/ace/snippets/scss.js create mode 100644 public/member/js/ace/snippets/sh.js create mode 100644 public/member/js/ace/snippets/sjs.js create mode 100644 public/member/js/ace/snippets/smarty.js create mode 100644 public/member/js/ace/snippets/snippets.js create mode 100644 public/member/js/ace/snippets/soy_template.js create mode 100644 public/member/js/ace/snippets/space.js create mode 100644 public/member/js/ace/snippets/sql.js create mode 100644 public/member/js/ace/snippets/stylus.js create mode 100644 public/member/js/ace/snippets/svg.js create mode 100644 public/member/js/ace/snippets/tcl.js create mode 100644 public/member/js/ace/snippets/tex.js create mode 100644 public/member/js/ace/snippets/text.js create mode 100644 public/member/js/ace/snippets/textile.js create mode 100644 public/member/js/ace/snippets/toml.js create mode 100644 public/member/js/ace/snippets/twig.js create mode 100644 public/member/js/ace/snippets/typescript.js create mode 100644 public/member/js/ace/snippets/vala.js create mode 100644 public/member/js/ace/snippets/vbscript.js create mode 100644 public/member/js/ace/snippets/velocity.js create mode 100644 public/member/js/ace/snippets/verilog.js create mode 100644 public/member/js/ace/snippets/vhdl.js create mode 100644 public/member/js/ace/snippets/xml.js create mode 100644 public/member/js/ace/snippets/xquery.js create mode 100644 public/member/js/ace/snippets/yaml.js create mode 100644 public/member/js/ace/theme-ambiance.js create mode 100644 public/member/js/ace/theme-chaos.js create mode 100644 public/member/js/ace/theme-chrome.js create mode 100644 public/member/js/ace/theme-cloud9_day.js create mode 100644 public/member/js/ace/theme-cloud9_night.js create mode 100644 public/member/js/ace/theme-cloud9_night_low_color.js create mode 100644 public/member/js/ace/theme-clouds.js create mode 100644 public/member/js/ace/theme-clouds_midnight.js create mode 100644 public/member/js/ace/theme-cobalt.js create mode 100644 public/member/js/ace/theme-crimson_editor.js create mode 100644 public/member/js/ace/theme-dawn.js create mode 100644 public/member/js/ace/theme-dreamweaver.js create mode 100644 public/member/js/ace/theme-eclipse.js create mode 100644 public/member/js/ace/theme-github.js create mode 100644 public/member/js/ace/theme-idle_fingers.js create mode 100644 public/member/js/ace/theme-katzenmilch.js create mode 100644 public/member/js/ace/theme-kr.js create mode 100644 public/member/js/ace/theme-kuroir.js create mode 100644 public/member/js/ace/theme-merbivore.js create mode 100644 public/member/js/ace/theme-merbivore_soft.js create mode 100644 public/member/js/ace/theme-mono_industrial.js create mode 100644 public/member/js/ace/theme-monokai.js create mode 100644 public/member/js/ace/theme-pastel_on_dark.js create mode 100644 public/member/js/ace/theme-solarized_dark.js create mode 100644 public/member/js/ace/theme-solarized_light.js create mode 100644 public/member/js/ace/theme-terminal.js create mode 100644 public/member/js/ace/theme-textmate.js create mode 100644 public/member/js/ace/theme-tomorrow.js create mode 100644 public/member/js/ace/theme-tomorrow_night.js create mode 100644 public/member/js/ace/theme-tomorrow_night_blue.js create mode 100644 public/member/js/ace/theme-tomorrow_night_bright.js create mode 100644 public/member/js/ace/theme-tomorrow_night_eighties.js create mode 100644 public/member/js/ace/theme-twilight.js create mode 100644 public/member/js/ace/theme-vibrant_ink.js create mode 100644 public/member/js/ace/theme-xcode.js create mode 100644 public/member/js/ace/worker-coffee.js create mode 100644 public/member/js/ace/worker-css.js create mode 100644 public/member/js/ace/worker-html.js create mode 100644 public/member/js/ace/worker-javascript.js create mode 100644 public/member/js/ace/worker-json.js create mode 100644 public/member/js/ace/worker-lua.js create mode 100644 public/member/js/ace/worker-php.js create mode 100644 public/member/js/ace/worker-xquery.js create mode 100644 public/member/js/jquery.sortable.js create mode 100644 public/member/js/member.js diff --git a/app/controllers/BlogController.go b/app/controllers/BlogController.go index 30a79bc..c1cf46c 100644 --- a/app/controllers/BlogController.go +++ b/app/controllers/BlogController.go @@ -1,36 +1,138 @@ package controllers import ( - "strings" - "time" "github.com/revel/revel" -// "encoding/json" - "gopkg.in/mgo.v2/bson" -// . "github.com/leanote/leanote/app/lea" + "strings" + // "encoding/json" "github.com/leanote/leanote/app/info" -// "github.com/leanote/leanote/app/types" -// "io/ioutil" -// "math" -// "os" -// "path" + . "github.com/leanote/leanote/app/lea" + "github.com/leanote/leanote/app/lea/blog" + "gopkg.in/mgo.v2/bson" + // "github.com/leanote/leanote/app/types" + // "io/ioutil" + // "math" + // "os" + // "path" +// "fmt" ) type Blog struct { BaseController } -//----------------------------- -// 前台 +/* +公共 +// 分类 [ok] +$.cates = [{title, cateId}] +// 单页 [ok] +$.singles = [{pageId, title}] +// 博客信息 [ok] +$.blog = {userId, desc, title, logo, openComment, disqusId} -// 域名, 没用 +// 公用url ok +$.indexUrl +$.cateUrl +$.searchUrl +$.postUrl +$.archiveUrl +$.singleUrl +$.themeBaseUrl + +// 静态文件 [ok] +$.jQueryUrl +$.fontAsomeUrl +$.bootstrapCssUrl +$.bootstrapJsUrl +*/ + + +func (c Blog) render(templateName string, themePath string) revel.Result { + isPreview := false + if c.RenderArgs["isPreview"] != nil { + themePath2 := c.RenderArgs["themePath"] + if themePath2 == nil { + return c.E404(); + } + isPreview = true + themePath = themePath2.(string) + c.setPreviewUrl() + } + return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath + "/" + themePath, isPreview) +} + +// 404 +func (c Blog) e404(themePath string) revel.Result { + // 不知道是谁的404, 则用系统的404 + if themePath == "" { + return c.E404(); + } + return c.render("404.html", themePath) +} + +// 二级域名或自定义域名 +// life.leanote.com +// lealife.com func (c Blog) domain() (ok bool, userBlog info.UserBlog) { - return + host := c.Request.Request.Host // a.cc.com:9000 + hostArr := strings.Split(host, ".") + if strings.Contains(host, configService.GetDefaultDomain()) { + // 有二级域名 a.leanoe.com 3个 + if len(hostArr) > 2 { + if userBlog = blogService.GetUserBlogBySubDomain(hostArr[0]); userBlog.UserId != "" { + ok = true + return + } + } + } else { + // 自定义域名 + // 把:9000去掉 + hostArr2 := strings.Split(host, ":") + if userBlog = blogService.GetUserBlogByDomain(hostArr2[0]); userBlog.UserId != "" { + ok = true + return + } + } + ok = false + return +} + +// 渲染模板之 +func (c Blog) setPreviewUrl() { + var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl string + + userId := c.GetUserId() + themeId := c.Session["themeId"] + theme := themeService.GetTheme(userId, themeId) + + blogUrl := siteUrl + "/preview" // blog.leanote.com + userIdOrEmail := userId + + indexUrl = blogUrl + "/" + userIdOrEmail + cateUrl = blogUrl + "/cate" // /notebookId + + postUrl = blogUrl + "/post" // /xxxxx + searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId + singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId + archiveUrl = blogUrl + "/archive/" + userIdOrEmail // blog.leanote.com/archive/userId + tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId + + c.RenderArgs["indexUrl"] = indexUrl + c.RenderArgs["cateUrl"] = cateUrl + c.RenderArgs["postUrl"] = postUrl + c.RenderArgs["searchUrl"] = searchUrl + c.RenderArgs["singleUrl"] = singleUrl // 单页 + c.RenderArgs["archiveUrl"] = archiveUrl + c.RenderArgs["tagsUrl"] = tagsUrl + c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail + + // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的 + c.RenderArgs["themeBaseUrl"] = "/" + theme.Path } // 各种地址设置 func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { // 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com - var indexUrl, viewUrl, searchUrl, cateUrl, aboutMeUrl, staticUrl string + var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl, staticUrl string host := c.Request.Request.Host staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0]) // staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com @@ -38,19 +140,25 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { if userBlog.Domain != "" && configService.AllowCustomDomain() { // ok indexUrl = configService.GetUserUrl(userBlog.Domain) - cateUrl = indexUrl + "/cate" // /xxxxx - viewUrl = indexUrl + "/view" // /xxxxx + cateUrl = indexUrl + "/cate" // /xxxxx + postUrl = indexUrl + "/post" // /xxxxx searchUrl = indexUrl + "/search" // /xxxxx - aboutMeUrl = indexUrl + "/aboutMe" + singleUrl = indexUrl + "/single" + archiveUrl = indexUrl + "/archive" + tagsUrl = indexUrl + "/tags" + tagPostsUrl = indexUrl + "/tag" } else if userBlog.SubDomain != "" { indexUrl = configService.GetUserSubUrl(userBlog.SubDomain) - cateUrl = indexUrl + "/cate" // /xxxxx - viewUrl = indexUrl + "/view" // /xxxxx + cateUrl = indexUrl + "/cate" // /xxxxx + postUrl = indexUrl + "/post" // /xxxxx searchUrl = indexUrl + "/search" // /xxxxx - aboutMeUrl = indexUrl + "/aboutMe" + singleUrl = indexUrl + "/single" + archiveUrl = indexUrl + "/archive" + tagsUrl = indexUrl + "/tags" + tagPostsUrl = indexUrl + "/tag" } else { // ok - blogUrl := configService.GetBlogUrl() + blogUrl := configService.GetBlogUrl() // blog.leanote.com userIdOrEmail := "" if userInfo.Username != "" { userIdOrEmail = userInfo.Username @@ -60,144 +168,327 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { userIdOrEmail = userInfo.UserId.Hex() } indexUrl = blogUrl + "/" + userIdOrEmail - cateUrl = blogUrl + "/cate" // /notebookId - viewUrl = blogUrl + "/view" // /xxxxx - searchUrl = blogUrl + "/search/" + userIdOrEmail // /xxxxx - aboutMeUrl = blogUrl + "/aboutMe/" + userIdOrEmail + cateUrl = blogUrl + "/cate" // /notebookId + postUrl = blogUrl + "/post" // /xxxxx + searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId + singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId + archiveUrl = blogUrl + "/archive/" + userIdOrEmail // blog.leanote.com/archive/userId + tagsUrl = blogUrl + "/tags/" + userIdOrEmail + tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/userId } - + // 分类 // 搜索 // 查看 + c.RenderArgs["siteUrl"] = siteUrl c.RenderArgs["indexUrl"] = indexUrl c.RenderArgs["cateUrl"] = cateUrl - c.RenderArgs["viewUrl"] = viewUrl + c.RenderArgs["postUrl"] = postUrl c.RenderArgs["searchUrl"] = searchUrl - c.RenderArgs["aboutMeUrl"] = aboutMeUrl - c.RenderArgs["staticUrl"] = staticUrl + c.RenderArgs["singleUrl"] = singleUrl // 单页 + c.RenderArgs["archiveUrl"] = archiveUrl + c.RenderArgs["tagsUrl"] = tagsUrl + c.RenderArgs["tagPostsUrl"] = tagPostsUrl + + // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的 + c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath + + // 其它static js + c.RenderArgs["jQueryUrl"] = siteUrl + "/js/jquery-1.9.0.min.js" + + c.RenderArgs["prettifyJsUrl"] = siteUrl + "/js/google-code-prettify/prettify.js" + c.RenderArgs["prettifyCssUrl"] = siteUrl + "/js/google-code-prettify/prettify.css" + + c.RenderArgs["blogCommonJsUrl"] = siteUrl + "/public/blog/js/common.js" + + c.RenderArgs["shareCommentCssUrl"] = siteUrl + "/public/blog/css/share_comment.css" + c.RenderArgs["shareCommentJsUrl"] = siteUrl + "/public/blog/js/share_comment.js" + + c.RenderArgs["fontAwesomeUrl"] = staticUrl + "/css/font-awesome-4.2.0/css/font-awesome.css" + + c.RenderArgs["bootstrapCssUrl"] = siteUrl + "/css/bootstrap.css" + c.RenderArgs["bootstrapJsUrl"] = siteUrl + "/js/bootstrap-min.js" +} + +// 笔记本分类 +// cates = [{title:"xxx", cateId: "xxxx"}, {}] +func (c Blog) getCates(userBlog info.UserBlog) { + notebooks := blogService.ListBlogNotebooks(userBlog.UserId.Hex()) + notebooksMap := map[string]info.Notebook{} + for _, each := range notebooks { + notebooksMap[each.NotebookId.Hex()] = each + } + + var i = 0 + cates := make([]map[string]string, len(notebooks)) + + // 先要保证已有的是正确的排序 + cateIds := userBlog.CateIds + has := map[string]bool{} // cateIds中有的 + if cateIds != nil && len(cateIds) > 0 { + for _, cateId := range cateIds { + if n, ok := notebooksMap[cateId]; ok { + cates[i] = map[string]string{"Title": n.Title, "CateId": n.NotebookId.Hex()} + i++ + has[cateId] = true + } + } + } + // 之后 + for _, n := range notebooks { + id := n.NotebookId.Hex() + if !has[id] { + cates[i] = map[string]string{"Title": n.Title, "CateId": id} + i++ + } + } + c.RenderArgs["cates"] = cates +} + +// 单页 +func (c Blog) getSingles(userId string) { + singles := blogService.GetSingles(userId) + /* + if singles == nil { + return + } + singles2 := make([]map[string]string, len(singles)) + for i, page := range singles { + singles2[i] = map[string]string{"title": page["Title"], "singleId": page["SingleId"]} + } + */ + c.RenderArgs["singles"] = singles +} + +// $.blog = {userId, title, subTitle, desc, openComment, } +func (c Blog) setBlog(userBlog info.UserBlog, userInfo info.User) { + blogInfo := map[string]interface{}{ + "UserId": userBlog.UserId.Hex(), + "Username": userInfo.Username, + "UserLogo": userInfo.Logo, + "Title": userBlog.Title, + "SubTitle": userBlog.SubTitle, + "Logo": userBlog.Logo, + "OpenComment": userBlog.CanComment, + "CommentType": userBlog.CommentType, // leanote, or disqus + "DisqusId": userBlog.DisqusId, + "ThemeId": userBlog.ThemeId, + "SubDomain": userBlog.SubDomain, + "Domain": userBlog.Domain, + } + c.RenderArgs["blogInfo"] = blogInfo + /* + blogInfo := info.BlogInfoCustom{ + UserId: userBlog.UserId.Hex(), + Username: userInfo.Username, + UserLogo: userInfo.Logo, + Title: userBlog.Title, + SubTitle: userBlog.SubTitle, + Logo: userBlog.Logo, + OpenComment: userBlog.CanComment, + CommentType: userBlog.CommentType, // leanote, or disqus + ThemeId: userBlog.ThemeId, + SubDomain: userBlog.SubDomain, + Domain: userBlog.Domain, + } + */ +} + +func (c Blog) setPaging(pageInfo info.Page) { + /* + // 这些分类信息用一个变量 + paging := map[string]interface{}{ // 分页信息 + "CurPage": pageInfo.CurPage, // 当前页 + "TotalPage": pageInfo.TotalPage, // 总页数 + "PerPageSize": pageInfo.PerPageSize, // 每一页的记录数 + "Count": pageInfo.Count, // 总记录数 + } + */ + c.RenderArgs["paging"] = pageInfo } // 公共 -func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.User) (ok bool) { +func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.User) (ok bool, ub info.UserBlog) { if userInfo.UserId == "" { userInfo = userService.GetUserInfoByAny(userId) if userInfo.UserId == "" { - return + return false, userBlog } } - c.RenderArgs["userInfo"] = userInfo - - // 分类导航 - c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId) +// c.RenderArgs["userInfo"] = userInfo + // 最新笔记 - c.getRecentBlogs(userId) + _, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc) + c.RenderArgs["recentPosts"] = c.fixBlogs(recentBlogs) + c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"] + // 语言, url地址 - c.SetLocale(); - c.RenderArgs["isMe"] = userId == c.GetUserId() - + c.SetLocale() + // 得到博客设置信息 if userBlog.UserId == "" { userBlog = blogService.GetUserBlog(userId) } - c.RenderArgs["userBlog"] = userBlog - + c.setBlog(userBlog, userInfo) +// c.RenderArgs["userBlog"] = userBlog + + // 分类导航 + c.getCates(userBlog) + + // 单页导航 + c.getSingles(userId) + c.setUrl(userBlog, userInfo) + + // 当前分类Id, 全设为"" + c.RenderArgs["curCateId"] = "" + c.RenderArgs["curSingleId"] = "" - return true + // 得到主题信息 + themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style) + LogJ(themeInfo) + c.RenderArgs["themeInfo"] = themeInfo + + return true, userBlog } -// 跨域判断是否是我的博客 -func (c Blog) IsMe(userId string) revel.Result { - var js = "" - if c.GetUserId() == userId { - js = "$('.is-me').removeClass('hide');" +// 修复博客, index, cate用到 +func (c Blog) fixBlog(blog info.BlogItem) map[string]interface{} { + blog2 := map[string]interface{}{ + "NoteId": blog.NoteId.Hex(), + "Title": blog.Title, + "CreatedTime": blog.CreatedTime, + "UpdatedTime": blog.UpdatedTime, + "PublicTime": blog.PublicTime, + "Desc": blog.Desc, + "Abstract": blog.Abstract, + "Content": blog.Content, + "Tags": blog.Tags, + "CommentNum": blog.CommentNum, + "ReadNum": blog.ReadNum, + "LikeNum": blog.LikeNum, + "IsMarkdown": blog.IsMarkdown, } - return c.RenderText(js); + return blog2 +} +func (c Blog) fixBlogs(blogs []info.BlogItem) []map[string]interface{} { + blogs2 := make([]map[string]interface{}, len(blogs)) + for i, blog := range blogs { + blogs2[i] = c.fixBlog(blog) + } + return blogs2 } -// 进入某个用户的博客 -var blogPageSize = 5 -var searchBlogPageSize = 30 - -// 分类 /cate/xxxxxxxx?notebookId=1212 -func (c Blog) Cate(notebookId string) revel.Result { - if notebookId == "" { - return c.E404() +// 404 +func (c Blog) E(userIdOrEmail, tag string) revel.Result { + ok, userBlog := c.domain() + var userId string + if ok { + userId = userBlog.UserId.Hex() } + var userInfo info.User + if userId != "" { + userInfo = userService.GetUserInfoByAny(userId) + } else { + // blog.leanote.com/userid/tag + userInfo = userService.GetUserInfoByAny(userIdOrEmail) + } + userId = userInfo.UserId.Hex() + _, userBlog = c.blogCommon(userId, userBlog, userInfo); + + return c.e404(userBlog.ThemePath) +} + +func (c Blog) Tags(userIdOrEmail string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() + userId := "" if hasDomain { userId = userBlog.UserId.Hex() } + + var userInfo info.User + if userId != "" { + userInfo = userService.GetUserInfoByAny(userId) + } else { + // blog.leanote.com/userid/tag + userInfo = userService.GetUserInfoByAny(userIdOrEmail) + } + userId = userInfo.UserId.Hex() + + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 + } + + c.RenderArgs["curIsTags"] = true + tags := blogService.ListBlogsTag(userId) + c.RenderArgs["tags"] = tags + return c.render("tags.html", userBlog.ThemePath) +} + +// 标签的文章页 +func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) { + // 自定义域名 + hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() - var notebook info.Notebook - notebook = notebookService.GetNotebookById(notebookId) - if !notebook.IsBlog { - return c.E404() + userId := "" + if hasDomain { + userId = userBlog.UserId.Hex() } - if userId != "" && userId != notebook.UserId.Hex() { - return c.E404() + + var userInfo info.User + if userId != "" { + userInfo = userService.GetUserInfoByAny(userId) + } else { + // blog.leanote.com/userid/tag + userInfo = userService.GetUserInfoByAny(userIdOrEmail) } - userId = notebook.UserId.Hex() - - if !c.blogCommon(userId, userBlog, info.User{}) { - return c.E404() + userId = userInfo.UserId.Hex() + + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 } - // 分页的话, 需要分页信息, totalPage, curPage + if hasDomain && tag == "" { + tag = userIdOrEmail + } + + c.RenderArgs["curIsTagPosts"] = true + c.RenderArgs["curTag"] = tag page := c.GetPage() - count, blogs := blogService.ListBlogs(userId, notebookId, page, blogPageSize, "PublicTime", false) - - c.RenderArgs["notebookId"] = notebookId - c.RenderArgs["notebook"] = notebook - c.RenderArgs["title"] = c.Message("blogClass") + " - " + notebook.Title - c.RenderArgs["blogs"] = blogs - c.RenderArgs["page"] = page - c.RenderArgs["pageSize"] = blogPageSize - c.RenderArgs["count"] = count - - return c.RenderTemplate("blog/index.html") + pageInfo, blogs := blogService.SearchBlogByTags([]string{tag}, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) + c.setPaging(pageInfo) + + c.RenderArgs["posts"] = c.fixBlogs(blogs) + tagPostsUrl := c.RenderArgs["tagPostsUrl"].(string) + c.RenderArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag + + return c.render("tag_posts.html", userBlog.ThemePath) } -// 显示分类的最近博客, json -func (c Blog) ListCateLatest(notebookId, callback string) revel.Result { - if notebookId == "" { - return c.E404() - } - // 自定义域名 - hasDomain, userBlog := c.domain() - userId := "" - if hasDomain { - userId = userBlog.UserId.Hex() - } - - var notebook info.Notebook - notebook = notebookService.GetNotebookById(notebookId) - if !notebook.IsBlog { - return c.E404() - } - if userId != "" && userId != notebook.UserId.Hex() { - return c.E404() - } - userId = notebook.UserId.Hex() - - if !c.blogCommon(userId, userBlog, info.User{}) { - return c.E404() - } - - // 分页的话, 需要分页信息, totalPage, curPage - page := 1 - _, blogs := blogService.ListBlogs(userId, notebookId, page, 5, "PublicTime", false) - re := info.NewRe() - re.Ok = true - re.List = blogs - return c.RenderJsonP(callback, re) -} - -func (c Blog) Index(userIdOrEmail string) revel.Result { +// 归档 +func (c Blog) Archive(userIdOrEmail string, cateId string) (re revel.Result) { + notebookId := cateId // 自定义域名 hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() userId := "" if hasDomain { userId = userBlog.UserId.Hex() @@ -205,7 +496,7 @@ func (c Blog) Index(userIdOrEmail string) revel.Result { // 用户id为空, 转至博客平台 if userIdOrEmail == "" { - userIdOrEmail = leanoteUserId; + userIdOrEmail = leanoteUserId } var userInfo info.User if userId != "" { @@ -215,158 +506,277 @@ func (c Blog) Index(userIdOrEmail string) revel.Result { } userId = userInfo.UserId.Hex() - if !c.blogCommon(userId, userBlog, userInfo) { - return c.E404() + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 } - - // 分页的话, 需要分页信息, totalPage, curPage - page := c.GetPage() - count, blogs := blogService.ListBlogs(userId, "", page, blogPageSize, "PublicTime", false) - - c.RenderArgs["blogs"] = blogs - c.RenderArgs["page"] = page - c.RenderArgs["pageSize"] = blogPageSize - c.RenderArgs["count"] = count - c.RenderArgs["index"] = true - c.RenderArgs["notebookId"] = "" - c.RenderArgs["title"] = userBlog.Title - - return c.RenderTemplate("blog/index.html") + + arcs := blogService.ListBlogsArchive(userId, notebookId, "PublicTime", false) + c.RenderArgs["archives"] = arcs + + c.RenderArgs["curIsArchive"] = true + if notebookId != "" { + notebook := notebookService.GetNotebookById(notebookId) + c.RenderArgs["curCateTitle"] = notebook.Title + c.RenderArgs["curCateId"] = notebookId + } + + return c.render("archive.html", userBlog.ThemePath) } -// 详情 -func (c Blog) View(noteId string) revel.Result { +// 进入某个用户的博客 +// TODO 可以配置, 排序和数目 +var blogPageSize = 5 +var searchBlogPageSize = 30 + +// 分类 /cate/xxxxxxxx?notebookId=1212 +func (c Blog) Cate(notebookId string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() + + if notebookId == "" { + return c.e404(userBlog.ThemePath); + } userId := "" if hasDomain { userId = userBlog.UserId.Hex() } - - blog := blogService.GetBlog(noteId) - userInfo := userService.GetUserInfo(blog.UserId.Hex()) - if userId != "" && userInfo.UserId.Hex() != userId { - return c.E404() + + var notebook info.Notebook + notebook = notebookService.GetNotebookById(notebookId) + if !notebook.IsBlog { + return c.e404("") + } + if userId != "" && userId != notebook.UserId.Hex() { + return c.e404("") + } + userId = notebook.UserId.Hex() + + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, info.User{}); !ok { + return c.e404(userBlog.ThemePath) + } + + // 分页的话, 需要分页信息, totalPage, curPage + page := c.GetPage() + pageInfo, blogs := blogService.ListBlogs(userId, notebookId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) + blogs2 := c.fixBlogs(blogs) + c.RenderArgs["posts"] = blogs2 + + c.setPaging(pageInfo) + + c.RenderArgs["curCateTitle"] = notebook.Title + c.RenderArgs["curCateId"] = notebookId + cateUrl := c.RenderArgs["cateUrl"].(string) + c.RenderArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId + c.RenderArgs["curIsCate"] = true + + return c.render("cate.html", userBlog.ThemePath) +} + +func (c Blog) Index(userIdOrEmail string) (re revel.Result) { + // 自定义域名 + hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() + userId := "" + if hasDomain { + userId = userBlog.UserId.Hex() + } + + // 用户id为空, 转至博客平台 + if userIdOrEmail == "" { + userIdOrEmail = leanoteUserId + } + var userInfo info.User + if userId != "" { + userInfo = userService.GetUserInfoByAny(userId) + } else { + userInfo = userService.GetUserInfoByAny(userIdOrEmail) } - c.RenderArgs["blog"] = blog - c.RenderArgs["userInfo"] = userInfo - c.RenderArgs["title"] = blog.Title + " - " + userInfo.Username - userId = userInfo.UserId.Hex() - c.blogCommon(userId, userBlog, info.User{}) + + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 + } + + // 分页的话, 需要分页信息, totalPage, curPage + page := c.GetPage() + pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) + blogs2 := c.fixBlogs(blogs) + c.RenderArgs["posts"] = blogs2 + + c.setPaging(pageInfo) + c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"] + + c.RenderArgs["curIsIndex"] = true + Log("----") + return c.render("index.html", userBlog.ThemePath) +} + +// 详情 +// 为了上一篇, 下一篇 +func (c Blog) fixNote(note info.Note) map[string]interface{} { + if note.NoteId == "" { + return nil + } + return map[string]interface{}{ + "NoteId": note.NoteId.Hex(), + "Title": note.Title, + "CreatedTime": note.CreatedTime, + "UpdatedTime": note.UpdatedTime, + "PublicTime": note.PublicTime, + "Desc": note.Desc, + "Tags": note.Tags, + "CommentNum": note.CommentNum, + "ReadNum": note.ReadNum, + "LikeNum": note.LikeNum, + "IsMarkdown": note.IsMarkdown, + } +} + +func (c Blog) Post(noteId string) (re revel.Result) { + // 自定义域名 + hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + Log(err) + re = c.e404(userBlog.ThemePath); + } + }() + userId := "" + if hasDomain { + userId = userBlog.UserId.Hex() + } + + blogInfo := blogService.GetBlog(noteId) + userInfo := userService.GetUserInfo(blogInfo.UserId.Hex()) + if userId != "" && userInfo.UserId.Hex() != userId { + panic("error") + } + + userId = userInfo.UserId.Hex() + _, userBlog = c.blogCommon(userId, userBlog, info.User{}) + + c.RenderArgs["post"] = c.fixBlog(blogInfo) + // c.RenderArgs["userInfo"] = userInfo + c.RenderArgs["curIsPost"] = true + // 得到访问者id + /* visitUserId := c.GetUserId() - if(visitUserId != "") { + if visitUserId != "" { visitUserInfo := userService.GetUserInfo(visitUserId) c.RenderArgs["visitUserInfoJson"] = c.Json(visitUserInfo) c.RenderArgs["visitUserInfo"] = visitUserInfo } else { - c.RenderArgs["visitUserInfoJson"] = "{}"; + c.RenderArgs["visitUserInfoJson"] = "{}" } + */ + + // 上一篇, 下一篇 + var baseTime interface{} + if userBlog.SortField == "PublicTime" { + baseTime = blogInfo.PublicTime + } else if userBlog.SortField == "CreatedTime" { + baseTime = blogInfo.CreatedTime + } else if userBlog.SortField == "UpdatedTime" { + baseTime = blogInfo.UpdatedTime + } else { + baseTime = blogInfo.Title + } + + preNote, nextNote := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, baseTime) + c.RenderArgs["prePost"] = c.fixNote(preNote) + c.RenderArgs["nextPost"] = c.fixNote(nextNote) + Log("---------") + return c.render("post.html", userBlog.ThemePath) +} + +func (c Blog) Single(singleId string) (re revel.Result) { + // 自定义域名 + hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() - return c.RenderTemplate("blog/view.html") + userId := "" + if hasDomain { + userId = userBlog.UserId.Hex() + } + + single := blogService.GetSingle(singleId) + userInfo := userService.GetUserInfo(single.UserId.Hex()) + if userId != "" && userInfo.UserId.Hex() != userId { + return c.e404(userBlog.ThemePath) + } + + userId = userInfo.UserId.Hex() + _, userBlog = c.blogCommon(userId, userBlog, info.User{}) + + c.RenderArgs["single"] = map[string]interface{}{ + "SingleId": single.SingleId.Hex(), + "Title": single.Title, + "Content": single.Content, + "CreatedTime": single.CreatedTime, + "UpdatedTime": single.UpdatedTime, + } + c.RenderArgs["curSingleId"] = singleId + c.RenderArgs["curIsSingle"] = true + + return c.render("single.html", userBlog.ThemePath) } // 搜索 -func (c Blog) Search(userIdOrEmail, key string) revel.Result { +func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() + defer func() { + if err := recover(); err != nil { + re = c.e404(userBlog.ThemePath); + } + }() userId := "" if hasDomain { userId = userBlog.UserId.Hex() } - - c.RenderArgs["title"] = c.Message("search") + " - " + key - c.RenderArgs["key"] = key - + var userInfo info.User if userId != "" { userInfo = userService.GetUserInfoByAny(userId) } else { userInfo = userService.GetUserInfoByAny(userIdOrEmail) } - c.RenderArgs["userInfo"] = userInfo +// c.RenderArgs["userInfo"] = userInfo userId = userInfo.UserId.Hex() - c.blogCommon(userId, userBlog, userInfo) - + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) + } + page := c.GetPage() - _, blogs := blogService.SearchBlog(key, userId, page, searchBlogPageSize, "PublicTime", false) - - c.RenderArgs["blogs"] = blogs - c.RenderArgs["key"] = key + pageInfo, blogs := blogService.SearchBlog(keywords, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) + c.setPaging(pageInfo) - return c.RenderTemplate("blog/search.html") -} + c.RenderArgs["posts"] = c.fixBlogs(blogs) + c.RenderArgs["keywords"] = keywords + searchUrl, _ := c.RenderArgs["searchUrl"].(string) + c.RenderArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords + c.RenderArgs["curIsSearch"] = true -// 博客设置 -func (c Blog) Set() revel.Result { - userId := c.GetUserId() - userInfo := userService.GetUserInfo(userId) - c.RenderArgs["userInfo"] = userInfo - - // 得到博客设置信息 - c.RenderArgs["title"] = c.Message("blogSet") - c.RenderArgs["isMe"] = true - c.RenderArgs["set"] = true - - c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain") - - userBlog := blogService.GetUserBlog(userId) - c.blogCommon(userId, userBlog, info.User{}) - - return c.RenderTemplate("blog/set.html") -} - -func (c Blog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result { - re := info.NewRe() - re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog) - return c.RenderJson(re) -} -func (c Blog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result { - re := info.NewRe() - re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog) - return c.RenderJson(re) -} -func (c Blog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result { - re := info.NewRe() - re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog) - return c.RenderJson(re) -} - -// userId可能是其它的 -func (c Blog) AboutMe(userIdOrEmail string) revel.Result { - // 自定义域名 - hasDomain, userBlog := c.domain() - userId := "" - if hasDomain { - userId = userBlog.UserId.Hex() - } - - var userInfo info.User - if userId != "" { - userInfo = userService.GetUserInfoByAny(userId) - } else { - userInfo = userService.GetUserInfoByAny(userIdOrEmail) - } - - if userInfo.UserId == "" { - return c.E404() - } - userId = userInfo.UserId.Hex() - - c.RenderArgs["userInfo"] = userInfo - c.RenderArgs["aboutMe"] = true - - c.RenderArgs["title"] = c.Message("aboutMe") - c.blogCommon(userId, userBlog, info.User{}) - - return c.RenderTemplate("blog/about_me.html") -} - -// 优化, 这里不要得到count -func (c Blog) getRecentBlogs(userId string) { - _, c.RenderArgs["recentBlogs"] = blogService.ListBlogs(userId, "", 1, 5, "PublicTime", false) + return c.render("search.html", userBlog.ThemePath) } // 可以不要, 因为注册的时候已经把username设为email了 @@ -377,128 +787,152 @@ func (c Blog) setRenderUserInfo(userInfo info.User) { c.RenderArgs["userInfo"] = userInfo } -//--------------------------- -// 后台 note<->blog - -// 设置/取消Blog; 置顶 -func (c Blog) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result { - noteUpdate := bson.M{} - if isTop { - isBlog = true - } - if !isBlog { - isTop = false - } - noteUpdate["IsBlog"] = isBlog - noteUpdate["IsTop"] = isTop - if isBlog { - noteUpdate["PublicTime"] = time.Now() - } - re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(), - noteId, noteUpdate) - return c.RenderJson(re) -} - -// 设置notebook <-> blog -func (c Blog) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result { - noteUpdate := bson.M{"IsBlog": isBlog} - re := notebookService.UpdateNotebook(c.GetUserId(), - notebookId, noteUpdate) - return c.RenderJson(re) -} - //---------------- // 社交, 点赞, 评论 -// 我是否点过赞? +// 得到博客统计信息 +func (c Blog) GetPostStat(noteId string) revel.Result { + re := info.NewRe() + re.Ok = true + statInfo := blogService.GetBlogStat(noteId) + re.Item = statInfo + return c.RenderJson(re); +} + +// jsonP +// 我是否点过赞? 得到我的信息 // 所有点赞的用户列表 // 各个评论中是否我也点过赞? -func (c Blog) GetLike(noteId string) revel.Result { +func (c Blog) GetLikes(noteId string, callback string) revel.Result { userId := c.GetUserId() - - // 我也点过? - isILikeIt := blogService.IsILikeIt(noteId, userId) + result := map[string]interface{}{} + isILikeIt := false + if userId != "" { + isILikeIt = blogService.IsILikeIt(noteId, userId) + result["visitUserInfo"] = userService.GetUserAndBlog(userId) + } // 点赞用户列表 likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false) - result := map[string]interface{}{} + re := info.NewRe() + re.Ok = true result["isILikeIt"] = isILikeIt result["likedUsers"] = likedUsers result["hasMoreLikedUser"] = hasMoreLikedUser - - return c.RenderJson(result) + + re.Item = result + return c.RenderJsonP(callback, re) } -func (c Blog) GetLikeAndComments(noteId string) revel.Result { +func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result { userId := c.GetUserId() - + result := map[string]interface{}{} + // 我也点过? - isILikeIt := blogService.IsILikeIt(noteId, userId) + isILikeIt := false + if userId != "" { + isILikeIt = blogService.IsILikeIt(noteId, userId) + result["visitUserInfo"] = userService.GetUserAndBlog(userId) + } + // 点赞用户列表 likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false) // 评论 page := c.GetPage() pageInfo, comments, commentUserInfo := blogService.ListComments(userId, noteId, page, 15) - - result := map[string]interface{}{} + + re := info.NewRe() + re.Ok = true result["isILikeIt"] = isILikeIt result["likedUsers"] = likedUsers result["hasMoreLikedUser"] = hasMoreLikedUser result["pageInfo"] = pageInfo result["comments"] = comments result["commentUserInfo"] = commentUserInfo - - return c.RenderJson(result) + re.Item = result + return c.RenderJsonP(callback, re) } func (c Blog) IncReadNum(noteId string) revel.Result { - blogService.IncReadNum(noteId) - return nil -} -// 点赞 -func (c Blog) LikeBlog(noteId string) revel.Result { - userId := c.GetUserId() re := info.NewRe() - re.Ok, re.Item = blogService.LikeBlog(noteId, userId) - + re.Ok = blogService.IncReadNum(noteId) return c.RenderJson(re) } -func (c Blog) ListLikes(noteId string) revel.Result { - return nil -} -func (c Blog) ListComments(noteId string) revel.Result { +// 点赞, 要用jsonp +func (c Blog) LikePost(noteId string, callback string) revel.Result { + re := info.NewRe() + userId := c.GetUserId() + re.Ok, re.Item = blogService.LikeBlog(noteId, userId) + return c.RenderJsonP(callback, re) +} +func (c Blog) GetComments(noteId string) revel.Result { // 评论 userId := c.GetUserId() page := c.GetPage() pageInfo, comments, commentUserInfo := blogService.ListComments(userId, noteId, page, 15) - + re := info.NewRe() + re.Ok = true result := map[string]interface{}{} result["pageInfo"] = pageInfo result["comments"] = comments result["commentUserInfo"] = commentUserInfo - - return c.RenderJson(result) + re.Item = result + + return c.RenderJson(re) } -func (c Blog) DeleteComment(noteId, commentId string) revel.Result { +// jsonp +func (c Blog) DeleteComment(noteId, commentId string, callback string) revel.Result { re := info.NewRe() re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId()) - return c.RenderJson(re) + return c.RenderJsonP(callback, re) } -func (c Blog) Comment(noteId, content, toCommentId string) revel.Result { +// jsonp +func (c Blog) CommentPost(noteId, content, toCommentId string, callback string) revel.Result { re := info.NewRe() - re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content); - return c.RenderJson(re) + re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content) + return c.RenderJsonP(callback, re) } -func (c Blog) LikeComment(commentId string) revel.Result { +// jsonp +func (c Blog) LikeComment(commentId string, callback string) revel.Result { re := info.NewRe() ok, isILikeIt, num := blogService.LikeComment(commentId, c.GetUserId()) re.Ok = ok re.Item = bson.M{"IsILikeIt": isILikeIt, "Num": num} - return c.RenderJson(re) + return c.RenderJsonP(callback, re) } -func (c Blog) Report(noteId, commentId, reason string) revel.Result { +// 显示分类的最近博客, jsonp +func (c Blog) ListCateLatest(notebookId, callback string) revel.Result { + if notebookId == "" { + return c.e404("") + } + // 自定义域名 + hasDomain, userBlog := c.domain() + userId := "" + if hasDomain { + userId = userBlog.UserId.Hex() + } + + var notebook info.Notebook + notebook = notebookService.GetNotebookById(notebookId) + if !notebook.IsBlog { + return c.e404(userBlog.ThemePath) + } + if userId != "" && userId != notebook.UserId.Hex() { + return c.e404(userBlog.ThemePath) + } + userId = notebook.UserId.Hex() + + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, info.User{}); !ok { + return c.e404(userBlog.ThemePath) + } + + // 分页的话, 需要分页信息, totalPage, curPage + page := 1 + _, blogs := blogService.ListBlogs(userId, notebookId, page, 5, userBlog.SortField, userBlog.IsAsc) re := info.NewRe() - re.Ok = blogService.Report(noteId, commentId, reason, c.GetUserId()); - return c.RenderJson(re) -} \ No newline at end of file + re.Ok = true + re.List = blogs + return c.RenderJsonP(callback, re) +} diff --git a/app/controllers/PreviewController.go b/app/controllers/PreviewController.go new file mode 100644 index 0000000..e3eda7f --- /dev/null +++ b/app/controllers/PreviewController.go @@ -0,0 +1,101 @@ +package controllers + +import ( + "github.com/revel/revel" +// "strings" +// "time" + // "encoding/json" +// "github.com/leanote/leanote/app/info" +// . "github.com/leanote/leanote/app/lea" +// "github.com/leanote/leanote/app/lea/blog" +// "gopkg.in/mgo.v2/bson" + // "github.com/leanote/leanote/app/types" + // "io/ioutil" + // "math" + // "os" + // "path" +) + +type Preview struct { + Blog +} + +// 得到要预览的主题绝对路径 +func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool { + if themeId != "" { + c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了 + } else { + themeId = c.Session["themeId"] // 直接从session中获取 + } + if themeId == "" { + return false + } + theme := themeService.GetTheme(c.GetUserId(), themeId) + + c.RenderArgs["isPreview"] = true + c.RenderArgs["themePath"] = theme.Path + if theme.Path == "" { + return false + } + return true +} + +func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result { + if !c.getPreviewThemeAbsolutePath(themeId) { + return c.E404() + } + return c.Blog.Index(c.GetUserId()) +// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId)) +} + +func (c Preview) Tag(userIdOrEmail, tag string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Tag(c.GetUserId(), tag) +} +func (c Preview) Tags(userIdOrEmail string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Tags(c.GetUserId()) +// if tag == "" { +// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +// } +// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +} +func (c Preview) Archive(userIdOrEmail string, notebookId string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Archive(c.GetUserId(), notebookId) +// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +} +func (c Preview) Cate(notebookId string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Cate(notebookId) +// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +} +func (c Preview) Post(noteId string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Post(noteId) +// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +} +func (c Preview) Single(singleId string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Single(singleId) +// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +} +func (c Preview) Search(userIdOrEmail, keywords string) revel.Result { + if !c.getPreviewThemeAbsolutePath("") { + return c.E404() + } + return c.Blog.Search(c.GetUserId(), keywords) +// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) +} \ No newline at end of file diff --git a/app/controllers/admin/AdminController.go b/app/controllers/admin/AdminController.go index 5bdc5e8..dad63d1 100644 --- a/app/controllers/admin/AdminController.go +++ b/app/controllers/admin/AdminController.go @@ -18,8 +18,8 @@ func (c Admin) Index() revel.Result { c.SetLocale() c.RenderArgs["countUser"] = userService.CountUser() - c.RenderArgs["countNote"] = noteService.CountNote() - c.RenderArgs["countBlog"] = noteService.CountBlog() + c.RenderArgs["countNote"] = noteService.CountNote("") + c.RenderArgs["countBlog"] = noteService.CountBlog("") return c.RenderTemplate("admin/index.html"); } diff --git a/app/controllers/admin/AdminUserController.go b/app/controllers/admin/AdminUserController.go index 1ab80a0..6f70079 100644 --- a/app/controllers/admin/AdminUserController.go +++ b/app/controllers/admin/AdminUserController.go @@ -2,7 +2,9 @@ package admin import ( "github.com/revel/revel" -// . "github.com/leanote/leanote/app/lea" + . "github.com/leanote/leanote/app/lea" + "time" + "github.com/leanote/leanote/app/info" ) // admin 首页 @@ -13,10 +15,13 @@ type AdminUser struct { // admin 主页 var userPageSize = 10 -func (c AdminUser) Index(sorter, keywords string) revel.Result { +func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result { pageNumber := c.GetPage() - sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"}); - pageInfo, users := userService.ListUsers(pageNumber, userPageSize, sorterField, isAsc, keywords); + if userPageSize == 0 { + pageSize = userPageSize + } + sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"}); + pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords); c.RenderArgs["pageInfo"] = pageInfo c.RenderArgs["users"] = users c.RenderArgs["keywords"] = keywords @@ -26,3 +31,35 @@ func (c AdminUser) Index(sorter, keywords string) revel.Result { func (c AdminUser) Add() revel.Result { return c.RenderTemplate("admin/user/add.html"); } + +// 添加 +func (c AdminUser) Register(email, pwd string) revel.Result { + re := info.NewRe(); + + if re.Ok, re.Msg = Vd("email", email); !re.Ok { + return c.RenderRe(re); + } + if re.Ok, re.Msg = Vd("password", pwd); !re.Ok { + return c.RenderRe(re); + } + + // 注册 + re.Ok, re.Msg = authService.Register(email, pwd) + + return c.RenderRe(re) +} + +// 修改帐户 +func (c AdminUser) UpdateAccount(userId string) revel.Result { + userInfo := userService.GetUserInfo(userId) + c.RenderArgs["userInfo"] = userInfo + return c.RenderTemplate("admin/user/update_account.html"); +} + +func (c AdminUser) DoUpdateAccount(userId, accountType string, accountStartTime, accountEndTime string, maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) revel.Result { + re := info.NewRe(); + s, _ := time.Parse("2006-01-02 15:04:02", accountStartTime) + e, _ := time.Parse("2006-01-02 15:04:02", accountEndTime) + re.Ok = userService.UpdateAccount(userId, accountType, s, e, maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize ) + return c.RenderRe(re) +} \ No newline at end of file diff --git a/app/controllers/init.go b/app/controllers/init.go index 19f00a2..186323e 100644 --- a/app/controllers/init.go +++ b/app/controllers/init.go @@ -3,6 +3,7 @@ package controllers import ( "github.com/leanote/leanote/app/service" "github.com/leanote/leanote/app/info" + "github.com/leanote/leanote/app/lea/blog" // . "github.com/leanote/leanote/app/lea" "github.com/revel/revel" "strings" @@ -27,6 +28,7 @@ var attachService *service.AttachService var configService *service.ConfigService var emailService *service.EmailService var sessionService *service.SessionService +var themeService *service.ThemeService var pageSize = 1000 var defaultSortField = "UpdatedTime" @@ -126,6 +128,7 @@ func InitService() { configService = service.ConfigS emailService = service.EmailS sessionService = service.SessionS + themeService = service.ThemeS } func init() { @@ -137,10 +140,12 @@ func init() { revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{}) - revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{}) revel.OnAppStart(func() { siteUrl, _ = revel.Config.String("site.url") + + // 博客初始化模板 + blog.Init() }) } \ No newline at end of file diff --git a/app/controllers/member/MemberBaseController.go b/app/controllers/member/MemberBaseController.go new file mode 100644 index 0000000..2fac5f4 --- /dev/null +++ b/app/controllers/member/MemberBaseController.go @@ -0,0 +1,59 @@ +package member + +import ( +// "github.com/revel/revel" +// "gopkg.in/mgo.v2/bson" +// "encoding/json" + . "github.com/leanote/leanote/app/lea" + "github.com/leanote/leanote/app/controllers" +// "io/ioutil" +// "fmt" +// "math" +// "strconv" + "strings" +) + +// 公用Controller, 其它Controller继承它 +type MemberBaseController struct { + controllers.BaseController // 不能用*BaseController +} + +// 得到sorterField 和 isAsc +// okSorter = ['email', 'username'] +func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){ + sorter := "" + c.Params.Bind(&sorter, "sorter") + if sorter == "" { + return sorterField, isAsc; + } + + // sorter形式 email-up, email-down + s2 := strings.Split(sorter, "-") + if len(s2) != 2 { + return sorterField, isAsc; + } + + // 必须是可用的sorter + if okSorter != nil && len(okSorter) > 0 { + if !InArray(okSorter, s2[0]) { + return sorterField, isAsc; + } + } + + sorterField = strings.Title(s2[0]) + if s2[1] == "up" { + isAsc = true + } else { + isAsc = false + } + c.RenderArgs["sorter"] = sorter + return sorterField, isAsc; +} + +func (c MemberBaseController) updateConfig(keys []string) { + userId := c.GetUserId() + for _, key := range keys { + v := c.Params.Values.Get(key) + configService.UpdateGlobalStringConfig(userId, key, v) + } +} \ No newline at end of file diff --git a/app/controllers/member/MemberBlogController.go b/app/controllers/member/MemberBlogController.go new file mode 100644 index 0000000..9dca66c --- /dev/null +++ b/app/controllers/member/MemberBlogController.go @@ -0,0 +1,428 @@ +package member + +import ( + "github.com/revel/revel" + . "github.com/leanote/leanote/app/lea" + "github.com/leanote/leanote/app/info" + "os" + "io/ioutil" + "time" + "fmt" +// "github.com/leanote/leanote/app/lea/blog" +) + +// admin 首页 + +type MemberBlog struct { + MemberBaseController +} + +func (c MemberBlog) common() info.UserBlog { + userId := c.GetUserId() + userInfo := userService.GetUserInfo(userId) + c.RenderArgs["userInfo"] = userInfo + + // 得到博客设置信息 + c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain") + + userBlog := blogService.GetUserBlog(userId) + c.RenderArgs["userBlog"] = userBlog + + c.SetUserInfo() + c.SetLocale() + return userBlog +} + +// 基本信息设置 +func (c MemberBlog) Base() revel.Result { + c.common() + c.RenderArgs["title"] = "Blog Base Info" + return c.RenderTemplate("member/blog/base.html"); +} +func (c MemberBlog) Comment() revel.Result { + c.common() + c.RenderArgs["title"] = "Comment" + return c.RenderTemplate("member/blog/comment.html"); +} +func (c MemberBlog) Domain() revel.Result { + c.common() + c.RenderArgs["title"] = "Domain" + return c.RenderTemplate("member/blog/domain.html"); +} + +func (c MemberBlog) Paging() revel.Result { + c.common() + c.RenderArgs["title"] = "Paging" + return c.RenderTemplate("member/blog/paging.html"); +} + +func (c MemberBlog) Cate() revel.Result { + userBlog := c.common() + c.RenderArgs["title"] = "Cate" + + notebooks := blogService.ListBlogNotebooks(c.GetUserId()) + notebooksMap := map[string]info.Notebook{} + for _, each := range notebooks { + notebooksMap[each.NotebookId.Hex()] = each + } + + var i = 0; + notebooks2 := make([]info.Notebook, len(notebooks)) + + // 先要保证已有的是正确的排序 + cateIds := userBlog.CateIds + has := map[string]bool{} // cateIds中有的 + if cateIds != nil && len(cateIds) > 0 { + for _, cateId := range cateIds { + if n, ok := notebooksMap[cateId]; ok { + notebooks2[i] = n + i++ + has[cateId] = true + } + } + } + // 之后 + for _, each := range notebooks { + id := each.NotebookId.Hex() + if !has[id] { + notebooks2[i] = each + i++ + } + } + c.RenderArgs["notebooks"] = notebooks2 + + return c.RenderTemplate("member/blog/cate.html"); +} + +// 修改分类排序 +func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result { + re := info.NewRe() + re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds) + return c.RenderJson(re) +} + +// 保存之, 包含增加与保存 +func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result { + re := info.NewRe() + re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content) + return c.RenderJson(re) +} +func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result { + c.common() + c.RenderArgs["title"] = "Add Single" + c.RenderArgs["singleId"] = singleId + if singleId != "" { + c.RenderArgs["single"] = blogService.GetSingle(singleId) + } + return c.RenderTemplate("member/blog/add_single.html"); +} +func (c MemberBlog) SortSingles(singleIds []string) revel.Result { + re := info.NewRe() + re.Ok = blogService.SortSingles(c.GetUserId(), singleIds) + return c.RenderJson(re) +} + +func (c MemberBlog) DeleteSingle(singleId string) revel.Result { + re := info.NewRe() + re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId) + return c.RenderJson(re) +} +func (c MemberBlog) Single() revel.Result { + c.common() + c.RenderArgs["title"] = "Cate" + c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId()) + + return c.RenderTemplate("member/blog/single.html"); +} + +// 主题 +func (c MemberBlog) Theme() revel.Result { + c.common() + activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId()) + c.RenderArgs["activeTheme"] = activeTheme + c.RenderArgs["otherThemes"] = otherThemes + + c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes() + + c.RenderArgs["title"] = "Theme" + return c.RenderTemplate("member/blog/theme.html"); +} + +// 编辑主题 +var baseTpls = []string{"header.html", "footer.html", "index.html", "cate.html", "search.html", "post.html", "single.html", "tags.html", "tag_posts.html", "archive.html", "share_comment.html", "404.html", "theme.json", "style.css", "blog.js"} +func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result { + // 查看用户是否有该theme, 若没有则复制default之 + // 得到主题的文件列表 + userBlog := blogService.GetUserBlog(c.GetUserId()) + if themeId == "" { + _, themeId = themeService.NewThemeForFirst(userBlog) + return c.Redirect("/member/blog/updateTheme?themeId=" + themeId) + } + + c.common() + c.RenderArgs["title"] = "Upate Theme" + c.RenderArgs["isNew"] = isNew + + // 先复制之 + c.RenderArgs["themeId"] = themeId + + // 得到脚本目录 + userId := c.GetUserId() + + theme := themeService.GetTheme(userId, themeId) + c.RenderArgs["theme"] = theme + + path := revel.BasePath + "/" + theme.Path + + tpls := ListDir(path) + myTpls := make([]string, len(baseTpls)) + tplMap := map[string]bool{} + for i, t := range baseTpls { + myTpls[i] = t + tplMap[t] = true + } + // 得到没有的tpls + for _, t := range tpls { + if t == "images" { + continue; + } + if !tplMap[t] { + myTpls = append(myTpls, t) + } + } + + c.RenderArgs["myTpls"] = myTpls + + return c.RenderTemplate("member/blog/update_theme.html"); +} + +// 得到文件内容 +func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result { + re := info.NewRe() + re.Ok = true + re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename) + + return c.RenderJson(re) +} +func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result { + re := info.NewRe() + re.Ok, re.Msg = themeService.UpdateTplContent(c.GetUserId(), themeId, filename, content) + return c.RenderJson(re) +} + +func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result { + re := info.NewRe() + re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename) + return c.RenderJson(re) +} + +func (c MemberBlog) ListThemeImages(themeId string) revel.Result { + re := info.NewRe() + userId := c.GetUserId() + path := themeService.GetThemeAbsolutePath(userId, themeId) + "/images" + os.MkdirAll(path, 0755) + images := ListDir(path) + re.List = images + re.Ok = true + return c.RenderJson(re) +} + +func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result { + re := info.NewRe() + path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename + re.Ok = DeleteFile(path) + return c.RenderJson(re) +} + +// 上传主题图片 +func (c MemberBlog) UploadThemeImage(themeId string) revel.Result { + re := c.uploadImage(themeId); + c.RenderArgs["fileUrlPath"] = re.Id + c.RenderArgs["resultCode"] = re.Code + c.RenderArgs["resultMsg"] = re.Msg + return c.RenderTemplate("file/blog_logo.html") +} +func (c MemberBlog) uploadImage(themeId string) (re info.Re) { + var fileId = "" + var resultCode = 0 // 1表示正常 + var resultMsg = "内部错误" // 错误信息 + var Ok = false + + defer func() { + re.Id = fileId // 只是id, 没有其它信息 + re.Code = resultCode + re.Msg = resultMsg + re.Ok = Ok + }() + + file, handel, err := c.Request.FormFile("file") + if err != nil { + return re + } + defer file.Close() + // 生成上传路径 + dir := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images" + err = os.MkdirAll(dir, 0755) + if err != nil { + return re + } + // 生成新的文件名 + filename := handel.Filename + + var ext string; + + _, ext = SplitFilename(filename) + if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") { + resultMsg = "不是图片" + return re + } + + filename = filename + data, err := ioutil.ReadAll(file) + if err != nil { + LogJ(err) + return re + } + + // > 2M? + if(len(data) > 5 * 1024 * 1024) { + resultCode = 0 + resultMsg = "图片大于2M" + return re + } + + toPath := dir + "/" + filename; + err = ioutil.WriteFile(toPath, data, 0777) + if err != nil { + LogJ(err) + return re + } + TransToGif(toPath, 0, true) + resultCode = 1 + resultMsg = "上传成功!" + + return re +} + +// +// 使用主题 +func (c MemberBlog) ActiveTheme(themeId string) revel.Result { + re := info.NewRe() + re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId) + return c.RenderJson(re) +} +// 删除主题 +func (c MemberBlog) DeleteTheme(themeId string) revel.Result { + re := info.NewRe() + re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId) + return c.RenderJson(re) +} +// 管理员公开主题 +func (c MemberBlog) PublicTheme(themeId string) revel.Result { + re := info.NewRe() + re.Ok = themeService.PublicTheme(c.GetUserId(), themeId) + return c.RenderJson(re) +} +// 导出 +func (c MemberBlog) ExportTheme(themeId string) revel.Result { + re := info.NewRe() + var path string + re.Ok, path = themeService.ExportTheme(c.GetUserId(), themeId) + if !re.Ok { + return c.RenderText("error...") + } + fw, err := os.Open(path) + if err != nil { + return c.RenderText("error") + } + return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment +} + +// 导入主题 +func (c MemberBlog) ImportTheme() revel.Result { + re := info.NewRe() + + file, handel, err := c.Request.FormFile("file") + if err != nil { + re.Msg = fmt.Sprintf("%v", err) + return c.RenderJson(re) + + } + defer file.Close() + // 生成上传路径 + userId := c.GetUserId() + dir := revel.BasePath + "/public/upload/" + userId + "/tmp" + err = os.MkdirAll(dir, 0755) + if err != nil { + re.Msg = fmt.Sprintf("%v", err) + return c.RenderJson(re) + } + // 生成新的文件名 + filename := handel.Filename + + var ext string; + _, ext = SplitFilename(filename) + if(ext != ".zip") { + re.Msg = "请上传zip文件" + return c.RenderJson(re) + } + + filename = filename + data, err := ioutil.ReadAll(file) + if err != nil { + return c.RenderJson(re) + } + + // > 10M? + if(len(data) > 10 * 1024 * 1024) { + re.Msg = "文件大于10M" + return c.RenderJson(re) + } + + toPath := dir + "/" + filename; + err = ioutil.WriteFile(toPath, data, 0777) + if err != nil { + re.Msg = fmt.Sprintf("%v", err) + return c.RenderJson(re) + } + + // 上传好后, 增加之 + themeService.ImportTheme(c.GetUserId(), toPath) + + re.Ok = true + return c.RenderJson(re) +} + +// 安装 +func (c MemberBlog) InstallTheme(themeId string) revel.Result { + re := info.NewRe() + re.Ok = themeService.InstallTheme(c.GetUserId(), themeId) + return c.RenderJson(re) +} +// 新建主题 +func (c MemberBlog) NewTheme() revel.Result { + _, themeId := themeService.NewTheme(c.GetUserId()) + return c.Redirect("/member/blog/updateTheme?isNew=1&themeId=" + themeId) +} +//----------- +// +func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result { + re := info.NewRe() + re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog) + return c.RenderJson(re) +} +func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result { + re := info.NewRe() + re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog) + return c.RenderJson(re) +} +func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result { + re := info.NewRe() + re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog) + return c.RenderJson(re) +} +func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result { + re := info.NewRe() + re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc) + return c.RenderRe(re) +} \ No newline at end of file diff --git a/app/controllers/member/MemberIndexController.go b/app/controllers/member/MemberIndexController.go new file mode 100644 index 0000000..6393450 --- /dev/null +++ b/app/controllers/member/MemberIndexController.go @@ -0,0 +1,37 @@ +package member + +import ( + "github.com/revel/revel" +) + +// admin 首页 + +type MemberIndex struct { + MemberBaseController +} + +// admin 主页 +func (c MemberIndex) Index() revel.Result { + c.SetUserInfo() + c.RenderArgs["title"] = "Leanote Member Center" + + c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId()) + c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId()) + + c.SetLocale() + + return c.RenderTemplate("member/index.html"); +} + +// 模板 +func (c MemberIndex) T(t string) revel.Result { + c.RenderArgs["str"] = configService.GlobalStringConfigs + c.RenderArgs["arr"] = configService.GlobalArrayConfigs + c.RenderArgs["map"] = configService.GlobalMapConfigs + c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs + return c.RenderTemplate("admin/" + t + ".html") +} + +func (c MemberIndex) GetView(view string) revel.Result { + return c.RenderTemplate("admin/" + view); +} \ No newline at end of file diff --git a/app/controllers/member/MemberUserController.go b/app/controllers/member/MemberUserController.go new file mode 100644 index 0000000..a413470 --- /dev/null +++ b/app/controllers/member/MemberUserController.go @@ -0,0 +1,45 @@ +package member + +import ( + "github.com/revel/revel" +) + +// 帐户信息 + +type MemberUser struct { + MemberBaseController +} + +func (c MemberUser) Username() revel.Result { + c.SetUserInfo() + c.SetLocale() + c.RenderArgs["title"] = "Username" + return c.RenderTemplate("member/user/username.html"); +} + +func (c MemberUser) Email() revel.Result { + c.SetUserInfo() + c.SetLocale() + c.RenderArgs["title"] = "Email" + return c.RenderTemplate("member/user/email.html"); +} + +func (c MemberUser) Password() revel.Result { + c.SetUserInfo() + c.SetLocale() + c.RenderArgs["title"] = "Password" + return c.RenderTemplate("member/user/password.html"); +} + +func (c MemberUser) Avatar() revel.Result { + c.SetUserInfo() + c.SetLocale() + c.RenderArgs["title"] = "Avatar" + return c.RenderTemplate("member/user/avatar.html"); +} +func (c MemberUser) AddAccount() revel.Result { + c.SetUserInfo() + c.SetLocale() + c.RenderArgs["title"] = "Add Account" + return c.RenderTemplate("member/user/add_account.html"); +} \ No newline at end of file diff --git a/app/controllers/member/init.go b/app/controllers/member/init.go new file mode 100644 index 0000000..a86b6f1 --- /dev/null +++ b/app/controllers/member/init.go @@ -0,0 +1,133 @@ +package member + +import ( + "github.com/leanote/leanote/app/service" + "github.com/leanote/leanote/app/info" +// . "github.com/leanote/leanote/app/lea" + "github.com/revel/revel" +// "strings" +) + +var userService *service.UserService +var noteService *service.NoteService +var trashService *service.TrashService +var notebookService *service.NotebookService +var noteContentHistoryService *service.NoteContentHistoryService +var authService *service.AuthService +var shareService *service.ShareService +var blogService *service.BlogService +var tagService *service.TagService +var pwdService *service.PwdService +var tokenService *service.TokenService +var suggestionService *service.SuggestionService +var albumService *service.AlbumService +var noteImageService *service.NoteImageService +var fileService *service.FileService +var attachService *service.AttachService +var configService *service.ConfigService +var emailService *service.EmailService +var upgradeService *service.UpgradeService +var themeService *service.ThemeService + +var adminUsername = "admin" +// 拦截器 +// 不需要拦截的url +// Index 除了Note之外都不需要 +var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true, + "Login": true, + "DoLogin": true, + "Logout": true, + "Register": true, + "DoRegister": true, + "FindPasswword": true, + "DoFindPassword": true, + "FindPassword2": true, + "FindPasswordUpdate": true, + "Suggestion": true, + }, + "Blog": map[string]bool{"Index": true, + "View": true, + "AboutMe": true, + "SearchBlog": true, + }, + // 用户的激活与修改邮箱都不需要登录, 通过链接地址 + "User": map[string]bool{"UpdateEmail": true, + "ActiveEmail":true, + }, + "Oauth": map[string]bool{"GithubCallback": true}, + "File": map[string]bool{"OutputImage": true, "OutputFile": true}, + "Attach": map[string]bool{"Download": true, "DownloadAll": true}, +} +func needValidate(controller, method string) bool { + // 在里面 + if v, ok := commonUrl[controller]; ok { + // 在commonUrl里 + if _, ok2 := v[method]; ok2 { + return false + } + return true + } else { + // controller不在这里的, 肯定要验证 + return true; + } +} +func AuthInterceptor(c *revel.Controller) revel.Result { + // 全部变成首字大写 + /* + var controller = strings.Title(c.Name) + var method = strings.Title(c.MethodName) + // 是否需要验证? + if !needValidate(controller, method) { + return nil + } + */ + + // 验证是否已登录 + // 必须是管理员 + if _, ok := c.Session["Username"]; ok { + return nil // 已登录 + } + + // 没有登录, 判断是否是ajax操作 + if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" { + re := info.NewRe() + re.Msg = "NOTLOGIN" + return c.RenderJson(re) + } + + return c.Redirect("/login") +} + +// 最外层init.go调用 +// 获取service, 单例 +func InitService() { + notebookService = service.NotebookS + noteService = service.NoteS + noteContentHistoryService = service.NoteContentHistoryS + trashService = service.TrashS + shareService = service.ShareS + userService = service.UserS + tagService = service.TagS + blogService = service.BlogS + tokenService = service.TokenS + noteImageService = service.NoteImageS + fileService = service.FileS + albumService= service.AlbumS + attachService = service.AttachS + pwdService = service.PwdS + suggestionService = service.SuggestionS + authService = service.AuthS + configService = service.ConfigS + emailService = service.EmailS + upgradeService = service.UpgradeS + themeService = service.ThemeS +} + +func init() { + revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberIndex{}) + revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{}) + revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{}) + revel.OnAppStart(func() { + adminUsername, _ = revel.Config.String("adminUsername") + }) +} \ No newline at end of file diff --git a/app/controllers/member/个人中心.md b/app/controllers/member/个人中心.md new file mode 100644 index 0000000..ab0218f --- /dev/null +++ b/app/controllers/member/个人中心.md @@ -0,0 +1,2 @@ +包括基本信息设置 +博客设置 diff --git a/app/db/Mgo.go b/app/db/Mgo.go index 55c2326..40beb0d 100644 --- a/app/db/Mgo.go +++ b/app/db/Mgo.go @@ -2,9 +2,9 @@ package db import ( "fmt" + "github.com/revel/revel" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" - "github.com/revel/revel" ) // Init mgo and the common DAO @@ -23,6 +23,8 @@ var ShareNotebooks *mgo.Collection var HasShareNotes *mgo.Collection var Blogs *mgo.Collection var Users *mgo.Collection +var Groups *mgo.Collection +var GroupUsers *mgo.Collection var Tags *mgo.Collection var TagNotes *mgo.Collection @@ -46,6 +48,8 @@ var EmailLogs *mgo.Collection var BlogLikes *mgo.Collection var BlogComments *mgo.Collection var Reports *mgo.Collection +var BlogSingles *mgo.Collection +var Themes *mgo.Collection // session var Sessions *mgo.Collection @@ -54,7 +58,7 @@ var Sessions *mgo.Collection func Init() { var url string var ok bool - config := revel.Config; + config := revel.Config url, ok = config.String("db.url") dbname, _ := config.String("db.dbname") if !ok { @@ -66,9 +70,9 @@ func Init() { if username == "" || password == "" { usernameAndPassword = "" } - url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname + url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname } - + // [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options] // mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb var err error @@ -82,55 +86,60 @@ func Init() { // notebook Notebooks = Session.DB(dbname).C("notebooks") - + // notes Notes = Session.DB(dbname).C("notes") - + // noteContents NoteContents = Session.DB(dbname).C("note_contents") NoteContentHistories = Session.DB(dbname).C("note_content_histories") - + // share ShareNotes = Session.DB(dbname).C("share_notes") ShareNotebooks = Session.DB(dbname).C("share_notebooks") HasShareNotes = Session.DB(dbname).C("has_share_notes") - + // user Users = Session.DB(dbname).C("users") - + // group + Groups = Session.DB(dbname).C("groups") + GroupUsers = Session.DB(dbname).C("group_users") + // blog Blogs = Session.DB(dbname).C("blogs") - + // tag Tags = Session.DB(dbname).C("tags") TagNotes = Session.DB(dbname).C("tag_notes") - + // blog UserBlogs = Session.DB(dbname).C("user_blogs") - + BlogSingles = Session.DB(dbname).C("blog_singles") + Themes = Session.DB(dbname).C("themes") + // find password Tokens = Session.DB(dbname).C("tokens") - + // Suggestion Suggestions = Session.DB(dbname).C("suggestions") - + // Album & file Albums = Session.DB(dbname).C("albums") Files = Session.DB(dbname).C("files") Attachs = Session.DB(dbname).C("attachs") - + NoteImages = Session.DB(dbname).C("note_images") - + Configs = Session.DB(dbname).C("configs") EmailLogs = Session.DB(dbname).C("email_logs") - + // 社交 BlogLikes = Session.DB(dbname).C("blog_likes") BlogComments = Session.DB(dbname).C("blog_comments") - + // 举报 Reports = Session.DB(dbname).C("reports") - + // session Sessions = Session.DB(dbname).C("sessions") } @@ -174,22 +183,29 @@ func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, return Err(err) } func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool { - return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field:value}}) + return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field: value}}) } func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool { return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v}) } + func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool { - return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}}) + return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field: value}}) } func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool { return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v}) } -// + +// func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool { _, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}}) return Err(err) } +func UpdateByQI(collection *mgo.Collection, q interface{}, v interface{}) bool { + _, err := collection.UpdateAll(q, bson.M{"$set": v}) + return Err(err) +} + // 查询条件和值 func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool { _, err := collection.UpdateAll(q, bson.M{"$set": v}) @@ -255,6 +271,7 @@ func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i i } collection.Find(q).Select(selector).One(i) } + // 查询某些字段, q是查询条件, fields是字段名列表 func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) { selector := make(bson.M, len(fields)) @@ -270,6 +287,11 @@ func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i i collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i) } +// 按field去重 +func Distinct(collection *mgo.Collection, q bson.M, field string, i interface{}) { + collection.Find(q).Distinct(field, i) +} + //---------------------- func Count(collection *mgo.Collection, q interface{}) int { @@ -303,9 +325,9 @@ func Err(err error) bool { fmt.Println(err) // 删除时, 查找 if err.Error() == "not found" { - return true; + return true } return false } return true -} \ No newline at end of file +} diff --git a/app/info/BlogCustom.go b/app/info/BlogCustom.go new file mode 100644 index 0000000..4e6cab5 --- /dev/null +++ b/app/info/BlogCustom.go @@ -0,0 +1,45 @@ +package info + +import ( +// "time" +) + +// 仅仅为了博客的主题 + +type BlogInfoCustom struct { + UserId string + Username string + UserLogo string + Title string + SubTitle string + Logo string + OpenComment bool + CommentType string + ThemeId string + SubDomain string + Domain string +} + +type Post struct { + NoteId string +} +// 归档 +type Archive struct { + Year int + Posts []map[string]interface{} +} + +type TagsCounts []TagCount +type TagCount struct { + Tag string + Count int +} +func (this TagsCounts) Len() int { + return len(this) +} +func (this TagsCounts) Less(i, j int) bool { + return this[i].Count > this[j].Count +} +func (this TagsCounts) Swap(i, j int) { + this[i], this[j] = this[j], this[i] +} \ No newline at end of file diff --git a/app/info/BlogInfo.go b/app/info/BlogInfo.go index 976c24f..68eaef3 100644 --- a/app/info/BlogInfo.go +++ b/app/info/BlogInfo.go @@ -9,6 +9,7 @@ import ( type BlogItem struct { Note + Abstract string Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了 HasMore bool // 是否是否还有 User User // 用户信息 @@ -18,13 +19,13 @@ type UserBlogBase struct { Logo string `Logo` Title string `Title` // 标题 SubTitle string `SubTitle` // 副标题 - AboutMe string `AboutMe` // 关于我 +// AboutMe string `AboutMe` // 关于我 } type UserBlogComment struct { - CanComment bool `CanComment` // 是否可以评论 + CanComment bool `CanComment` // 是否可以评论 CommentType string `CommentType` // default 或 disqus - DisqusId string `DisqusId` + DisqusId string `DisqusId` } type UserBlogStyle struct { @@ -38,18 +39,47 @@ type UserBlog struct { Logo string `Logo` Title string `Title` // 标题 SubTitle string `SubTitle` // 副标题 - AboutMe string `AboutMe` // 关于我 + AboutMe string `AboutMe` // 关于我, 弃用 + + CanComment bool `CanComment` // 是否可以评论 - CanComment bool `CanComment` // 是否可以评论 - CommentType string `CommentType` // default 或 disqus - DisqusId string `DisqusId` + DisqusId string `DisqusId` Style string `Style` // 风格 Css string `Css` // 自定义css + ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id + ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/ + + CateIds []string `CateIds,omitempty` // 分类Id, 排序好的 + Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"] + + PerPageSize int `PerPageSize,omitempty` + SortField string `SortField` // 排序字段 + IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序 + SubDomain string `SubDomain` // 二级域名 Domain string `Domain` // 自定义域名 + +} + +// 博客统计信息 +type BlogStat struct { + NoteId bson.ObjectId `bson:"_id,omitempty"` + ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28 + LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28 + CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28 +} + +// 单页 +type BlogSingle struct { + SingleId bson.ObjectId `bson:"_id"` + UserId bson.ObjectId `UserId` + Title string `Title` + Content string `Content` + UpdatedTime time.Time `UpdatedTime` + CreatedTime time.Time `CreatedTime` } //------------------------ diff --git a/app/info/ThemeInfo.go b/app/info/ThemeInfo.go new file mode 100644 index 0000000..886cce3 --- /dev/null +++ b/app/info/ThemeInfo.go @@ -0,0 +1,26 @@ +package info + +import ( + "gopkg.in/mgo.v2/bson" + "time" +) + +// 主题, 每个用户有多个主题, 这里面有主题的配置信息 +// 模板, css, js, images, 都在路径Path下 +type Theme struct { + ThemeId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 + UserId bson.ObjectId `UserId` + Name string `Name` + Version string `Version` + Author string `Author` + AuthorUrl string `AuthorUrl` + Path string `Path` // 文件夹路径 + Info map[string]interface{} `Info` // 所有信息 + IsActive bool `IsActive` // 是否在用 + + IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题 + Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed + + CreatedTime time.Time `CreatedTime` + UpdatedTime time.Time `UpdatedTime` +} diff --git a/app/info/UserInfo.go b/app/info/UserInfo.go index 104069e..8a406d5 100644 --- a/app/info/UserInfo.go +++ b/app/info/UserInfo.go @@ -34,4 +34,45 @@ type User struct { ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别 ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示 ThirdType int `ThirdType` // 第三方类型 + + // 用户的帐户类型 + + ImageNum int `bson:"ImageNum" json:"-"` // 图片数量 + ImageSize int `bson:"ImageSize" json:"-"` // 图片大小 + AttachNum int `bson:"AttachNum" json:"-"` // 附件数量 + AttachSize int `bson:"AttachSize" json:"-"` // 附件大小 + PerAttachSize int `bson:"PerAttachSize" json:"-"` // 单个附件大小 + + AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium + AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期 + AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期 + // 阈值 + MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量 + MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小 + MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量 + MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小 + MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小 +} + +type UserAccount struct { + AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium + AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期 + AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期 + // 阈值 + MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量 + MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小 + MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量 + MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小 + MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小 +} + +// 用户与博客信息结合, 公开 +type UserAndBlog struct { + UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 + Email string `Email` // 全是小写 + Username string `Username` // 不区分大小写, 全是小写 + Logo string `Logo` + BlogTitle string `BlogTitle` // 博客标题 + BlogLogo string `BlogLogo` // 博客Logo + BlogUrl string `BlogUrl` // 博客链接 } diff --git a/app/init.go b/app/init.go index 10e94f9..94b6245 100644 --- a/app/init.go +++ b/app/init.go @@ -7,6 +7,7 @@ import ( "github.com/leanote/leanote/app/db" "github.com/leanote/leanote/app/controllers" "github.com/leanote/leanote/app/controllers/admin" + "github.com/leanote/leanote/app/controllers/member" _ "github.com/leanote/leanote/app/lea/binder" "github.com/leanote/leanote/app/lea/session" "github.com/leanote/leanote/app/lea/memcache" @@ -56,6 +57,11 @@ func init() { i = i - 1; return i } + // 增加或减少 + revel.TemplateFuncs["incr"] = func(n, i int) int { + n = n + i; + return n + } revel.TemplateFuncs["join"] = func(arr []string) template.HTML { if arr == nil { return template.HTML("") @@ -79,6 +85,9 @@ func init() { revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML { return template.HTML(t.Format("2006-01-02 15:04:05")) } + revel.TemplateFuncs["dateFormat"] = func(t time.Time, format string) template.HTML { + return template.HTML(t.Format(format)) + } revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML { sec, _ := strconv.Atoi(unixSec) t := time.Unix(int64(sec), 0) @@ -135,8 +144,6 @@ func init() { } */ revel.TemplateFuncs["li"] = func(a string) string { - Log(a) - Log("life==") return "" } // str连接 @@ -248,6 +255,7 @@ func init() { // https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js // http://play.golang.org/p/snygrVpQva // http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour + /* revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool { switch a1.(type) { case string: @@ -273,6 +281,7 @@ func init() { } return false } + */ /* {{range $i := N 1 10}} @@ -302,6 +311,7 @@ func init() { service.InitService() controllers.InitService() admin.InitService() + member.InitService() service.ConfigS.InitGlobalConfigs() }) } \ No newline at end of file diff --git a/app/lea/File.go b/app/lea/File.go index d3d54f9..20e245f 100644 --- a/app/lea/File.go +++ b/app/lea/File.go @@ -1,10 +1,11 @@ package lea import ( - "strings" - "path/filepath" - "os" "io" + "io/ioutil" + "os" + "path/filepath" + "strings" ) // 分离文件名与扩展名(包含.) @@ -14,14 +15,14 @@ func SplitFilename(filename string) (baseName, ext string) { ext = SubstringByte(filename, strings.LastIndex(filename, ".")) baseName = strings.TrimRight(filename, ext) ext = strings.ToLower(ext) - return; + return } // 转换文件的格式 // toExt包含. func TransferExt(path string, toExt string) string { - dir := filepath.Dir(path) + "/" // 文件路径 - name := filepath.Base(path) // 文件名 a.jpg + dir := filepath.Dir(path) + "/" // 文件路径 + name := filepath.Base(path) // 文件名 a.jpg // 获取文件名与路径 baseName, _ := SplitFilename(name) return dir + baseName + toExt @@ -38,7 +39,7 @@ func GetFilesize(path string) int64 { if err == nil { return fileinfo.Size() } - return 0; + return 0 } // 清空dir下所有的文件和文件夹 @@ -79,12 +80,103 @@ func CopyFile(srcName, dstName string) (written int64, err error) { return io.Copy(dst, src) } +func CopyDir(source string, dest string) (err error) { + // get properties of source dir + sourceinfo, err := os.Stat(source) + if err != nil { + return err + } + + // create dest dir + + err = os.MkdirAll(dest, sourceinfo.Mode()) + if err != nil { + return err + } + + directory, _ := os.Open(source) + + objects, err := directory.Readdir(-1) + + for _, obj := range objects { + + sourcefilepointer := source + "/" + obj.Name() + + destinationfilepointer := dest + "/" + obj.Name() + + if obj.IsDir() { + // create sub-directories - recursively + err = CopyDir(sourcefilepointer, destinationfilepointer) + if err != nil { +// fmt.Println(err) + } + } else { + // perform copy + _, err = CopyFile(sourcefilepointer, destinationfilepointer) + if err != nil { +// fmt.Println(err) + } + } + } + return +} + +func DeleteFile(path string) bool { + err := os.Remove(path) + if err != nil { + return false + } + return true +} + func IsDirExists(path string) bool { - fi, err := os.Stat(path) - if err != nil { - return os.IsExist(err) - }else{ - return fi.IsDir() - } - return false -} \ No newline at end of file + fi, err := os.Stat(path) + if err != nil { + return os.IsExist(err) + } else { + return fi.IsDir() + } + return false +} + +// 获得文件str内容 +func GetFileStrContent(path string) string { + fileBytes, err := ioutil.ReadFile(path) + if err != nil { + return "" + } + return string(fileBytes) +} + +func IsFileExist(filename string) bool { + var exist = true + if _, err := os.Stat(filename); os.IsNotExist(err) { + exist = false + } + return exist +} + +// 写入string内容 +func PutFileStrContent(path, content string) bool { + var f *os.File + var err1 error + defer (func() { + if f != nil { + f.Close() + } + })() + f, err1 = os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) //打开文件 + // Log(err1) + // var n int + _, err1 = io.WriteString(f, content) //写入文件(字符串) + // Log(content) + // Log(err1) + // Log(n) + // Log(path) + + if err1 != nil { + Log(err1) + return false + } + return true +} diff --git a/app/lea/Vd.go b/app/lea/Vd.go index 4adcf12..6dcf409 100644 --- a/app/lea/Vd.go +++ b/app/lea/Vd.go @@ -27,6 +27,12 @@ var rulesStr = `{ ], "domain": [ {"rule": "domain", "msg": "errorDomain"} + ], + "perPageSize": [ + {"rule": "min", "data": "1", "msg": "errorPerPageSize"} + ], + "sortField": [ + {"rule": "sortField", "msg": "errorSortField"} ] } ` @@ -49,6 +55,25 @@ var rules = map[string]func(string, map[string]string)(bool, string) { ok = len(value) >= dataI return }, + "min": func(value string, rule map[string]string)(ok bool, msg string) { + if value == "" { + return + } + data := rule["data"] + dataI, _ := strconv.Atoi(data) + vI, _ := strconv.Atoi(value) + ok = vI >= dataI + return + }, + + "sortField": func(value string, rule map[string]string)(ok bool, msg string) { + if value == "" { + return + } + sortFields := []string{"PublicTime", "CreatedTime", "UpdatedTime", "Title"} + ok = InArray(sortFields, value) + return + }, "password": func(value string, rule map[string]string)(ok bool, msg string) { if value == "" { diff --git a/app/lea/archive/tar.go b/app/lea/archive/tar.go new file mode 100644 index 0000000..3bb914f --- /dev/null +++ b/app/lea/archive/tar.go @@ -0,0 +1,230 @@ +package archive + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "os" + "path" +) + +// main functions shows how to TarGz a directory/file and +// UnTarGz a file +// Gzip and tar from source directory or file to destination file +// you need check file exist before you call this function + +func main() { + /* + os.Mkdir("/home/ty4z2008/tar", 0777) + w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf") + //targetfile,sourcefile + if err != nil { + fmt.Println(err.Error()) + } + fmt.Println(w) + + TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩 + //UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压 + os.RemoveAll("/home/ty4z2008/tar") + */ +// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz") + Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip") + fmt.Println("ok") +} + +func TarGz(srcDirPath string, destFilePath string) (ok bool) { + defer func() { //必须要先声明defer,否则不能捕获到panic异常 + if err := recover(); err != nil { + ok = false + } + + }() + + fw, err := os.Create(destFilePath) + + if err != nil { + panic(err) + } + defer fw.Close() + + // Gzip writer + gw := gzip.NewWriter(fw) + defer gw.Close() + + // Tar writer + tw := tar.NewWriter(gw) + defer tw.Close() + + // Check if it's a file or a directory + f, err := os.Open(srcDirPath) + if err != nil { + panic(err) + } + fi, err := f.Stat() + if err != nil { + panic(err) + } + if fi.IsDir() { + // handle source directory +// fmt.Println("Cerating tar.gz from directory...") + tarGzDir(srcDirPath, path.Base(srcDirPath), tw) + } else { + // handle file directly +// fmt.Println("Cerating tar.gz from " + fi.Name() + "...") + tarGzFile(srcDirPath, fi.Name(), tw, fi) + } + ok = true + return +} + +// Deal with directories +// if find files, handle them with tarGzFile +// Every recurrence append the base path to the recPath +// recPath is the path inside of tar.gz +func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) { + // Open source diretory + dir, err := os.Open(srcDirPath) + if err != nil { + panic(err) + } + defer dir.Close() + + // Get file info slice + fis, err := dir.Readdir(0) + if err != nil { + panic(err) + } + for _, fi := range fis { + // Append path + curPath := srcDirPath + "/" + fi.Name() + // Check it is directory or file + if fi.IsDir() { + // Directory + // (Directory won't add unitl all subfiles are added) +// fmt.Printf("Adding path...%s\n", curPath) + tarGzDir(curPath, recPath+"/"+fi.Name(), tw) + } else { + // File +// fmt.Printf("Adding file...%s\n", curPath) + } + + tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi) + } +} + +// Deal with files +func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) { + if fi.IsDir() { +// fmt.Println("??") + // Create tar header + hdr := new(tar.Header) + // if last character of header name is '/' it also can be directory + // but if you don't set Typeflag, error will occur when you untargz + hdr.Name = recPath // + "/" +// fmt.Println(hdr.Name) + hdr.Typeflag = tar.TypeDir +// hdr.Size = 0 + //hdr.Mode = 0755 | c_ISDIR +// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!! +// hdr.ModTime = fi.ModTime() // 加这个会有错误!! + + // Write hander + err := tw.WriteHeader(hdr) + if err != nil { + panic(err) + } + } else { + // File reader + fr, err := os.Open(srcFile) + if err != nil { + panic(err) + } + defer fr.Close() + + // Create tar header + hdr := new(tar.Header) + hdr.Name = recPath +// fmt.Println(hdr.Name) + hdr.Size = fi.Size() + hdr.Mode = int64(fi.Mode()) + hdr.ModTime = fi.ModTime() + + // Write hander + err = tw.WriteHeader(hdr) + if err != nil { + panic(err) + } + + // Write file data + _, err = io.Copy(tw, fr) + if err != nil { + panic(err) + } + } +} + +// Ungzip and untar from source file to destination directory +// you need check file exist before you call this function +func UnTarGz(srcFilePath string, destDirPath string) { +// fmt.Println("UnTarGzing " + srcFilePath + "...") + // Create destination directory + os.Mkdir(destDirPath, os.ModePerm) + + fr, err := os.Open(srcFilePath) + if err != nil { + panic(err) + } + defer fr.Close() + + // Gzip reader + gr, err := gzip.NewReader(fr) + if err != nil { + panic(err) + } + defer gr.Close() + + // Tar reader + tr := tar.NewReader(gr) + + for { + hdr, err := tr.Next() + if err == io.EOF { + // End of tar archive + break + } + //handleError(err) +// fmt.Println("UnTarGzing file..." + hdr.Name) + // Check if it is diretory or file + if hdr.Typeflag != tar.TypeDir { + // Get files from archive + // Create diretory before create file + os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm) + // Write data to file + fw, _ := os.Create(destDirPath + "/" + hdr.Name) + if err != nil { + panic(err) + } + _, err = io.Copy(fw, tr) + if err != nil { + panic(err) + } + } + } +// fmt.Println("Well done!") +} + +// Copyfile +func CopyFile(dstName, srcName string) (written int64, err error) { + src, err := os.Open(srcName) + if err != nil { + return + } + defer src.Close() + dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return + } + defer dst.Close() + return io.Copy(dst, src) +} \ No newline at end of file diff --git a/app/lea/archive/zip.go b/app/lea/archive/zip.go new file mode 100644 index 0000000..c1a705c --- /dev/null +++ b/app/lea/archive/zip.go @@ -0,0 +1,192 @@ +package archive + +import ( + "archive/zip" + "fmt" + "strings" + "io" + "os" + "path" +) + +// main functions shows how to TarGz a directory/file and +// UnTarGz a file +// Gzip and tar from source directory or file to destination file +// you need check file exist before you call this function + +func Zip(srcDirPath string, destFilePath string) (ok bool) { + defer func() { //必须要先声明defer,否则不能捕获到panic异常 + if err := recover(); err != nil { + ok = false + } + }() + + fw, err := os.Create(destFilePath) + + if err != nil { + panic(err) + } + defer fw.Close() + + // Tar writer + tw := zip.NewWriter(fw) + defer tw.Close() + + // Check if it's a file or a directory + f, err := os.Open(srcDirPath) + if err != nil { + panic(err) + } + fi, err := f.Stat() + if err != nil { + panic(err) + } + if fi.IsDir() { + // handle source directory +// fmt.Println("Cerating tar.gz from directory...") + zipDir(srcDirPath, path.Base(srcDirPath), tw) + } else { + // handle file directly +// fmt.Println("Cerating tar.gz from " + fi.Name() + "...") + zipFile(srcDirPath, fi.Name(), tw, fi) + } + ok = true + return +} + +// Deal with directories +// if find files, handle them with zipFile +// Every recurrence append the base path to the recPath +// recPath is the path inside of tar.gz +func zipDir(srcDirPath string, recPath string, tw *zip.Writer) { + // Open source diretory + dir, err := os.Open(srcDirPath) + if err != nil { + panic(err) + } + defer dir.Close() + + // Get file info slice + fis, err := dir.Readdir(0) + if err != nil { + panic(err) + } + for _, fi := range fis { + // Append path + curPath := srcDirPath + "/" + fi.Name() + // Check it is directory or file + if fi.IsDir() { + // Directory + // (Directory won't add unitl all subfiles are added) +// fmt.Printf("Adding path...%s\n", curPath) + zipDir(curPath, recPath+"/"+fi.Name(), tw) + } else { + // File +// fmt.Printf("Adding file...%s\n", curPath) + } + + zipFile(curPath, recPath+"/"+fi.Name(), tw, fi) + } +} + +// Deal with files +func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) { + if fi.IsDir() { +// fmt.Println("??") + // Create tar header + /* + fh, err := zip.FileInfoHeader(fi) + if err != nil { + panic(err) + } + fh.Name = recPath // + "/" + err = tw.WriteHeader(hdr) + tw.Create(recPath) + */ + } else { + // File reader + fr, err := os.Open(srcFile) + if err != nil { + panic(err) + } + defer fr.Close() + + // Write hander + w, err2 := tw.Create(recPath) + if err2 != nil { + panic(err) + } + // Write file data + _, err = io.Copy(w, fr) + if err != nil { + panic(err) + } + } +} + +// Ungzip and untar from source file to destination directory +// you need check file exist before you call this function +func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) { + ok = false + msg = "" + + defer func() { //必须要先声明defer,否则不能捕获到panic异常 + if err := recover(); err != nil { + msg = fmt.Sprintf("%v", err) + ok = false + } + }() + + os.Mkdir(destDirPath, os.ModePerm) + r, err := zip.OpenReader(srcFilePath); + if err != nil { + panic(err) + } + defer r.Close(); + for _, f := range r.File { +// fmt.Println("FileName : ", f.Name); // j/aaa.zip + rc, err := f.Open(); + if err!=nil { + panic(err) + } + + // 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名 + paths := strings.Split(f.Name, "/") + prePath := "" + filename := "" + l := len(paths) +// fmt.Println(l) + if l > 1 { + // 去掉第1个文件夹 + if l == 2 { + filename = paths[1] + } else { + filename = paths[l-1] + prePath = strings.Join(paths[1:l-1], "/") + } + } else { + filename = f.Name + } +// fmt.Println(prePath) + + // 相对于目标文件件下的路径 + destPath := destDirPath + "/" + filename + if prePath != "" { + os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm) + destPath = destDirPath + "/" + prePath + "/" + filename + } + // Write data to file +// fmt.Println(destPath) + fw, _ := os.Create(destPath) + if err != nil { + panic(err) + } + _, err = io.Copy(fw, rc) + if err != nil { + panic(err) + } + } + + ok = true + return +} \ No newline at end of file diff --git a/app/lea/blog/Template.go b/app/lea/blog/Template.go new file mode 100644 index 0000000..7586788 --- /dev/null +++ b/app/lea/blog/Template.go @@ -0,0 +1,302 @@ +package blog + +import ( + . "github.com/leanote/leanote/app/lea" + "github.com/revel/revel" + "html/template" + "io/ioutil" + // "os" + "fmt" + "bytes" + "io" + "net/http" + "regexp" + "strconv" + "strings" +) + +//-------------------- +// leanote 自定义主题 +// 不使用revel的模板机制 +// By life +//-------------------- + +var ts = []string{"header.html", "footer.html", "highlight.html", "comment.html", "view.html", "404.html"} +var selfTs = []string{"header.html", "footer.html", "index.html", "about_me.html"} // 用户自定义的文件列表 + +type BlogTpl struct { + Template *template.Template + PathContent map[string]string // path => content +} + +func (this *BlogTpl) Content(name string) string { + return this.PathContent[name] +} + +var BlogTplObject *BlogTpl +var CloneTemplate *template.Template + +type RenderTemplateResult struct { + Template *template.Template + PathContent map[string]string + RenderArgs map[string]interface{} + + IsPreview bool // 是否是预览 + CurBlogTpl *BlogTpl +} + +func parseTemplateError(err error) (templateName string, line int, description string) { + description = err.Error() + i := regexp.MustCompile(`:\d+:`).FindStringIndex(description) + if i != nil { + line, err = strconv.Atoi(description[i[0]+1 : i[1]-1]) + if err != nil { + } + templateName = description[:i[0]] + if colon := strings.Index(templateName, ":"); colon != -1 { + templateName = templateName[colon+1:] + } + templateName = strings.TrimSpace(templateName) + description = description[i[1]+1:] + } + return templateName, line, description +} +func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) { + err := r.Template.Execute(wr, r.RenderArgs) + if err == nil { + return + } + + var templateContent []string + templateName, line, description := parseTemplateError(err) + var content = "" + if templateName == "" { + templateName = r.Template.Name() + content = r.PathContent[templateName] + } else { + content = r.PathContent[templateName] + } + if content != "" { + templateContent = strings.Split(content, "\n") + } + + compileError := &revel.Error{ + Title: "Template Execution Error", + Path: templateName, + Description: description, + Line: line, + SourceLines: templateContent, + } + + // 这里, 错误!! + // 这里应该导向到本主题的错误页面 + resp.Status = 500 + ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp) +} + +func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) { + // Handle panics when rendering templates. + defer func() { + if err := recover(); err != nil { + } + }() + + chunked := revel.Config.BoolDefault("results.chunked", false) + + // If it's a HEAD request, throw away the bytes. + out := io.Writer(resp.Out) + if req.Method == "HEAD" { + out = ioutil.Discard + } + + // In a prod mode, write the status, render, and hope for the best. + // (In a dev mode, always render to a temporary buffer first to avoid having + // error pages distorted by HTML already written) + if chunked && !revel.DevMode { + resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8") + r.render(req, resp, out) // 这里!!! + return + } + + // Render the template into a temporary buffer, to see if there was an error + // rendering the template. If not, then copy it into the response buffer. + // Otherwise, template render errors may result in unpredictable HTML (and + // would carry a 200 status code) + var b bytes.Buffer + r.render(req, resp, &b) + if !chunked { + resp.Out.Header().Set("Content-Length", strconv.Itoa(b.Len())) + } + resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8") + b.WriteTo(out) +} + +// 博客模板 +func Init() { + BlogTplObject = &BlogTpl{PathContent: map[string]string{}} + BlogTplObject.Template = template.New("blog").Funcs(revel.TemplateFuncs) + for _, path := range ts { + fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path) + fileStr := string(fileBytes) + path := "blog/" + path +// path := path + BlogTplObject.PathContent[path] = fileStr + BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根 + } + // 复制一份 + CloneTemplate, _ = BlogTplObject.Template.Clone() +} + +// name = index.html, search.html, cate.html, page.html +// basePath 表未用户主题的基路径, 如/xxx/public/upload/32323232/themes/theme1, 如果没有, 则表示用自带的 +// isPreview 如果是, 错误提示则显示系统的 500 错误详情信息, 供debug +// +func RenderTemplate(name string, args map[string]interface{}, basePath string, isPreview bool) revel.Result { + var r *RenderTemplateResult + // 传来的主题路径为空, 则用系统的 + // 都不会为空的 + if basePath == "" { + path := "blog/" + name +// path := name + t := BlogTplObject.Template.Lookup(path) + r = &RenderTemplateResult{ + Template: t, + PathContent: BlogTplObject.PathContent, // 为了显示错误 + RenderArgs: args, // 把args给它 + } + } else { + // 复制一份 + newBlogTplObject := &BlogTpl{} + var err error + newBlogTplObject.Template, err = CloneTemplate.Clone() // 复制一份, 为防止多用户出现问题, 因为newBlogTplObject是全局的 + if err != nil { + return nil + } + newBlogTplObject.PathContent = map[string]string{} + for k, v := range BlogTplObject.PathContent { + newBlogTplObject.PathContent[k] = v + } + + // 将该basePath下的所有文件提出 + files := ListDir(basePath) + Log(basePath) + LogJ(files); + for _, t := range files { + if !strings.Contains(t, ".html") { + continue; + } + fileBytes, err := ioutil.ReadFile(basePath + "/" + t) + if err != nil { + continue + } + fileStr := string(fileBytes) + newBlogTplObject.PathContent[t] = fileStr + newBlogTplObject.Template.New(t).Parse(fileStr) + } + + // 如果本主题下没有, 则用系统的 + t := newBlogTplObject.Template.Lookup(name) + + if t == nil { + path := "blog/" + name + t = BlogTplObject.Template.Lookup(path) + } + r = &RenderTemplateResult{ + Template: t, + PathContent: newBlogTplObject.PathContent, // 为了显示错误 + RenderArgs: args, + CurBlogTpl: newBlogTplObject, + IsPreview: isPreview, + } + } + + return r +} + + +//////////////////// +// 错误显示 + +type ErrorResult struct { + RenderArgs map[string]interface{} + Error error + IsPreview bool + CurBlogTpl *BlogTpl +} + +// 错误显示出 +func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) { + format := req.Format + status := resp.Status + if status == 0 { + status = http.StatusInternalServerError + } + + contentType := revel.ContentTypeByFilename("xxx." + format) + if contentType == revel.DefaultFileContentType { + contentType = "text/plain" + } + + // Get the error template. + var err error + templatePath := fmt.Sprintf("errors/%d.%s", status, format) + err = nil +// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题 + + // This func shows a plaintext error message, in case the template rendering + // doesn't work. + showPlaintext := func(err error) { + revel.PlaintextErrorResult{fmt.Errorf("Server Error:\n%s\n\n"+ + "Additionally, an error occurred when rendering the error page:\n%s", + r.Error, err)}.Apply(req, resp) + } + + // 根据是否是preview来得到404模板 + // 是, 则显示系统的错误信息, blog-500.html + var tmpl *template.Template + if r.IsPreview { + tmpl = r.CurBlogTpl.Template.Lookup("blog/404.html") + } else { + tmpl = r.CurBlogTpl.Template.Lookup("404.html") + } + if tmpl == nil { + if err == nil { + err = fmt.Errorf("Couldn't find template %s", templatePath) + } + showPlaintext(err) + return + } + + // If it's not a revel error, wrap it in one. + var revelError *revel.Error + switch e := r.Error.(type) { + case *revel.Error: + revelError = e + case error: + revelError = &revel.Error{ + Title: "Server Error", + Description: e.Error(), + } + } + + if revelError == nil { + panic("no error provided") + } + + if r.RenderArgs == nil { + r.RenderArgs = make(map[string]interface{}) + } + r.RenderArgs["Error"] = revelError + r.RenderArgs["Router"] = revel.MainRouter + + // 不是preview就不要显示错误了 + LogJ(revelError) +// if r.IsPreview { + var b bytes.Buffer + out := io.Writer(resp.Out) + // out = ioutil.Discard + err = tmpl.Execute(&b, r.RenderArgs) + resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8") + b.WriteTo(out) +// } +} \ No newline at end of file diff --git a/app/lea/netutil/NetUtil.go b/app/lea/netutil/NetUtil.go index 9cf4ff3..c27af89 100644 --- a/app/lea/netutil/NetUtil.go +++ b/app/lea/netutil/NetUtil.go @@ -3,6 +3,7 @@ import ( "strings" "os" // "path/filepath" + "net" "net/http" "io/ioutil" . "github.com/leanote/leanote/app/lea" @@ -89,4 +90,13 @@ func trimQueryParams(url string) string { url = Substr(url, 0, pos); } return url; +} + +// 通过domain得到ip +func GetIpFromDomain(domain string) string { + ip, _ := net.LookupIP(domain) + if ip != nil && len(ip) > 0 { + return ip[0].String() + } + return "" } \ No newline at end of file diff --git a/app/lea/route/Route.go b/app/lea/route/Route.go index 386d74b..595a529 100644 --- a/app/lea/route/Route.go +++ b/app/lea/route/Route.go @@ -44,8 +44,12 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) { if route.ControllerName != "Static" { // api设置 // leanote.com/api/user/get => ApiUser::Get - if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "api/") { + //* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了 + if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){ route.ControllerName = "Api" + route.ControllerName + } else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") { + // member设置 + route.ControllerName = "Member" + route.ControllerName } // end } diff --git a/app/service/BlogService.go b/app/service/BlogService.go index 4ca78fd..a396d0b 100644 --- a/app/service/BlogService.go +++ b/app/service/BlogService.go @@ -4,11 +4,13 @@ import ( "github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/db" . "github.com/leanote/leanote/app/lea" +// "github.com/leanote/leanote/app/lea/netutil" "gopkg.in/mgo.v2/bson" // "time" -// "sort" + "sort" "strings" "time" + "strconv" ) // blog @@ -30,6 +32,13 @@ note, notebook都可设为blog type BlogService struct { } +// 得到博客统计信息 +// ReadNum, LikeNum, CommentNum +func (this *BlogService) GetBlogStat(noteId string) (stat info.BlogStat) { + note := noteService.GetBlogNote(noteId) + stat = info.BlogStat{note.NoteId, note.ReadNum, note.LikeNum, note.CommentNum} + return +} // 得到某博客具体信息 func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) { note := noteService.GetBlogNote(noteId) @@ -42,7 +51,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) { noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex()) // 组装成blogItem - blog = info.BlogItem{note, noteContent.Content, false, info.User{}} + blog = info.BlogItem{note, noteContent.Abstract, noteContent.Content, false, info.User{}} return } @@ -56,11 +65,11 @@ func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook { // 博客列表 // userId 表示谁的blog -func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) { +func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) { count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true); if(notes == nil || len(notes) == 0) { - return 0, nil + return info.Page{}, nil } // 得到content, 并且每个都要substring @@ -83,47 +92,253 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int for i, note := range notes { hasMore := true var content string + var abstract string if noteContent, ok := noteContentsMap[note.NoteId]; ok { - content = noteContent.Abstract + abstract = noteContent.Abstract + content = noteContent.Content } - blogs[i] = info.BlogItem{note, content, hasMore, info.User{}} + blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}} } - return count, blogs + + pageInfo := info.NewPage(page, pageSize, count, nil) + + return pageInfo, blogs } -func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) { +// 得到博客的标签, 那得先得到所有博客, 比较慢 +/* +[ + {Tag:xxx, Count: 32} +] +*/ +func (this *BlogService) ListBlogsTag(userId string) (info.TagsCounts) { + // 得到所有博客 + notes := []info.Note{} + query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": false, "IsBlog": true} + db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es) + if(notes == nil || len(notes) == 0) { + return nil + } + // 统计所有的Tags和数目 + tagsCount := map[string]int{} + for _, note := range notes { + tags := note.Tags + if tags != nil && len(tags) > 0 { + for _, tag := range tags { + count := tagsCount[tag] + count++ + tagsCount[tag] = count + } + } + } + // 排序, 从大到小 + var tagsCounts info.TagsCounts + tagsCounts = make(info.TagsCounts, len(tagsCount)) + i := 0 + for tag, count := range tagsCount { + tagsCounts[i] = info.TagCount{tag, count} + i++ + } + sort.Sort(&tagsCounts) + return tagsCounts +} +// 归档博客 +/* +数据: 按年汇总 +[ +archive1, +archive2, +] +archive的数据类型是 +{ +Year: 2014 +Posts: [] +} +*/ +func (this *BlogService) ListBlogsArchive(userId, notebookId string, sortField string, isAsc bool) ([]info.Archive) { + _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true); + + if(notes == nil || len(notes) == 0) { + return nil + } + + arcs := []info.Archive{} + // 按年汇总 + arcsMap := map[int]*info.Archive{} + var t time.Time + var arc *info.Archive + everYear := 0 + for _, note := range notes { + if sortField == "PublicTime" { + t = note.PublicTime + } else if sortField == "CreatedTime"{ + t = note.CreatedTime + } else { + t = note.UpdatedTime + } + year := t.Year() + if everYear == 0 { + everYear = year + } + + if everYear != year { + arcs = append(arcs, *arcsMap[everYear]) + everYear = year + } + + if arcT, ok := arcsMap[year]; ok { + arc = arcT + } else { + arc = &info.Archive{Year: year, Posts: []map[string]interface{}{}} + } + arc.Posts = append(arc.Posts, map[string]interface{}{ + "NoteId": note.NoteId.Hex(), + "Title": note.Title, + "CreatedTime": note.CreatedTime, + "UpdatedTime": note.UpdatedTime, + "PublicTime": note.PublicTime, + "Desc": note.Desc, + "Tags": note.Tags, + "CommentNum": note.CommentNum, + "ReadNum": note.ReadNum, + "LikeNum": note.LikeNum, + "IsMarkdown": note.IsMarkdown, + }); + arcsMap[year] = arc + } + // 最后一个 + arcs = append(arcs, *arcsMap[everYear]) + + return arcs +} + +// 根据tag搜索博客 +func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumber, pageSize int, sortField string, isAsc bool) (pageInfo info.Page, blogs []info.BlogItem) { + notes := []info.Note{} + skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc) + + // 不是trash的 + query := bson.M{"UserId": bson.ObjectIdHex(userId), + "IsTrash": false, + "IsBlog": true, + "Tags": bson.M{"$all": tags}} + + q := db.Notes.Find(query); + + // 总记录数 + count, _ := q.Count() + if count == 0 { + return + } + + q.Sort(sortFieldR). + Skip(skipNum). + Limit(pageSize). + All(¬es) + + blogs = this.notes2BlogItems(notes) + pageInfo = info.NewPage(pageNumber, pageSize, count, nil) + + return +} + +func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem{ + // 得到content, 并且每个都要substring + noteIds := make([]bson.ObjectId, len(notes)) + for i, note := range notes { + noteIds[i] = note.NoteId + } + + // 直接得到noteContents表的abstract + // 这里可能是乱序的 + noteContents := noteService.ListNoteContentByNoteIds(noteIds) // 返回[info.NoteContent] + noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents)) + for _, noteContent := range noteContents { + noteContentsMap[noteContent.NoteId] = noteContent + } + + // 组装成blogItem + // 按照notes的顺序 + blogs := make([]info.BlogItem, len(noteIds)) + for i, note := range notes { + hasMore := true + var content, abstract string + if noteContent, ok := noteContentsMap[note.NoteId]; ok { + abstract = noteContent.Abstract + content = noteContent.Content + } + blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}} + } + return blogs +} +func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) { count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true); if(notes == nil || len(notes) == 0) { - return 0, nil + return info.Page{}, nil } - // 得到content, 并且每个都要substring - noteIds := make([]bson.ObjectId, len(notes)) - for i, note := range notes { - noteIds[i] = note.NoteId + blogs := this.notes2BlogItems(notes) + pageInfo := info.NewPage(page, pageSize, count, nil) + return pageInfo, blogs +} + +// 上一篇文章, 下一篇文章 +// sorterField, baseTime是基准, sorterField=PublicTime, title +// isAsc是用户自定义的排序方式 +func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, baseTime interface{}) (info.Note, info.Note) { + userIdO := bson.ObjectIdHex(userId) + + var sortFieldT1, sortFieldT2 bson.M + var sortFieldR1, sortFieldR2 string + if !isAsc { + // 降序 + /* +------- pre +----- now +--- next +-- + */ + // 上一篇时间要比它大, 找最小的 + sortFieldT1 = bson.M{"$gt": baseTime} + sortFieldR1 = sorterField + // 下一篇时间要比它小 + sortFieldT2 = bson.M{"$lt": baseTime} + sortFieldR2 = "-" + sorterField + } else { + // 升序 +/* +--- pre +----- now +------- next +--------- +*/ + // 上一篇要比它小, 找最大的 + sortFieldT1 = bson.M{"$lt": baseTime} + sortFieldR1 = "-" + sorterField + // 下一篇, 找最小的 + sortFieldT2 = bson.M{"$gt": baseTime} + sortFieldR2 = sorterField } - // 直接得到noteContents表的abstract - // 这里可能是乱序的 - noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent] - noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents)) - for _, noteContent := range noteContents { - noteContentsMap[noteContent.NoteId] = noteContent + // 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序 + note := info.Note{} + query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true, + sorterField: sortFieldT1, } + q := db.Notes.Find(query); + q.Sort(sortFieldR1).Limit(1).One(¬e) + + // 下一篇, 比基时间要大, 但是是第一篇, 所以是升序 + note2 := info.Note{} + query[sorterField] = sortFieldT2 +// Log(isAsc) +// LogJ(query) +// Log(sortFieldR2) + q = db.Notes.Find(query); + q.Sort(sortFieldR2).Limit(1).One(¬e2) - // 组装成blogItem - // 按照notes的顺序 - blogs := make([]info.BlogItem, len(noteIds)) - for i, note := range notes { - hasMore := true - var content string - if noteContent, ok := noteContentsMap[note.NoteId]; ok { - content = noteContent.Abstract - } - blogs[i] = info.BlogItem{note, content, hasMore, info.User{}} - } - return count, blogs + return note, note2 } //------- @@ -200,29 +415,39 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b content = noteContent.Abstract } */ - blogs[i] = info.BlogItem{note, content, hasMore, userMap[note.UserId]} + blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]} } pageInfo = info.NewPage(page, pageSize, count, nil) return pageInfo, blogs } + //------------------------ // 博客设置 func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) { - /* - if userBlog.Title == "" { - userInfo := userService.GetUserInfo(userBlog) - userBlog.Title = userInfo.Username + " 's Blog" - } - */ - // Logo路径问题, 有些有http: 有些没有 - Log(userBlog.Logo) if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") { userBlog.Logo = strings.Trim(userBlog.Logo, "/") userBlog.Logo = siteUrl + "/" + userBlog.Logo } + + if userBlog.SortField == "" { + userBlog.SortField = "PublicTime" + } + if userBlog.PerPageSize <= 0 { + userBlog.PerPageSize = 10 + } + + // themePath + if userBlog.Style == "" { + userBlog.Style = defaultStyle + } + if userBlog.ThemeId == "" { + userBlog.ThemePath = themeService.GetDefaultThemePath(userBlog.Style) + } else { + userBlog.ThemePath = themeService.GetThemePath(userBlog.UserId.Hex(), userBlog.ThemeId.Hex()) + } } func (this *BlogService) GetUserBlog(userId string) info.UserBlog { userBlog := info.UserBlog{} @@ -246,7 +471,28 @@ func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.User func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool { return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog) } +// 分页与排序 +func (this *BlogService) UpdateUserBlogPaging(userId string, perPageSize int, sortField string, isAsc bool) (ok bool, msg string) { + if ok, msg = Vds(map[string]string{"perPageSize": strconv.Itoa(perPageSize), "sortField": sortField}); !ok { + return + } + ok = db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, + bson.M{"PerPageSize": perPageSize, "SortField": sortField, "IsAsc": isAsc}) + return +} +func (this *BlogService) GetUserBlogBySubDomain(subDomain string) info.UserBlog { + blogUser := info.UserBlog{} + db.GetByQ(db.UserBlogs, bson.M{"SubDomain": subDomain}, &blogUser) + this.fixUserBlog(&blogUser) + return blogUser +} +func (this *BlogService) GetUserBlogByDomain(domain string) info.UserBlog { + blogUser := info.UserBlog{} + db.GetByQ(db.UserBlogs, bson.M{"Domain": domain}, &blogUser) + this.fixUserBlog(&blogUser) + return blogUser +} //--------------------- // 后台管理 @@ -264,7 +510,7 @@ func (this *BlogService) SetRecommend(noteId string, isRecommend bool) bool { // 博客社交, 评论 // 返回所有liked用户, bool是否还有 -func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User, bool) { +func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.UserAndBlog, bool) { // 默认前5 pageSize := 5 skipNum, sortFieldR := parsePageAndSort(1, pageSize, "CreatedTime", false) @@ -291,11 +537,11 @@ func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User, userIds[i] = like.UserId } // 得到用户信息 - userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds) + userMap := userService.MapUserAndBlogByUserIds(userIds) - users := make([]info.User, len(likes)); + users := make([]info.UserAndBlog, len(likes)); for i, like := range likes { - users[i] = userMap[like.UserId] + users[i] = userMap[like.UserId.Hex()] } return users, count > pageSize @@ -495,7 +741,7 @@ func (this *BlogService) LikeComment(commentId, userId string) (ok bool, isILike // 评论列表 // userId主要是显示userId是否点过某评论的赞 // 还要获取用户信息 -func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.User) { +func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.UserAndBlog) { pageInfo := info.Page{CurPage: page} comments2 := []info.BlogComment{} @@ -540,15 +786,10 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) } // 得到用户信息 - userMap := userService.MapUserInfoByUserIds(userIds) - userMap2 := make(map[string]info.User, len(userMap)) - for userId, v := range userMap { - userMap2[userId.Hex()] = v - } - + userMap := userService.MapUserAndBlogByUserIds(userIds) pageInfo = info.NewPage(page, pageSize, count, nil) - return pageInfo, comments, userMap2 + return pageInfo, comments, userMap } // 举报 @@ -568,4 +809,127 @@ func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool) report.CommentId = bson.ObjectIdHex(commentId) } return db.Insert(db.Reports, report) -} \ No newline at end of file +} + +//--------------- +// 分类排序 + +// CateIds +func (this *BlogService) UpateCateIds(userId string, cateIds[] string) bool { + return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "CateIds", cateIds) +} + +// 单页 +func (this *BlogService) GetSingles(userId string) []map[string]string { + userBlog := this.GetUserBlog(userId) + singles := userBlog.Singles + return singles +} +func (this *BlogService) GetSingle(singleId string) info.BlogSingle { + page := info.BlogSingle{} + db.Get(db.BlogSingles, singleId, &page) + return page +} + +func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd bool, singleId, title string) (ok bool) { + userBlog := this.GetUserBlog(userId) + singles := userBlog.Singles + if singles == nil { + singles = []map[string]string{} + } + if isDelete || !isAdd { // 删除或更新, 需要找到相应的 + i := 0 + for _, p := range singles { + if p["SingleId"] == singleId { + break; + } + i++ + } + // 得到i + // 找不到 + if i == len(singles) { + } else { + // 找到了, 如果是删除, 则删除 + if isDelete { + singles = append(singles[:i], singles[i+1:]...) + } else { + singles[i]["Title"] = title + } + } + } else { + // 是添加, 直接添加到最后 + singles = append(singles, map[string]string{"SingleId": singleId, "Title": title}) + } + return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles) +} + +// 删除页面 +func (this *BlogService) DeleteSingle(userId, singleId string) (ok bool) { + ok = db.DeleteByIdAndUserId(db.BlogSingles, singleId, userId) + if ok { + // 还要修改UserBlog中的Singles + this.updateBlogSingles(userId, true, false, singleId, "") + } + return +} +// 更新或添加 +func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content string) (ok bool) { + ok = false + if singleId != "" { + ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{ + "Title": title, + "Content": content, + "UpdatedTime": time.Now(), + }) + if ok { + // 还要修改UserBlog中的Singles + this.updateBlogSingles(userId, false, false, singleId, title) + } + return + } + // 添加 + page := info.BlogSingle{SingleId: bson.NewObjectId(), UserId: bson.ObjectIdHex(userId), Title: title, Content: content, + CreatedTime: time.Now(), + } + page.UpdatedTime = page.CreatedTime + ok = db.Insert(db.BlogSingles, page) + + // 还要修改UserBlog中的Singles + this.updateBlogSingles(userId, false, true, page.SingleId.Hex(), title) + + return +} + +// 重新排序 +func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool) { + if singleIds == nil || len(singleIds) == 0 { + return + } + userBlog := this.GetUserBlog(userId) + singles := userBlog.Singles + if singles == nil || len(singles) == 0 { + return + } + + singlesMap := map[string]map[string]string{} + for _, page := range singles { + singlesMap[page["SingleId"]] = page + } + + singles2 := make([]map[string]string, len(singles)) + for i, singleId := range singleIds { + singles2[i] = singlesMap[singleId] + } + + return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles2) +} + +// 得到用户的博客url +func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog) (string) { + if userBlog.Domain != "" && configService.AllowCustomDomain() { + return configService.GetUserUrl(userBlog.Domain) + } else if userBlog.SubDomain != "" { + return configService.GetUserSubUrl(userBlog.SubDomain) + } + return configService.GetBlogUrl() + "/" + userBlog.UserId.Hex() +} diff --git a/app/service/NoteService.go b/app/service/NoteService.go index dd8386b..a4accd3 100644 --- a/app/service/NoteService.go +++ b/app/service/NoteService.go @@ -111,6 +111,11 @@ func (this *NoteService) ListNoteAbstractsByNoteIds(noteIds []bson.ObjectId) (no db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es) return } +func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) { + notes = []info.NoteContent{} + db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract", "Content"}, ¬es) + return +} // 添加笔记 // 首先要判断Notebook是否是Blog, 是的话设为blog @@ -171,6 +176,17 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC // 添加笔记和内容 // 这里使用 info.NoteAndContent 接收? +func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note { + if note.UserId.Hex() != updatedUserId { + if !shareService.HasUpdateNotebookPerm(note.UserId.Hex(), updatedUserId, note.NotebookId.Hex()) { + Log("NO AUTH11") + return info.Note{} + } else { + Log("HAS AUTH -----------") + } + } + return this.AddNoteAndContent(note, noteContent, bson.ObjectIdHex(updatedUserId)); +} func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note { if(note.NoteId.Hex() == "") { noteId := bson.NewObjectId() @@ -194,7 +210,7 @@ func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUp // updatedUserId 要修改userId的note, 此时需要判断是否有修改权限 if userId != updatedUserId { if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) { - Log("NO AUTH") + Log("NO AUTH2") return false } else { Log("HAS AUTH -----------") @@ -419,15 +435,20 @@ func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId { } //------------------ -// 搜索Note +// 搜索Note, 博客使用了 func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) { notes = []info.Note{} skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc) + // 利用标题和desc, 不用content + orQ := []bson.M{ + bson.M{"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}, + bson.M{"Desc": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}, + } // 不是trash的 query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": false, - "Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}, + "$or": orQ, } if isBlog { query["IsBlog"] = true @@ -509,11 +530,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb return } + //------------ // 统计 -func (this *NoteService) CountNote() int { - return db.Count(db.Notes, bson.M{"IsTrash": false}) +func (this *NoteService) CountNote(userId string) int { + q := bson.M{"IsTrash": false} + if userId != "" { + q["UserId"] = bson.ObjectIdHex(userId) + } + return db.Count(db.Notes, q) } -func (this *NoteService) CountBlog() int { - return db.Count(db.Notes, bson.M{"IsBlog": true, "IsTrash": false}) +func (this *NoteService) CountBlog(userId string) int { + q := bson.M{"IsBlog": true, "IsTrash": false} + if userId != "" { + q["UserId"] = bson.ObjectIdHex(userId) + } + return db.Count(db.Notes, q) } \ No newline at end of file diff --git a/app/service/ThemeService.go b/app/service/ThemeService.go new file mode 100644 index 0000000..1f717e9 --- /dev/null +++ b/app/service/ThemeService.go @@ -0,0 +1,477 @@ +package service + +import ( + "github.com/revel/revel" + "github.com/leanote/leanote/app/info" + "github.com/leanote/leanote/app/db" + . "github.com/leanote/leanote/app/lea" + "github.com/leanote/leanote/app/lea/archive" + "gopkg.in/mgo.v2/bson" + "time" + "strings" + "os" + "fmt" + "html/template" + "regexp" + "encoding/json" +) + +// 主题 +type ThemeService struct { +} + +var defaultStyle = "blog_default" +var elegantStyle = "blog_daqi" +var fixedStyle = "blog_left_fixed" + +// admin用户的主题基路径 +func (this *ThemeService) getDefaultThemeBasePath() string { + return revel.BasePath + "/public/blog/themes" +} +// 默认主题路径 +func (this *ThemeService) getDefaultThemePath(style string) string { + if style == elegantStyle { + return this.getDefaultThemeBasePath() + "/elegant" + } else if style == fixedStyle { + return this.getDefaultThemeBasePath() + "/nav_fixed" + } else { + return this.getDefaultThemeBasePath() + "/default" + } +} +// blogService用 +func (this *ThemeService) GetDefaultThemePath(style string) string { + if style == elegantStyle { + return "public/blog/themes/elegant" + } else if style == fixedStyle { + return "public/blog/themes/nav_fixed" + } else { + return "public/blog/themes/default" + } +} + +// 得到默认主题 +// style是之前的值, 有3个值 blog_default, blog_daqi, blog_left_fixed +func (this *ThemeService) getDefaultTheme(style string) info.Theme { + if style == elegantStyle { + return info.Theme{ + IsDefault: true, + Path: "public/blog/themes/elegant", + Name: "leanote elegant", + Author: "leanote", + AuthorUrl: "http://leanote.com", + Version: "1.0", + } + } else if style == fixedStyle { + return info.Theme{ + IsDefault: true, + Path: "public/blog/themes/nav_fixed", + Name: "leanote nav fixed", + Author: "leanote", + AuthorUrl: "http://leanote.com", + Version: "1.0", + } + } else { // blog default + return info.Theme{ + IsDefault: true, + Path: "public/blog/themes/default", + Name: "leanote default", + Author: "leanote", + AuthorUrl: "http://leanote.com", + Version: "1.0", + } + } +} + +// 用户的主题路径设置 +func (this *ThemeService) getUserThemeBasePath(userId string) string { + return revel.BasePath + "/public/upload/" + userId + "/themes" +} +func (this *ThemeService) getUserThemePath(userId, themeId string) string { + return this.getUserThemeBasePath(userId) + "/" + themeId +} +func (this *ThemeService) getUserThemePath2(userId, themeId string) string { + return "public/upload/" + userId + "/themes/" + themeId +} + +// 新建主题 +// 复制默认主题到文件夹下 +func (this *ThemeService) CopyDefaultTheme(userBlog info.UserBlog) (ok bool, themeId string) { + newThemeId := bson.NewObjectId() + themeId = newThemeId.Hex() + userId := userBlog.UserId.Hex() + themePath := this.getUserThemePath(userId, themeId) + err := os.MkdirAll(themePath, 0755) + if err != nil { + return + } + // 复制默认主题 + defaultThemePath := this.getDefaultThemePath(userBlog.Style) + err = CopyDir(defaultThemePath, themePath) + if err != nil { + return + } + + // 保存到数据库中 + theme, _ := this.getThemeConfig(themePath) + theme.ThemeId = newThemeId + theme.Path = this.getUserThemePath2(userId, themeId) + theme.CreatedTime = time.Now() + theme.UpdatedTime = theme.CreatedTime + theme.UserId = bson.ObjectIdHex(userId) + + ok = db.Insert(db.Themes, theme) + return ok, themeId +} + +// 第一次新建主题 +// 设为active true +func (this *ThemeService) NewThemeForFirst(userBlog info.UserBlog) (ok bool, themeId string) { + ok, themeId = this.CopyDefaultTheme(userBlog) + db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true) + return +} + +// 新建主题, 判断是否有主题了 +func (this *ThemeService) NewTheme(userId string) (ok bool, themeId string) { + userBlog := blogService.GetUserBlog(userId) + // 如果还没有主题, 那先复制旧的主题 + if userBlog.ThemeId == "" { + themeService.NewThemeForFirst(userBlog) + } + // 再copy一个默认主题 + userBlog.Style = "defaultStyle"; + ok, themeId = this.CopyDefaultTheme(userBlog) + return +} + +// 将字符串转成Theme配置 +func (this *ThemeService) parseConfig(configStr string) (theme info.Theme, err error) { + theme = info.Theme{} + // 除去/**/注释 + reg, _ := regexp.Compile("/\\*[\\s\\S]*?\\*/") + configStr = reg.ReplaceAllString(configStr, "") + // 转成map + config := map[string]interface{}{} + err = json.Unmarshal([]byte(configStr), &config) + if err != nil { + return + } + // 没有错, 则将Name, Version, Author, AuthorUrl + Name := config["Name"] + if Name != nil { + theme.Name = Name.(string) + } + Version := config["Version"] + if Version != nil { + theme.Version = Version.(string) + } + Author := config["Author"] + if Author != nil { + theme.Author = Author.(string) + } + AuthorUrl := config["AuthorUrl"] + if AuthorUrl != nil { + theme.AuthorUrl = AuthorUrl.(string) + } + theme.Info = config + + return +} + +// 读取theme.json得到值 +func (this *ThemeService) getThemeConfig(themePath string) (theme info.Theme, err error) { + theme = info.Theme{} + configStr := GetFileStrContent(themePath + "/theme.json") + theme, err = this.parseConfig(configStr) + return +} + +func (this *ThemeService) GetTheme(userId, themeId string) info.Theme { + theme := info.Theme{} + db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, &theme) + return theme +} +func (this *ThemeService) GetThemeById(themeId string) info.Theme { + theme := info.Theme{} + db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, &theme) + return theme +} + +// 得到主题信息, 为了给博客用 +func (this *ThemeService) GetThemeInfo(themeId, style string) map[string]interface{} { + q := bson.M{} + if themeId == "" { + if style == "" { + style = defaultStyle + } + q["Style"] = style + q["IsDefault"] = true + } else { + q["_id"] = bson.ObjectIdHex(themeId) + } + theme := info.Theme{} + db.GetByQ(db.Themes, q, &theme) + return theme.Info +} + +// 得到用户的主题 +// 若用户没有主题, 则至少有一个默认主题 +// 第一个返回值是当前active +func (this *ThemeService) GetUserThemes(userId string) (theme info.Theme, themes []info.Theme) { + theme = info.Theme{} + themes = []info.Theme{} + +// db.ListByQ(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId)}, &themes) + + // 创建时间逆序 + query := bson.M{"UserId": bson.ObjectIdHex(userId)} + q := db.Themes.Find(query); + q.Sort("-CreatedTime").All(&themes) + if len(themes) == 0 { + userBlog := blogService.GetUserBlog(userId) + theme = this.getDefaultTheme(userBlog.Style) + } else { + var has = false + // 第一个是active的主题 + themes2 := make([]info.Theme, len(themes)) + i := 0 + for _, t := range themes { + if t.IsActive { + theme = t + } else { + has = true + themes2[i] = t + i++ + } + } + if has { + themes = themes2 + } else { + themes = nil + } + } + return +} + +// 得到默认主题供选择 +func (this *ThemeService) GetDefaultThemes() (themes []info.Theme) { + themes = []info.Theme{} + db.ListByQ(db.Themes, bson.M{"IsDefault": true}, &themes) + return +} + +// 得到模板内容 +func (this *ThemeService) GetTplContent(userId, themeId, filename string) string { + path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename + return GetFileStrContent(path) +} + +// 得到主题的绝对路径 +func (this *ThemeService) GetThemeAbsolutePath(userId, themeId string) string { + theme := info.Theme{} + db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme) + if theme.Path != "" { + return revel.BasePath + "/" + theme.Path + } + return "" +} +func (this *ThemeService) GetThemePath(userId, themeId string) string { + theme := info.Theme{} + db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme) + if theme.Path != "" { + return theme.Path + } + return "" +} +// 更新模板内容 +func (this *ThemeService) UpdateTplContent(userId, themeId, filename, content string) (ok bool, msg string) { + path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename + if strings.Contains(filename, ".html") { + // 模板 + if ok, msg = this.mustTpl(filename, content); ok { + ok = PutFileStrContent(path, content) + } + return + } else if filename == "theme.json" { + // 主题配置, 判断是否是正确的json + theme, err := this.parseConfig(content) + if err != nil { + return false, fmt.Sprintf("%v", err) + } + // 正确, 更新theme信息 + ok = db.UpdateByQMap(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, + bson.M{ + "Name": theme.Name, + "Version": theme.Version, + "Author": theme.Author, + "AuthorUrl": theme.AuthorUrl, + "Info": theme.Info, + }) + if ok { + ok = PutFileStrContent(path, content) + } + return + } + ok = PutFileStrContent(path, content) + return +} + +func (this *ThemeService) DeleteTpl(userId, themeId, filename string) (ok bool) { + path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename + ok = DeleteFile(path) + return +} + +// 判断是否有语法错误 +func (this *ThemeService) mustTpl(filename, content string) (ok bool, msg string) { + ok = true + defer func() { + if err := recover(); err != nil { + ok = false + Log(err) + msg = fmt.Sprintf("%v", err) + } + }() + template.Must(template.New(filename).Funcs(revel.TemplateFuncs).Parse(content)) + return +} + +///////// + +// 使用主题 +func (this *ThemeService) ActiveTheme(userId, themeId string) (ok bool) { + if db.Has(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}) { + // 之前的设为false + db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "IsActive": true}, "IsActive", false) + // 现在的设为true + db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true) + + // UserBlog ThemeId + db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "ThemeId", bson.ObjectIdHex(themeId)) + return true + } + return false +} + +// 删除主题 +func (this *ThemeService) DeleteTheme(userId, themeId string) (ok bool) { + return db.Delete(db.Themes,bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId), "IsActive": false}) +} + +// 公开主题, 只有管理员才有权限, 之前没公开的变成公开 +func (this *ThemeService) PublicTheme(userId, themeId string) (ok bool) { + // 是否是管理员? + userInfo := userService.GetUserInfo(userId) + if userInfo.Username == adminUsername { + theme := this.GetThemeById(themeId) + return db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(themeId)}, "IsDefault", !theme.IsDefault) + } + return false +} + + +// 导出主题 +func (this *ThemeService) ExportTheme(userId, themeId string) (ok bool, path string) { + theme := this.GetThemeById(themeId) + // 打包 + // 验证路径, 别把整个项目打包了 + Log(theme.Path) + if theme.Path == "" || + (!strings.HasPrefix(theme.Path, "public/upload") && + !strings.HasPrefix(theme.Path, "public/blog/themes")) || + strings.Contains(theme.Path, "..") { + return + } + + sourcePath := revel.BasePath + "/" + theme.Path + targetPath := revel.BasePath + "/public/upload/" + userId + "/tmp" + err := os.MkdirAll(targetPath, 0755) + if err != nil { + Log(err) + return + } + targetName := targetPath + "/" + theme.Name + ".zip" + Log(sourcePath) + Log(targetName) + ok = archive.Zip(sourcePath, targetName) + if !ok { + return + } + + return true, targetName +} +// 导入主题 +// path == /llllllll/..../public/upload/.../aa.zip, 绝对路径 +func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string) { + themeIdO := bson.NewObjectId() + themeId := themeIdO.Hex() + targetPath := this.getUserThemePath(userId, themeId) // revel.BasePath + "/public/upload/" + userId + "/themes/" + themeId + if ok, msg = archive.Unzip(path, targetPath); !ok { + DeleteFile(targetPath) + return + } + // 解压成功, 那么新建之 + // 保存到数据库中 + theme, _ := this.getThemeConfig(targetPath) + if theme.Name == "" { + ok = false + DeleteFile(targetPath) + msg = "解析错误" + return + } + theme.ThemeId = themeIdO + theme.Path = this.getUserThemePath2(userId, themeId) + theme.CreatedTime = time.Now() + theme.UpdatedTime = theme.CreatedTime + theme.UserId = bson.ObjectIdHex(userId) + + ok = db.Insert(db.Themes, theme) + if !ok { + DeleteFile(targetPath) + } + DeleteFile(path) + return +} + +// 安装主题 +// 得到该主题路径 +func (this *ThemeService) InstallTheme(userId, themeId string) (ok bool) { + theme := this.GetThemeById(themeId) + // 不是默认主题, 即不是admin用户的主题, 不能乱安装 + if !theme.IsDefault { + return false + } + + // 用户之前是否有主题? + userBlog := blogService.GetUserBlog(userId) + if userBlog.ThemeId == "" { + this.NewThemeForFirst(userBlog) + } + + // 生成新主题 + newThemeId := bson.NewObjectId() + themeId = newThemeId.Hex() + themePath := this.getUserThemePath(userId, themeId) + err := os.MkdirAll(themePath, 0755) + if err != nil { + return + } + // 复制默认主题 + sourceThemePath := revel.BasePath + "/" + theme.Path + err = CopyDir(sourceThemePath, themePath) + if err != nil { + return + } + + // 保存到数据库中 + theme, _ = this.getThemeConfig(themePath) + theme.ThemeId = newThemeId + theme.Path = this.getUserThemePath2(userId, themeId) + theme.CreatedTime = time.Now() + theme.UpdatedTime = theme.CreatedTime + theme.UserId = bson.ObjectIdHex(userId) + + ok = db.Insert(db.Themes, theme) + + return ok +} diff --git a/app/service/UpgradeService.go b/app/service/UpgradeService.go index 0f67b69..117ea0b 100644 --- a/app/service/UpgradeService.go +++ b/app/service/UpgradeService.go @@ -19,9 +19,34 @@ func (this *UpgradeService) UpgradeBlog() bool { // PublicTime, RecommendTime = UpdatedTime for _, note := range notes { - db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime}) - Log(note.NoteId.Hex()) + if note.IsBlog && note.PublicTime.Year() < 100 { + db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime}) + Log(note.NoteId.Hex()) + } } return true -} \ No newline at end of file +} + +// 11-5自定义博客升级, 将aboutMe移至pages +func (this *UpgradeService) UpgradeBetaToSelfBlog(userId string) (ok bool, msg string) { + if configService.GetGlobalStringConfig("UpgradeBetaToSelfBlog") != "" { + return false, "已升级" + } + + // 1. aboutMe -> page + userBlogs := []info.UserBlog{} + db.ListByQ(db.UserBlogs, bson.M{}, &userBlogs) + + for _, userBlog := range userBlogs { + blogService.AddOrUpdateSingle(userBlog.UserId.Hex(), "", "About Me", userBlog.AboutMe) + } + + configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToSelfBlog", "ok") + + ok = true + msg = "success" + + // 2. 默认主题, 给admin用户 + return +} diff --git a/app/service/UserService.go b/app/service/UserService.go index fd9a81d..3bce643 100644 --- a/app/service/UserService.go +++ b/app/service/UserService.go @@ -26,7 +26,7 @@ func (this *UserService) AddUser(user info.User) bool { go func() { emailService.RegisterSendActiveEmail(user, user.Email) // 发送给我 life@leanote.com - // emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}"); + emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}"); }(); } @@ -133,6 +133,57 @@ func (this *UserService) MapUserInfoAndBlogInfosByUserIds(userIds []bson.ObjectI return this.MapUserInfoByUserIds(userIds) } +// 返回info.UserAndBlog +func (this *UserService) MapUserAndBlogByUserIds(userIds []bson.ObjectId) map[string]info.UserAndBlog { + users := []info.User{} + db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users) + + userBlogs := []info.UserBlog{} + db.ListByQ(db.UserBlogs, bson.M{"_id": bson.M{"$in": userIds}}, &userBlogs) + + userBlogMap := make(map[bson.ObjectId]info.UserBlog, len(userBlogs)) + for _, user := range userBlogs { + userBlogMap[user.UserId] = user + } + + userAndBlogMap := make(map[string]info.UserAndBlog, len(users)) + + for _, user := range users { + this.setUserLogo(&user) + + userBlog, ok := userBlogMap[user.UserId] + if !ok { + continue + } + + userAndBlogMap[user.UserId.Hex()] = info.UserAndBlog{ + UserId: user.UserId, + Username: user.Username, + Email: user.Email, + Logo: user.Logo, + BlogTitle: userBlog.Title, + BlogLogo: userBlog.Logo, + BlogUrl: blogService.GetUserBlogUrl(&userBlog), + } + } + return userAndBlogMap +} + +// 得到userAndBlog公开信息 +func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog { + user := this.GetUserInfo(userId) + userBlog := blogService.GetUserBlog(userId) + return info.UserAndBlog{ + UserId: user.UserId, + Username: user.Username, + Email: user.Email, + Logo: user.Logo, + BlogTitle: userBlog.Title, + BlogLogo: userBlog.Logo, + BlogUrl: blogService.GetUserBlogUrl(&userBlog), + } +} + // 通过ids得到users, 按id的顺序组织users func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User { users := []info.User{} @@ -143,9 +194,11 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info. usersMap[user.UserId] = user } + hasAppend := map[bson.ObjectId]bool{} // 为了防止userIds有重复的 users2 := []info.User{}; for _, userId := range userIds { - if user, ok := usersMap[userId]; ok { + if user, ok := usersMap[userId]; ok && !hasAppend[userId] { + hasAppend[userId] = true users2 = append(users2, user) } } @@ -169,7 +222,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U // 更新username func (this *UserService) UpdateUsername(userId, username string) (bool, string) { if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置 - return false, "用户已存在" + return false, "usernameIsExisted" } usernameRaw := username // 原先的, 可能是同一个, 但有大小写 username = strings.ToLower(username) @@ -177,7 +230,7 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string) // 先判断是否存在 userIdO := bson.ObjectIdHex(userId) if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) { - return false, "用户已存在" + return false, "usernameIsExisted" } ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw}) @@ -195,7 +248,7 @@ func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) { func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) { userInfo := this.GetUserInfo(userId) if userInfo.Pwd != Md5(oldPwd) { - return false, "旧密码错误" + return false, "oldPasswordError" } ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd)) return ok, "" @@ -207,6 +260,21 @@ func (this *UserService) UpdateTheme(userId, theme string) (bool) { return ok } +// 帐户类型设置 +func (this *UserService) UpdateAccount(userId, accountType string, accountStartTime, accountEndTime time.Time, + maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) bool { + return db.UpdateByQI(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, info.UserAccount{ + AccountType: accountType, + AccountStartTime: accountStartTime, + AccountEndTime: accountEndTime, + MaxImageNum: maxImageNum, + MaxImageSize: maxImageSize, + MaxAttachNum: maxAttachNum, + MaxAttachSize: maxAttachSize, + MaxPerAttachSize: maxPerAttachSize, + }) +} + //--------------- // 修改email @@ -261,6 +329,13 @@ func (this *UserService) UpdateEmail(token string) (ok bool, msg, email string) //--------- // 第三方添加账号 func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) { + // 判断该用户是否已有了帐户 + userInfo := this.GetUserInfo(userId) + if userInfo.Email != "" { + msg = "你已有帐户" + return + } + // 判断email是否存在 if this.IsExistsUser(email) { msg = "该用户已存在" diff --git a/app/service/init.go b/app/service/init.go index 01fdbe9..e386a7c 100644 --- a/app/service/init.go +++ b/app/service/init.go @@ -28,8 +28,10 @@ var emailService, EmailS *EmailService var AuthS *AuthService var UpgradeS *UpgradeService var SessionS, sessionService *SessionService +var ThemeS, themeService *ThemeService var siteUrl string +var adminUsername = "admin" // onAppStart调用 func InitService() { @@ -53,6 +55,7 @@ func InitService() { EmailS = NewEmailService() UpgradeS = &UpgradeService{} SessionS = &SessionService{} + ThemeS = &ThemeService{} notebookService = NotebookS noteService = NoteS @@ -70,7 +73,7 @@ func InitService() { configService = ConfigS emailService = EmailS sessionService = SessionS + themeService = ThemeS - // siteUrl, _ = revel.Config.String("site.url") } \ No newline at end of file diff --git a/app/views/member/blog/add_single.html b/app/views/member/blog/add_single.html new file mode 100644 index 0000000..700fda8 --- /dev/null +++ b/app/views/member/blog/add_single.html @@ -0,0 +1,101 @@ +{{template "member/top.html" .}} +

+{{if .page}} +修改页面 +{{else}} +添加页面 +{{end}} +

+ + +
+
+
+
+
+ + +
+ + +
+ +
+ +
+ +
+
+
+ +
+
+
+
+ +
+{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} diff --git a/app/views/member/blog/base.html b/app/views/member/blog/base.html new file mode 100644 index 0000000..67cf73f --- /dev/null +++ b/app/views/member/blog/base.html @@ -0,0 +1,115 @@ +{{template "member/top.html" .}} +

{{msg . "baseInfoSet"}}

+ +
+
+
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ + + +
+
+ +
+ +
+ +
+
+ +
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+ +
+{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} diff --git a/app/views/member/blog/cate.html b/app/views/member/blog/cate.html new file mode 100644 index 0000000..314f205 --- /dev/null +++ b/app/views/member/blog/cate.html @@ -0,0 +1,47 @@ +{{template "member/top.html" .}} +

(笔记本)分类

+ +
+
+
+
+ 分类是公开为博客的笔记本 +
+ 拖动可排序 +
    + {{range .notebooks}} +
  • + + {{.Title}} +
  • + {{end}} +
+
+
+ +
+
+
+ +
+{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} diff --git a/app/views/member/blog/comment.html b/app/views/member/blog/comment.html new file mode 100644 index 0000000..8a1c071 --- /dev/null +++ b/app/views/member/blog/comment.html @@ -0,0 +1,92 @@ +{{template "member/top.html" .}} +

{{msg . "commentSet"}}

+ +
+
+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + +
+ +
+ {{msg . "disqusHelp"}} + {{msg . "needHelp"}} +
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+{{template "member/footer.html" .}} + + +{{template "member/end.html" .}} diff --git a/app/views/member/blog/paging.html b/app/views/member/blog/paging.html new file mode 100644 index 0000000..782202e --- /dev/null +++ b/app/views/member/blog/paging.html @@ -0,0 +1,76 @@ +{{template "member/top.html" .}} +

分页与排序设置

+ +
+
+
+
+
+ + +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+ + +
+ +
+
+ +
+
+
+
+ +
+{{template "member/footer.html" .}} + + +{{template "member/end.html" .}} diff --git a/app/views/member/blog/single.html b/app/views/member/blog/single.html new file mode 100644 index 0000000..24fb6e8 --- /dev/null +++ b/app/views/member/blog/single.html @@ -0,0 +1,70 @@ +{{template "member/top.html" .}} +

页面

+ +
+
+
+
+

+ 您可以添加多个单页面 + 添加页面 +

+
    + {{range .singles}} +
  • + + + + + +
    + {{.Title}} +
    +
  • + {{end}} +
+
+ {{if .singles}} +
+ +
+ {{end}} +
+
+ +
+{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} diff --git a/app/views/member/blog/theme.html b/app/views/member/blog/theme.html new file mode 100644 index 0000000..45cd322 --- /dev/null +++ b/app/views/member/blog/theme.html @@ -0,0 +1,221 @@ +{{template "member/top.html" .}} +
+

+ {{msg . "themeSet"}} + ({{msg . "needHelp"}}) +

+
+
+
+
+
+ +

+ 当前主题: +

+ + +
+

+ 我的其它主题: +

+ + +
+

+ leanote主题市场: +

+ +
+
+
+ +
+{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} \ No newline at end of file diff --git a/app/views/member/blog/update_theme.html b/app/views/member/blog/update_theme.html new file mode 100644 index 0000000..9495550 --- /dev/null +++ b/app/views/member/blog/update_theme.html @@ -0,0 +1,334 @@ +{{template "member/top.html" .}} +
+

+ {{if .isNew}} + 新建主题 + {{else}} + 编辑主题 + - + {{.theme.Name}} + {{end}} + 预览 +

+
+ + +
+
+
+
+ 模板, 样式, 脚本: +
+
+ +
+ {{range .myTpls}} + + + {{.}} + + + {{end}} + +
+
+ +
+
+
+
+
+ 当前文件: header.html + +
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ 图片: images/ +
+
+
    +
+
+
+ + +
+
+
+
+ +{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} diff --git a/app/views/member/end.html b/app/views/member/end.html new file mode 100644 index 0000000..a57a3db --- /dev/null +++ b/app/views/member/end.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/views/member/footer.html b/app/views/member/footer.html new file mode 100644 index 0000000..ab40505 --- /dev/null +++ b/app/views/member/footer.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/views/member/index.html b/app/views/member/index.html new file mode 100644 index 0000000..a877e35 --- /dev/null +++ b/app/views/member/index.html @@ -0,0 +1,81 @@ +{{template "member/top.html" .}} +

{{.userInfo.Username}}, 欢迎来到leanote

+ +
+ +
+ + +
+

+ Leanote 动态 +

+ +
+ + + +{{template "member/footer.html" .}} + +{{template "member/end.html" .}} \ No newline at end of file diff --git a/app/views/member/nav.html b/app/views/member/nav.html new file mode 100644 index 0000000..5515301 --- /dev/null +++ b/app/views/member/nav.html @@ -0,0 +1,137 @@ + \ No newline at end of file diff --git a/app/views/member/top.html b/app/views/member/top.html new file mode 100644 index 0000000..3c51a8d --- /dev/null +++ b/app/views/member/top.html @@ -0,0 +1,118 @@ + + + + + + {{.title}} + + + + + + + + + +
+ +
+
+ + + +
+
+
+ + + \ No newline at end of file diff --git a/app/views/member/user/add_account.html b/app/views/member/user/add_account.html new file mode 100644 index 0000000..8c3f8c3 --- /dev/null +++ b/app/views/member/user/add_account.html @@ -0,0 +1,80 @@ +{{template "member/top.html" .}} +

用户名设置

+ +
+ +
+
+
+
+ + {{msg . "thirdCreateAcountTips"}} +
+ + +
+
+ + + {{msg . "passwordTips"}} +
+
+ + +
+
+
+ +
+
+
+
+ +
+ +{{template "member/footer.html" .}} + + +{{template "member/end.html" .}} diff --git a/app/views/member/user/avatar.html b/app/views/member/user/avatar.html new file mode 100644 index 0000000..f3fa94c --- /dev/null +++ b/app/views/member/user/avatar.html @@ -0,0 +1,53 @@ +{{template "member/top.html" .}} + +

头像设置

+ +
+ +
+
+
+
+
+
+
+ +
+ + Choose Image + + +
+
+
+
+
+
+
+
+ +
+ +{{template "member/footer.html" .}} + + + +{{template "member/end.html" .}} diff --git a/app/views/member/user/email.html b/app/views/member/user/email.html new file mode 100644 index 0000000..a09c139 --- /dev/null +++ b/app/views/member/user/email.html @@ -0,0 +1,117 @@ +{{template "member/top.html" .}} +

邮箱设置

+ +
+ +
+
+
+
+ {{msg . "currentEmail" .userInfo.Email}} +
+ {{if .userInfo.Verified}} + {{msg . "verified"}} + {{else}} + {{msg . "unVerified"}} + {{msg . "verifiedNow"}} + {{msg . "or"}} + {{msg . "resendVerifiedEmail"}} + {{end}} + + +
+ + + {{msg . "updateEmailTips"}} +
+
+
+ +
+
+
+
+ + + + +
+ +{{template "member/footer.html" .}} + + +{{template "member/end.html" .}} diff --git a/app/views/member/user/password.html b/app/views/member/user/password.html new file mode 100644 index 0000000..f055565 --- /dev/null +++ b/app/views/member/user/password.html @@ -0,0 +1,74 @@ +{{template "member/top.html" .}} +

用户名设置

+ +
+ +
+
+
+
+ +
+ + +
+
+ + + {{msg . "passwordTips"}} +
+
+ + +
+
+
+ +
+
+
+
+ +
+ +{{template "member/footer.html" .}} + + +{{template "member/end.html" .}} diff --git a/app/views/member/user/username.html b/app/views/member/user/username.html new file mode 100644 index 0000000..a58f5aa --- /dev/null +++ b/app/views/member/user/username.html @@ -0,0 +1,57 @@ +{{template "member/top.html" .}} +

用户名设置

+ +
+ +
+
+
+
+ +
+ + + {{msg . "setUsernameTips" .userInfo.Email}} +
+
+
+ +
+
+
+
+ +
+ +{{template "member/footer.html" .}} + + +{{template "member/end.html" .}} diff --git a/app/views/member/个人中心.md b/app/views/member/个人中心.md new file mode 100644 index 0000000..e69de29 diff --git a/app/views/note/note-dev.html b/app/views/note/note-dev.html index 060c698..dc5fc22 100644 --- a/app/views/note/note-dev.html +++ b/app/views/note/note-dev.html @@ -136,30 +136,28 @@ function log(o) { diff --git a/app/views/admin/setting/upload.html b/app/views/admin/setting/upload.html new file mode 100644 index 0000000..ebc7a5a --- /dev/null +++ b/app/views/admin/setting/upload.html @@ -0,0 +1,65 @@ +{{template "admin/top.html" .}} +

Upload File Size Limit

+ +
+ +
+
+
+
+
+ + + MB. Default is unlimit; +
+
+ + + MB. Default is unlimit; +
+
+ + + MB. Default is unlimit; +
+
+ + + MB. Default is unlimit; +
+
+ +
+ +
+
+
+
+ +
+ +{{template "admin/footer.html" .}} + + + +{{template "admin/end.html" .}} \ No newline at end of file diff --git a/app/views/member/user/avatar.html b/app/views/member/user/avatar.html index f3fa94c..0250c5d 100644 --- a/app/views/member/user/avatar.html +++ b/app/views/member/user/avatar.html @@ -31,7 +31,8 @@ {{template "member/footer.html" .}} diff --git a/public/js/app/attachment_upload.js b/public/js/app/attachment_upload.js index 2998f3a..8b25956 100644 --- a/public/js/app/attachment_upload.js +++ b/public/js/app/attachment_upload.js @@ -83,10 +83,11 @@ define('attachment_upload', ['jquery.ui.widget', 'fileupload'], function(){ // 检查文件大小 var size = data.files[0].size; - if(typeof size == 'number' && size > 1024 * 1024 * 5) { + var maxFileSize = +GlobalConfigs["uploadAttachSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { tpl.find("img").remove(); tpl.removeClass("alert-info").addClass("alert-danger"); - tpl.append(" Warning: File size is bigger than 5M"); + tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); setTimeout((function(tpl) { return function() { tpl.remove(); @@ -156,10 +157,11 @@ define('attachment_upload', ['jquery.ui.widget', 'fileupload'], function(){ // 检查文件大小 var size = data.files[0].size; - if(typeof size == 'number' && size > 1024 * 1024) { + var maxFileSize = +GlobalConfigs["uploadAvatarSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { tpl.find("img").remove(); tpl.removeClass("alert-info").addClass("alert-danger"); - tpl.append(" Warning: File size is bigger than 1M"); + tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); setTimeout((function(tpl) { return function() { tpl.remove(); diff --git a/public/tinymce/plugins/leaui_image/public/css/style.css b/public/tinymce/plugins/leaui_image/public/css/style.css index c5ade2f..f1e9dee 100644 --- a/public/tinymce/plugins/leaui_image/public/css/style.css +++ b/public/tinymce/plugins/leaui_image/public/css/style.css @@ -34,7 +34,7 @@ right: 10px; width: 300px; max-height: 240px; - overflow: scroll; + overflow: auto; z-index: 3; } /**/ diff --git a/public/tinymce/plugins/leaui_image/public/js/main.js b/public/tinymce/plugins/leaui_image/public/js/main.js index 946eb50..670840a 100644 --- a/public/tinymce/plugins/leaui_image/public/js/main.js +++ b/public/tinymce/plugins/leaui_image/public/js/main.js @@ -718,7 +718,7 @@ var o = { $('#upload').fileupload({ dataType: 'json', acceptFileTypes: /(\.|\/)(gif|jpg|jpeg|png|jpe)$/i, - maxFileSize: 210000, + // maxFileSize: 210000, // This element will accept file drag/drop uploading dropZone: $('#drop'), @@ -734,9 +734,17 @@ var o = { // This function is called when a file is added to the queue; // either via the browse button, or via drag/drop: add: function(e, data) { - + // 文件大小限制 + var size = data.files[0].size; + var maxFileSize = +parent.GlobalConfigs["uploadImageSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { + var tpl = $('
  • '); + tpl.find('div').append('Warning: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] is bigger than ' + maxFileSize + 'M '); + tpl.appendTo(ul); + return; + } + var tpl = $('
  • '); - // Append the file name and file size tpl.find('div').append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); @@ -763,6 +771,11 @@ var o = { var tpl = $('
  • '); tpl.find('div').append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); data.context.append(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); } $("#upload-msg").scrollTop(1000); }, From e5f7c66d1ec6b1badc3b52276c59e33c1744e71e Mon Sep 17 00:00:00 2001 From: life Date: Sun, 9 Nov 2014 22:14:08 +0800 Subject: [PATCH 04/12] test --- app/controllers/BaseController.go | 3 + app/controllers/init.go | 1 + app/views/share/note_share_user_infos.html | 84 - public/js/app/attachment_upload.js | 212 --- public/js/app/blog/common.js | 207 --- public/js/app/blog/view.js | 509 ------ public/js/app/import_theme.js | 114 -- public/js/app/note-min.js | 1 - public/js/app/note.js | 1674 -------------------- public/js/app/notebook-min.js | 1 - public/js/app/notebook.js | 888 ----------- public/js/app/page-min.js | 1 - public/js/app/page.js | 795 ---------- public/js/app/share-min.js | 1 - public/js/app/share.js | 583 ------- public/js/app/tag-min.js | 1 - public/js/app/tag.js | 300 ---- 17 files changed, 4 insertions(+), 5371 deletions(-) delete mode 100644 app/views/share/note_share_user_infos.html delete mode 100644 public/js/app/attachment_upload.js delete mode 100644 public/js/app/blog/common.js delete mode 100644 public/js/app/blog/view.js delete mode 100644 public/js/app/import_theme.js delete mode 100644 public/js/app/note-min.js delete mode 100644 public/js/app/note.js delete mode 100644 public/js/app/notebook-min.js delete mode 100644 public/js/app/notebook.js delete mode 100644 public/js/app/page-min.js delete mode 100644 public/js/app/page.js delete mode 100644 public/js/app/share-min.js delete mode 100644 public/js/app/share.js delete mode 100644 public/js/app/tag-min.js delete mode 100644 public/js/app/tag.js diff --git a/app/controllers/BaseController.go b/app/controllers/BaseController.go index d86a99e..8ed0de9 100644 --- a/app/controllers/BaseController.go +++ b/app/controllers/BaseController.go @@ -196,6 +196,9 @@ func (c BaseController) SetLocale() string { func (c BaseController) SetUserInfo() { userInfo := c.GetUserInfo() c.RenderArgs["userInfo"] = userInfo + if(userInfo.Username == adminUsername) { + c.RenderArgs["isAdmin"] = true + } } // life diff --git a/app/controllers/init.go b/app/controllers/init.go index 186323e..2af847f 100644 --- a/app/controllers/init.go +++ b/app/controllers/init.go @@ -33,6 +33,7 @@ var themeService *service.ThemeService var pageSize = 1000 var defaultSortField = "UpdatedTime" var leanoteUserId = "admin" // 不能更改 +var adminUsername = "admin" var siteUrl = "http://leanote.com" // 拦截器 diff --git a/app/views/share/note_share_user_infos.html b/app/views/share/note_share_user_infos.html deleted file mode 100644 index 68bc9fe..0000000 --- a/app/views/share/note_share_user_infos.html +++ /dev/null @@ -1,84 +0,0 @@ - - \ No newline at end of file diff --git a/public/js/app/attachment_upload.js b/public/js/app/attachment_upload.js deleted file mode 100644 index 8b25956..0000000 --- a/public/js/app/attachment_upload.js +++ /dev/null @@ -1,212 +0,0 @@ -// upload attachment -// 依赖note -var urlPrefix = UrlPrefix; -define('attachment_upload', ['jquery.ui.widget', 'fileupload'], function(){ - // Helper function that formats the file sizes - function formatFileSize(bytes) { - if (typeof bytes !== 'number') { - return ''; - } - if (bytes >= 1000000000) { - return (bytes / 1000000000).toFixed(2) + ' GB'; - } - if (bytes >= 1000000) { - return (bytes / 1000000).toFixed(2) + ' MB'; - } - return (bytes / 1000).toFixed(2) + ' KB'; - } - - function setDropStyle(dropzoneId, formId) { - // drag css - var dropZone = $(dropzoneId); - $(formId).bind('dragover', function (e) { - e.preventDefault(); - var timeout = window.dropZoneTimeoutAttach; - if(timeout) { - clearTimeout(timeout); - } - - var found = false, - node = e.target; - do { - if (node === dropZone[0]) { - found = true; - break; - } - node = node.parentNode; - } while (node != null); - if (found) { - dropZone.addClass('hover'); - } else { - dropZone.removeClass('hover'); - } - window.dropZoneTimeoutAttach = setTimeout(function () { - window.dropZoneTimeoutAttach = null; - dropZone.removeClass('in hover'); - }, 100); - }); - } - - setDropStyle("#dropAttach", "#uploadAttach"); - setDropStyle("#dropAvatar", "#uploadAvatar"); - - var initUploader = function() { - $('.dropzone .btn-choose-file').click(function() { - $(this).parent().find('input').click(); - }); - - var $msg = $('#attachUploadMsg'); - // Initialize the jQuery File Upload plugin - $('#uploadAttach').fileupload({ - dataType: 'json', - // This element will accept file drag/drop uploading - dropZone: $('#dropAttach'), - formData: function(form) { - return [{name: 'noteId', value: Note.curNoteId}] // 传递笔记本过去 - }, - // This function is called when a file is added to the queue; - // either via the browse button, or via drag/drop: - add: function(e, data) { - var note = Note.getCurNote(); - if(!note || note.IsNew) { - alert("This note hasn't saved, please save it firstly!") - return; - } - var tpl = $(''); - - // Append the file name and file size - tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); - - // Add the HTML to the UL element - $msg.html(tpl); - data.context = $msg; - - // 检查文件大小 - var size = data.files[0].size; - var maxFileSize = +GlobalConfigs["uploadAttachSize"] || 100; - if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { - tpl.find("img").remove(); - tpl.removeClass("alert-info").addClass("alert-danger"); - tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - return; - } - - // Automatically upload the file once it is added to the queue - var jqXHR; - setTimeout(function() { - jqXHR = data.submit(); - }, 10); - }, - /* - progress: function (e, data) { - }, - */ - done: function(e, data) { - if (data.result.Ok == true) { - data.context.html(""); - Attach.addAttach(data.result.Item); - } else { - var re = data.result; - data.context.html(""); - var tpl = $(''); - tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); - data.context.html(tpl); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - } - $("#uploadAttachMsg").scrollTop(1000); - }, - fail: function(e, data) { - data.context.html(""); - var tpl = $(''); - tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); - data.context.html(tpl); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - - $("#uploadAttachMsg").scrollTop(1000); - } - }); - - //------------------- - - var $msg2 = $('#avatarUploadMsg'); - $('#uploadAvatar').fileupload({ - dataType: 'json', - dropZone: $('#dropAvatar'), - add: function(e, data) { - var tpl = $(''); - - // Append the file name and file size - tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); - - // Add the HTML to the UL element - $msg2.html(tpl); - data.context = $msg2; - - // 检查文件大小 - var size = data.files[0].size; - var maxFileSize = +GlobalConfigs["uploadAvatarSize"] || 100; - if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { - tpl.find("img").remove(); - tpl.removeClass("alert-info").addClass("alert-danger"); - tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - return; - } - - // Automatically upload the file once it is added to the queue - var jqXHR; - setTimeout(function() { - jqXHR = data.submit(); - }, 10); - }, - done: function(e, data) { - if (data.result.Ok == true) { - data.context.html(""); - var re = data.result; - $("#avatar").attr("src", UrlPrefix + "/" + re.Id); - } else { - var re = data.result; - data.context.html(""); - var tpl = $(''); - tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); - data.context.html(tpl); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - } - }, - fail: function(e, data) { - data.context.html(""); - var tpl = $(''); - tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); - data.context.html(tpl); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - } - }); - } - - initUploader(); -}); \ No newline at end of file diff --git a/public/js/app/blog/common.js b/public/js/app/blog/common.js deleted file mode 100644 index be4e505..0000000 --- a/public/js/app/blog/common.js +++ /dev/null @@ -1,207 +0,0 @@ -// 返回是否是re.Ok == true -function reIsOk(re) { - return re && typeof re == "object" && re.Ok; -} -function showAlert(id, msg, type, id2Focus) { - $(id).html(msg).removeClass("alert-danger").removeClass("alert-success").removeClass("alert-warning").addClass("alert-" + type).show(); - if(id2Focus) { - $(id2Focus).focus(); - } -} -function hideAlert(id, timeout) { - if(timeout) { - setTimeout(function() { - $(id).hide(); - }, timeout); - } else { - $(id).hide(); - } -} -function ajaxGet(url, param, func) { - $.get(url, param, func); -} -function ajaxPost(url, param, func) { - $.post(url, param, func); -} -function goLogin(){ - var loginUrl = urlPrefix + '/login?from=' + encodeURI(location.href); - location.href = loginUrl; -} -function goRegister() { - var registerUrl = urlPrefix + '/register?from=' + encodeURI(location.href); - location.href = registerUrl; -} -function needLogin() { - if(typeof visitUserInfo == "undefined" || !visitUserInfo || !visitUserInfo.UserId) { - // 弹框之 - var loginUrl = urlPrefix + '/login?from=' + encodeURI(location.href); - var registerUrl = urlPrefix + '/register?from=' + encodeURI(location.href); - var modal = BootstrapDialog.show({ - title: "你还未登录", - message: '
    立即登录, 发表评论.
    没有帐号? 立即注册', - nl2br: false - }); - return true; - } - return false; -} -function scrollToTarget(t, fixed) { - if(!fixed) { - fixed = 0; - } - var $t = $(t) - var targetOffset = $t.offset().top + fixed; - $('html,body').animate({scrollTop: targetOffset}, 300); -} - -var windowParam = 'width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no'; -function getShareUrl(noteId) { - return viewUrl + "/" + noteId; -} -function getShareTitle(title) { - return encodeURI(title + " (来自leanote.com)"); -} -function shareSinaWeibo(noteId, title, pic) { - var url = "http://service.weibo.com/share/share.php?title=" + getShareTitle(title) + "&url=" + getShareUrl(noteId); - window.open(url, 'Share', windowParam); -} -function shareTencentWeibo(noteId, title, pic) { - var _appkey = '801542571'; - var url = "http://share.v.t.qq.com/index.php?c=share&a=index&appkey=" + _appkey +"&title=" + getShareTitle(title) + "&url=" + getShareUrl(noteId) +"&pic=" + pic; - window.open(url, 'Share', windowParam); -} -function shareQQ(noteId, title, pic) { - var url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + getShareUrl(noteId) + '&title=' + title + '&pics=' + pic; - window.open(url, 'Share', windowParam); -} -function shareRenRen(noteId, title, pic) { - var url = 'http://widget.renren.com/dialog/share?resourceUrl=' + getShareUrl(noteId) + '&srcUrl=' + getShareUrl(noteId) + '&title=' + getShareTitle(title) + '&pic=' + pic; - window.open(url, 'Share', windowParam); -} - -// https://twitter.com/intent/tweet?text=&pic= -function shareTwitter(noteId, title, pic) { - var url = 'https://twitter.com/intent/tweet?text=' + getShareTitle(title) + '&pic=' + pic; - window.open(url, 'Share', windowParam); -} -// http://www.facebook.com/sharer.php?u=&t=” -function shareFacebook(noteId, title, pic) { - var url = ' http://www.facebook.com/sharer.php?t=' + getShareTitle(title) + '&pic=' + pic; - window.open(url, 'Share', windowParam); -} - -//JavaScript函数: -var minute = 1000 * 60; -var hour = minute * 60; -var day = hour * 24; -var halfamonth = day * 15; -var month = day * 30; -// 2014-01-06T18:29:48.802+08:00 - -function goNowToDatetime(goNow) { - if(!goNow) { - return ""; - } - return goNow.substr(0, 10) + " " + goNow.substr(11, 8); -} -function getDateDiff(dateTimeStamp){ - var now = new Date().getTime(); - var diffValue = now - dateTimeStamp; - if(diffValue < 0){ - return ""; - } - var monthC =diffValue/month; - var weekC =diffValue/(7*day); - var dayC =diffValue/day; - var hourC =diffValue/hour; - var minC =diffValue/minute; - if(monthC>=1){ - result=parseInt(monthC) + getMsg("monthsAgo"); - } - else if(weekC>=1){ - result=parseInt(weekC) + getMsg("weeksAgo"); - } - else if(dayC>=1){ - result=parseInt(dayC) + getMsg("daysAgo"); - } - else if(hourC>=1){ - result=parseInt(hourC) + getMsg("hoursAgo"); - } - else if(minC>=1){ - result=parseInt(minC) + getMsg("minutesAgo"); - }else { - result=getMsg("justNow"); - } - return result; -} - -function weixin() { - var local=window.location.href; - var title = $.trim($(".title").text()); - var desc = $.trim($("#desc").text()); - var imgUrl = $("#content img").eq(0).attr('src'); - window.shareData = { - "imgUrl": imgUrl, - "timeLineLink":local, - "sendFriendLink": local, - "weiboLink":local, - "tTitle": title, - "tContent": desc, - "fTitle": title, - "fContent": desc, - "wContent": desc - }; - document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() { - // 发送给好友 - WeixinJSBridge.on('menu:share:appmessage', function (argv) { - WeixinJSBridge.invoke('sendAppMessage', { - "img_url": window.shareData.imgUrl, - "img_width": "200", - "link": window.shareData.sendFriendLink, - "desc": window.shareData.fContent, - "title": window.shareData.fTitle - }, function (res) { - hs_guide('none'); - _report('send_msg', res.err_msg); - }) - }); - - // 分享到朋友圈 - WeixinJSBridge.on('menu:share:timeline', function (argv) { - WeixinJSBridge.invoke('shareTimeline', { - "img_url": window.shareData.imgUrl, - "img_width": "200", - "link": window.shareData.timeLineLink, - "desc": window.shareData.tContent, - "title": window.shareData.tTitle - }, function (res) { - hs_guide('none'); - _report('timeline', res.err_msg); - }); - }); - - // 分享到微博 - WeixinJSBridge.on('menu:share:weibo', function (argv) { - WeixinJSBridge.invoke('shareWeibo', { - "content": window.shareData.wContent, - "url": window.shareData.weiboLink, - }, function (res) { - hs_guide('none'); - _report('weibo', res.err_msg); - }); - }); - }, false); -} - -var LEA = {isMobile: false}; -function isMobile() { - var u = navigator.userAgent; - LEA.isMobile = false; - LEA.isMobile = /Mobile|Android|iPhone/i.test(u); - if(!LEA.isMobile && $(document).width() <= 600){ - LEA.isMobile = true - } -} -$(function() { - isMobile(); -}); \ No newline at end of file diff --git a/public/js/app/blog/view.js b/public/js/app/blog/view.js deleted file mode 100644 index 8bb7b09..0000000 --- a/public/js/app/blog/view.js +++ /dev/null @@ -1,509 +0,0 @@ -function scrollTo(self, tagName, text) { - var iframe = $("#content"); - var target = iframe.find(tagName + ":contains(" + text + ")"); - - // 找到是第几个 - // 在nav是第几个 - var navs = $('#blogNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]'); - var len = navs.size(); - for(var i = 0; i < len; ++i) { - if(navs[i] == self) { - break; - } - } - - if (target.size() >= i+1) { - target = target.eq(i); - // 之前插入, 防止多行定位不准 - var top = target.offset().top; - if(LEA.isMobile) { - top -= 50; - } - var nowTop = $(document).scrollTop(); - // 用$("body").scrllTop(10)没反应 firefox下 - $('html,body').animate({scrollTop: top}, 200); - return; - } -} -function genNav() { - var $con = $("#content"); - var html = $con.html(); - // 构造一棵树 - // {"h1-title":{h2-title:{}}} - var tree = [];//[{title: "xx", children:[{}]}, {title:"xx2"}]; - var hs = $con.find("h1,h2,h3,h4,h5,h6").toArray(); - var titles = '
      '; - for(var i = 0; i < hs.length; ++i) { - var text = $(hs[i]).text(); - var tagName = hs[i].tagName.toLowerCase(); - // scrollTo在page.js中定义 - titles += ''; - } - titles += "
    "; - $("#blogNavContent").html(titles); - if(!hs.length) { - $("#blogNavContent").html(getMsg("none")); - return false; - } - return true; -} - -function initNav() { - var hasNav = genNav(); - if(!hasNav) { - return; - } - - var $title = $(".title"); - var titlePos = $title.offset(); - var top = titlePos.top + 10;// - $title.height(); - // 手机下不要与标题在同一高度 - if(LEA.isMobile){ - top += 30; - } - if(top < 0) { - top = 10; - } - - var left = $title.width() + titlePos.left - 100; - $("#blogNav").css("top", top).css("left", left); - $("#blogNav").show(); - - $("#blogNavNav").click(function() { - var $o = $("#blogNavContent"); - if($o.is(":hidden")) { - $o.show(); - } else { - $o.hide(); - } - }); - - var $d = $(document); - function reNav() { - var vtop = $d.scrollTop(); - if(vtop <= top) { - $("#blogNav").css("top", top-vtop); - } else { - // 差距很磊了 - if(LEA.isMobile) { - $("#blogNav").css("top", 50); - } else { - $("#blogNav").css("top", 10); - } - } - } - reNav(); - $(window).scroll(reNav); -} - -var C = { - info: null, - noteId: noteId, - preLikeNum: preLikeNum, - commentNum: commentNum, - likeBtnO: $("#likeBtn"), - likeNumO: $("#likeNum"), - tLikersO: $("#tLikers"), - likersO: $("#likers"), - tCommentsO: $("#tComments"), - commentsO: $("#comments"), - - commentBtnO: $("#commentBtn"), - - commentsLoadingO: $(".comments-loading"), - commentsMoreO: $(".comments-more"), - - commentBoxO: $(".comment-box"), - init: function() { - var self = this; - if(UserBlogInfo.CanComment && UserBlogInfo.CommentType != "disqus") { - self.initLikeAndComments(); - } else { - self.initLike(); - } - self.initEvent(); - self.incReadNum(); - }, - incReadNum: function() { - var self = this; - if(!$.cookie(self.noteId)) { - $.cookie(self.noteId, 1); - ajaxGet(staticUrl + "/blog/incReadNum", {noteId: self.noteId}); - } - }, - initLike: function() { - var self = this; - ajaxGet(staticUrl + "/blog/getLike", {noteId: self.noteId}, function(ret) { - self.info = ret; - self.toggleLikeBtnActive(); - self.renderLikers(); - }); - }, - initLikeAndComments: function() { - var self = this; - ajaxGet(staticUrl + "/blog/getLikeAndComments", {noteId: self.noteId}, function(ret) { - self.info = ret; - self.toggleLikeBtnActive(); - self.renderLikers(); - // 是否需要renderComments? - self.info.commentUserInfo = self.info.commentUserInfo || {}; - // 为了防止第一条评论找不到用户信息情况 - if(visitUserInfo.UserId) { - self.info.commentUserInfo[visitUserInfo.UserId] = visitUserInfo; - } - self.renderComments(); - - self.commentBoxO.removeClass("hide"); - self.commentsLoadingO.addClass("hide"); - if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) { - self.commentsMoreO.removeClass("hide"); - self.initMoreComments(); - } - }); - }, - initMoreComments: function() { - var self = this; - self.commentsMoreO.find("a").click(function(){ - if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) { - self.commentsMoreO.addClass("hide"); - self.commentsLoadingO.removeClass("hide"); - ajaxGet(staticUrl + "/blog/listComments", {noteId: self.noteId, page: self.info.pageInfo.CurPage+1}, function(ret) { - var pageInfo = ret.pageInfo; - var comments = ret.comments; - var commentUserInfo = ret.commentUserInfo; - - $.extend(self.info.commentUserInfo, commentUserInfo); - - // 渲染之 - for(var i in comments) { - var comment = comments[i]; - comment = self.parseComment(comment); - } - var html = self.tCommentsO.render({comments: comments, visitUserInfo: visitUserInfo}); - self.commentsO.append(html); - - self.info.pageInfo = pageInfo; - - if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) { - self.commentsMoreO.removeClass("hide"); - } else { - self.commentsMoreO.addClass("hide"); - } - - self.commentsLoadingO.addClass("hide"); - }); - } - }); - }, - addCommentRender: function(comment){ - var self = this; - comment = self.parseComment(comment); - var html = self.tCommentsO.render({blogUrl: blogUrl, comments: [comment], visitUserInfo: visitUserInfo}); - self.commentsO.prepend(html); - var li = self.commentsO.find("li").eq(0); - li.hide(); - li.show(500); - li.addClass("item-highlight"); - setTimeout(function() { - li.removeClass("item-highlight"); - }, 2000); - }, - parseComment: function(comment) { - var self = this; - var authorUserId = UserInfo.UserId; - commentUserInfo = self.info.commentUserInfo; - comment.UserInfo = commentUserInfo[comment.UserId]; - // 是作者自己 - if(visitUserInfo.UserId == UserInfo.UserId) { - comment.IsMyNote = true; - } - if(comment.UserId == authorUserId) { - comment.IsAuthorComment = true; - } - if(comment.UserId == visitUserInfo.UserId) { - comment.IsMyComment = true; - } - // 不是回复自己 - if(comment.ToUserId && comment.ToUserId != comment.UserId) { - comment.ToUserInfo = commentUserInfo[comment.ToUserId]; - if(comment.ToUserInfo.UserId == UserInfo.UserId) { - comment.ToUserIsAuthor = true; - } - } - comment.PublishDate = getDateDiff(Date.parse(goNowToDatetime(comment.CreatedTime))); - return comment; - }, - // 渲染评论 - renderComments: function() { - var self = this; - var comments = self.info.comments || []; - if(comments.length == 0) { - return; - } - - // 整理数据 - // 回复谁, 是否是作者? - // 回复日期, 几天前, 刚刚 - for(var i in comments) { - var comment = comments[i]; - comment = self.parseComment(comment); - } - var html = self.tCommentsO.render({blogUrl: blogUrl, comments: comments, visitUserInfo: visitUserInfo}); - self.commentsO.html(html); - }, - - // 重新渲染likers - reRenderLikers: function(addMe) { - var self = this; - var likedUsers = self.info.likedUsers || []; - for(var i = 0; i < likedUsers.length; ++i) { - var user = likedUsers[i]; - if(user.UserId == visitUserInfo.UserId) { - likedUsers.splice(i, 1); - break; - } - } - if(addMe) { - likedUsers = [visitUserInfo].concat(likedUsers); - self.info.likedUsers = likedUsers; - } - self.renderLikers(); - }, - renderLikers: function() { - var self = this; - var users = self.info.likedUsers || []; - var html = self.tLikersO.render({blogUrl: blogUrl, users: users}); - self.likersO.html(html); - }, - toggleLikeBtnActive: function() { - var self = this; - if(self.info.isILikeIt) { - self.likeBtnO.addClass("active"); - } else { - self.likeBtnO.removeClass("active"); - } - }, - commentNumO: $("#commentNum"), - bindCommentNum: function(fix) { - var self = this; - self.commentNum += fix; - self.commentNumO.text(self.commentNum); - }, - initEvent: function() { - var self = this; - - // like or not - self.likeBtnO.click(function() { - if(!visitUserInfo.UserId) { - needLogin(); - return; - } - ajaxPost(staticUrl + "/blog/likeBlog", {noteId: self.noteId}, function(ret) { - if(ret.Ok) { - // like - if(ret.Item) { - var num = self.preLikeNum+1; - } else { - var num = self.preLikeNum-1; - } - self.preLikeNum = num >= 0 ? num : 0; - self.likeNumO.text(self.preLikeNum); - self.info.isILikeIt = ret.Item; - self.toggleLikeBtnActive(); - - // 重新render likers - // 我是否在列表中 - self.reRenderLikers(ret.Item); - } - }); - }); - - // 显示回复回复 - $("#comments").on("click", ".comment-reply", function() { - var form = $(this).closest("li").find("form"); - if(form.is(":hidden")) { - form.show(); - form.find("textarea").focus(); - } else { - form.hide(); - } - }); - $("#comments").on("click", ".reply-cancel", function() { - $(this).closest("form").hide(); - }); - - // 回复 - $(".comment-box").on("click", ".reply-comment-btn", function(e) { - e.preventDefault(); - var commentId = $(this).data("comment-id"); - var $form = $(this).closest("form"); - var $content = $form.find("textarea"); - var content = $.trim($content.val()); - if(!content) { - $content.focus(); - return; - } - var t = $(this); - t.button("loading"); - var data = {noteId: self.noteId, toCommentId: commentId, content: content}; - ajaxPost(staticUrl + "/blog/comment", data, function(ret) { - t.button("reset"); - $content.val(""); - self.bindCommentNum(1); - if(commentId) { - $form.hide(); - } - - if(commentId) { - scrollToTarget("#comments", -200); - } - - // 添加一个 - self.addCommentRender(ret.Item); - }); - }); - - // 删除 - $(".comment-box").on("click", ".comment-trash", function(e) { - var commentId = $(this).parent().data("comment-id"); - var t = this; - BootstrapDialog.confirm(getMsg("confirmDeleteComment"), function(yes) { - if(yes) { - ajaxPost(staticUrl + "/blog/deleteComment", {noteId: self.noteId, commentId: commentId}, function(ret) { - if(ret.Ok) { - var li = $(t).closest("li"); - li.hide(500); // remove(); - setTimeout(function() { - li.remove(); - }, 300); - - self.bindCommentNum(-1); - } - }); - } - }); - }); - - // 点zan - $(".comment-box").on("click", ".comment-like", function(e) { - var commentId = $(this).parent().data("comment-id"); - var t = this; - - ajaxPost(staticUrl + "/blog/likeComment", {commentId: commentId}, function(re) { - if(re.Ok) { - var ret = re.Item; - if(ret.Num <= 0) { - $(t).parent().find(".like-num").addClass("hide"); - } else { - $(t).parent().find(".like-num").removeClass("hide"); - $(t).parent().find(".like-num-i").text(ret.Num) - } - if(ret.IsILikeIt) { - $(t).find(".like-text").text(getMsg("unlike")); - } else { - $(t).find(".like-text").text(getMsg('like')); - } - } - }); - }); - - // 举报 - function report(commentId, noteId, title) { - var form = $("#reportMsg").html(); - var body; - var input; - var isOver = false; - var modal = BootstrapDialog.show({ - title: title, - message: form, - nl2br: false, - buttons: [{ - label: getMsg("cancel"), - action: function(dialog) { - dialog.close(); - } - }, { - label: getMsg("confirm"), - cssClass: 'btn-primary', - action: function(dialog) { - if(isOver) { - dialog.close(); - } - var val = body.find("input[type='radio']:checked").val(); - if(!val) { - var val = body.find(".input-container input").val(); - } - if(!val) { - body.find(".footnote").html(getMsg("chooseReason")); - return; - } - ajaxPost(staticUrl + "/blog/report", {commentId: commentId, noteId: noteId, reason: val}, function(re) { - isOver = true; - if(reIsOk(re)) { - body.html(getMsg("reportSuccess")); - } else { - body.html(getMsg("error")); - } - setTimeout(function() { - dialog.close(); - }, 3000); - }); - } - }] - }); - body = modal.getModalBody(); - input = body.find(".input-container"); - body.find("input[type='radio']").click(function(){ - if(!$(this).val()) { - input.show(); - input.find("input").focus(); - } else { - input.hide(); - } - }); - } - $(".comment-box").on("click", ".comment-report", function() { - if(needLogin()) { - return; - } - var commentId = $(this).parent().data("comment-id"); - report(commentId, self.noteId, getMsg("reportComment?")); - }); - $("#reportBtn").click(function() { - if(needLogin()) { - return; - } - report("", self.noteId, getMsg("reportBlog?")); - }); - - self.initShare(); - }, - weixinQRCodeO: $("#weixinQRCode"), - initShare: function() { - var self = this; - $(".btn-weixin").click(function() { - if(!self.weixinQRCodeO.html()) { - self.weixinQRCodeO.qrcode(viewUrl + "/" + self.noteId); - } - BootstrapDialog.show({ - title: getMsg('scanQRCode'), - message: self.weixinQRCodeO - }); - }); - - $(".btn-share").click(function() { - var $this = $(this); - var map = {"btn-weibo": shareSinaWeibo, "tencent-weibo": shareTencentWeibo, "qq": shareQQ, "renren": shareRenRen}; - for(var i in map) { - if($this.hasClass(i)) { - map[i](self.noteId, document.title); - break; - } - } - }); - } -} - -$(function() { - C.init(); -}); \ No newline at end of file diff --git a/public/js/app/import_theme.js b/public/js/app/import_theme.js deleted file mode 100644 index 83f7b52..0000000 --- a/public/js/app/import_theme.js +++ /dev/null @@ -1,114 +0,0 @@ -define('import_theme', ['jquery.ui.widget', 'fileupload'], function(){ - // Helper function that formats the file sizes - function formatFileSize(bytes) { - if (typeof bytes !== 'number') { - return ''; - } - if (bytes >= 1000000000) { - return (bytes / 1000000000).toFixed(2) + ' GB'; - } - if (bytes >= 1000000) { - return (bytes / 1000000).toFixed(2) + ' MB'; - } - return (bytes / 1000).toFixed(2) + ' KB'; - } - - function setDropStyle(dropzoneId, formId) { - // drag css - var dropZone = $(dropzoneId); - $(formId).bind('dragover', function (e) { - e.preventDefault(); - var timeout = window.dropZoneTimeoutAttach; - if(timeout) { - clearTimeout(timeout); - } - - var found = false, - node = e.target; - do { - if (node === dropZone[0]) { - found = true; - break; - } - node = node.parentNode; - } while (node != null); - if (found) { - dropZone.addClass('hover'); - } else { - dropZone.removeClass('hover'); - } - window.dropZoneTimeoutAttach = setTimeout(function () { - window.dropZoneTimeoutAttach = null; - dropZone.removeClass('in hover'); - }, 100); - }); - } - - setDropStyle("#dropAvatar", "#uploadAvatar"); - - var initUploader = function() { - $('.dropzone .btn-choose-file').click(function() { - $(this).parent().find('input').click(); - }); - - var $msg2 = $('#avatarUploadMsg'); - $('#uploadAvatar').fileupload({ - dataType: 'json', - dropZone: $('#dropAvatar'), - add: function(e, data) { - var tpl = $(''); - - // Append the file name and file size - tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); - - // Add the HTML to the UL element - $msg2.html(tpl); - data.context = $msg2; - - // 检查文件大小 - var size = data.files[0].size; - if(typeof size == 'number' && size > 10 * 1024 * 1024) { - tpl.find("img").remove(); - tpl.removeClass("alert-info").addClass("alert-danger"); - tpl.append("Warning: File size is bigger than 10M"); - return; - } - - // Automatically upload the file once it is added to the queue - var jqXHR; - setTimeout(function() { - jqXHR = data.submit(); - }, 10); - }, - done: function(e, data) { - if (data.result.Ok == true) { - data.context.html(""); - var re = data.result; - art.tips("Success"); - setTimeout(function() { - location.reload(); - }, 1000); - } else { - var re = data.result; - data.context.html(""); - var tpl = $(''); - tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); - data.context.html(tpl); - } - }, - fail: function(e, data) { - data.context.html(""); - var tpl = $(''); - tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); - data.context.html(tpl); - setTimeout((function(tpl) { - return function() { - tpl.remove(); - } - })(tpl), 3000); - } - }); - } - - initUploader(); -}); \ No newline at end of file diff --git a/public/js/app/note-min.js b/public/js/app/note-min.js deleted file mode 100644 index 26a4329..0000000 --- a/public/js/app/note-min.js +++ /dev/null @@ -1 +0,0 @@ -Note.curNoteId="";Note.interval="";Note.itemIsBlog='
    ';Note.itemTplNoImg='
  • ';Note.itemTplNoImg+=Note.itemIsBlog+'

    ?

    ? ?

    ?

  • ';Note.itemTpl='
  • ';Note.itemTpl+=Note.itemIsBlog+'

    ?

    ? ?

    ?

  • ';Note.newItemTpl='
  • ';Note.newItemTpl+=Note.itemIsBlog+'

    ?

    ? ?
    ?

  • ';Note.noteItemListO=$("#noteItemList");Note.cacheByNotebookId={all:{}};Note.notebookIds={};Note.isReadOnly=false;Note.intervalTime=6e5;Note.startInterval=function(){Note.interval=setInterval(function(){log("自动保存开始...");changedNote=Note.curChangedSaveIt(false)},Note.intervalTime)};Note.stopInterval=function(){clearInterval(Note.interval);setTimeout(function(){Note.startInterval()},Note.intervalTime)};Note.addNoteCache=function(note){Note.cache[note.NoteId]=note;Note.clearCacheByNotebookId(note.NotebookId)};Note.setNoteCache=function(content,clear){if(!Note.cache[content.NoteId]){Note.cache[content.NoteId]=content}else{$.extend(Note.cache[content.NoteId],content)}if(clear==undefined){clear=true}if(clear){Note.clearCacheByNotebookId(content.NotebookId)}};Note.getCurNote=function(){var self=this;if(self.curNoteId==""){return null}return self.cache[self.curNoteId]};Note.getNote=function(noteId){var self=this;return self.cache[noteId]};Note.clearCacheByNotebookId=function(notebookId){if(notebookId){Note.cacheByNotebookId[notebookId]={};Note.cacheByNotebookId["all"]={};Note.notebookIds[notebookId]=true}};Note.notebookHasNotes=function(notebookId){var notes=Note.getNotesByNotebookId(notebookId);return!isEmpty(notes)};Note.getNotesByNotebookId=function(notebookId,sortBy,isAsc){if(!sortBy){sortBy="UpdatedTime"}if(isAsc=="undefined"){isAsc=false}if(!notebookId){notebookId="all"}if(!Note.cacheByNotebookId[notebookId]){return[]}if(Note.cacheByNotebookId[notebookId][sortBy]){return Note.cacheByNotebookId[notebookId][sortBy]}else{}var notes=[];var sortBys=[];for(var i in Note.cache){if(!i){continue}var note=Note.cache[i];if(note.IsTrash||note.IsShared){continue}if(notebookId=="all"||note.NotebookId==notebookId){notes.push(note)}}notes.sort(function(a,b){var t1=a[sortBy];var t2=b[sortBy];if(isAsc){if(t1t2){return 1}}else{if(t1t2){return-1}}return 0});Note.cacheByNotebookId[notebookId][sortBy]=notes;return notes};Note.renderNotesAndFirstOneContent=function(ret){if(!isArray(ret)){return}Note.renderNotes(ret);if(!isEmpty(ret[0])){Note.changeNote(ret[0].NoteId)}else{}};Note.curHasChanged=function(force){if(force==undefined){force=true}var cacheNote=Note.cache[Note.curNoteId]||{};var title=$("#noteTitle").val();var tags=Tag.getTags();var contents=getEditorContent(cacheNote.IsMarkdown);var content,preview;var contentText;if(isArray(contents)){content=contents[0];preview=contents[1];contentText=content;if(content&&previewIsEmpty(preview)&&Converter){preview=Converter.makeHtml(content)}if(!content){preview=""}cacheNote.Preview=preview}else{content=contents;try{contentText=$(content).text()}catch(e){}}var hasChanged={hasChanged:false,IsNew:cacheNote.IsNew,IsMarkdown:cacheNote.IsMarkdown,FromUserId:cacheNote.FromUserId,NoteId:cacheNote.NoteId,NotebookId:cacheNote.NotebookId};if(hasChanged.IsNew){$.extend(hasChanged,cacheNote)}if(cacheNote.Title!=title){hasChanged.hasChanged=true;hasChanged.Title=title;if(!hasChanged.Title){}}if(!arrayEqual(cacheNote.Tags,tags)){hasChanged.hasChanged=true;hasChanged.Tags=tags}if(force&&cacheNote.Content!=content||!force&&$(cacheNote.Content).text()!=contentText){hasChanged.hasChanged=true;hasChanged.Content=content;var c=preview||content;hasChanged.Desc=Note.genDesc(c);hasChanged.ImgSrc=Note.getImgSrc(c);hasChanged.Abstract=Note.genAbstract(c)}else{log("text相同");log(cacheNote.Content==content)}hasChanged["UserId"]=cacheNote["UserId"]||"";return hasChanged};Note.genDesc=function(content){if(!content){return""}content=content.replace(/
    /g,"
    ");content=content.replace(/<\/p>/g,"

    ");content=content.replace(/<\/div>/g,"
    ");content=$("
    ").html(content).text();content=content.replace(//g,">");if(content.length<300){return content}return content.substring(0,300)};Note.genAbstract=function(content,len){if(len==undefined){len=1e3}if(content.length"&&isCode){n=n-1;isCode=false}else if(temp==";"&&isHTML){isHTML=false}if(!isCode&&!isHTML){n=n+1}result+=temp;if(n>=maxLen){break}}var d=document.createElement("div");d.innerHTML=result;return d.innerHTML};Note.getImgSrc=function(content){if(!content){return""}var imgs=$(content).find("img");for(var i in imgs){var src=imgs.eq(i).attr("src");if(src){return src}}return""};Note.curChangedSaveIt=function(force){if(!Note.curNoteId||Note.isReadOnly){return}var hasChanged=Note.curHasChanged(force);Note.renderChangedNote(hasChanged);if(hasChanged.hasChanged||hasChanged.IsNew){delete hasChanged.hasChanged;Note.setNoteCache(hasChanged,false);Note.setNoteCache({NoteId:hasChanged.NoteId,UpdatedTime:(new Date).format("yyyy-MM-ddThh:mm:ss.S")},false);showMsg(getMsg("saving"));ajaxPost("/note/UpdateNoteOrContent",hasChanged,function(ret){if(hasChanged.IsNew){ret.IsNew=false;Note.setNoteCache(ret,false)}showMsg(getMsg("saveSuccess"),1e3)});return hasChanged}return false};Note.selectTarget=function(target){$(".item").removeClass("item-active");$(target).addClass("item-active")};Note.showContentLoading=function(){$("#noteMaskForLoading").css("z-index",99999)};Note.hideContentLoading=function(){$("#noteMaskForLoading").css("z-index",-1)};Note.contentAjax=null;Note.contentAjaxSeq=1;Note.changeNote=function(selectNoteId,isShare,needSaveChanged){var self=this;Note.stopInterval();var target=$(tt('[noteId="?"]',selectNoteId));Note.selectTarget(target);if(needSaveChanged==undefined){needSaveChanged=true}if(needSaveChanged){var changedNote=Note.curChangedSaveIt()}Note.curNoteId="";var cacheNote=Note.cache[selectNoteId];if(!isShare){if(cacheNote.Perm!=undefined){isShare=true}}var hasPerm=!isShare||Share.hasUpdatePerm(selectNoteId);if(hasPerm){Note.hideReadOnly();Note.renderNote(cacheNote);switchEditor(cacheNote.IsMarkdown)}else{Note.renderNoteReadOnly(cacheNote)}Attach.renderNoteAttachNum(selectNoteId,true);Note.contentAjaxSeq++;var seq=Note.contentAjaxSeq;function setContent(ret){Note.contentAjax=null;if(seq!=Note.contentAjaxSeq){return}Note.setNoteCache(ret,false);ret=Note.cache[selectNoteId];if(hasPerm){Note.renderNoteContent(ret)}else{Note.renderNoteContentReadOnly(ret)}self.hideContentLoading()}if(cacheNote.Content){setContent(cacheNote);return}var url="/note/GetNoteContent";var param={noteId:selectNoteId};if(isShare){url="/share/GetShareNoteContent";param.sharedUserId=cacheNote.UserId}self.showContentLoading();if(Note.contentAjax!=null){Note.contentAjax.abort()}note.contentAjax=ajaxGet(url,param,setContent)};Note.renderChangedNote=function(changedNote){if(!changedNote){return}var $leftNoteNav=$(tt('[noteId="?"]',changedNote.NoteId));if(changedNote.Title){$leftNoteNav.find(".item-title").html(changedNote.Title)}if(changedNote.Desc){$leftNoteNav.find(".desc").html(changedNote.Desc)}if(changedNote.ImgSrc){$thumb=$leftNoteNav.find(".item-thumb");if($thumb.length>0){$thumb.find("img").attr("src",changedNote.ImgSrc)}else{$leftNoteNav.append(tt('
    ',changedNote.ImgSrc));$leftNoteNav.addClass("item-image")}$leftNoteNav.find(".item-desc").removeAttr("style")}else if(changedNote.ImgSrc==""){$leftNoteNav.find(".item-thumb").remove();$leftNoteNav.removeClass("item-image")}};Note.clearNoteInfo=function(){Note.curNoteId="";Tag.clearTags();$("#noteTitle").val("");setEditorContent("");$("#wmd-input").val("");$("#wmd-preview").html("");$("#noteRead").hide()};Note.clearNoteList=function(){Note.noteItemListO.html("")};Note.clearAll=function(){Note.curNoteId="";Note.clearNoteInfo();Note.clearNoteList()};Note.renderNote=function(note){if(!note){return}$("#noteTitle").val(note.Title);Tag.renderTags(note.Tags)};Note.renderNoteContent=function(content){setEditorContent(content.Content,content.IsMarkdown,content.Preview);Note.curNoteId=content.NoteId};Note.showEditorMask=function(){$("#editorMask").css("z-index",10).show();if(Notebook.curNotebookIsTrashOrAll()){$("#editorMaskBtns").hide();$("#editorMaskBtnsEmpty").show()}else{$("#editorMaskBtns").show();$("#editorMaskBtnsEmpty").hide()}};Note.hideEditorMask=function(){$("#editorMask").css("z-index",-10).hide()};Note.renderNotesC=0;Note.renderNotes=function(notes,forNewNote,isShared){var renderNotesC=++Note.renderNotesC;if(!LEA.isMobile&&!Mobile.isMobile()){$("#noteItemList").slimScroll({scrollTo:"0px",height:"100%",onlyScrollBar:true})}if(!notes||typeof notes!="object"||notes.length<=0){if(!forNewNote){Note.showEditorMask()}return}Note.hideEditorMask();if(forNewNote==undefined){forNewNote=false}if(!forNewNote){Note.noteItemListO.html("")}var len=notes.length;var c=Math.ceil(len/20);Note._renderNotes(notes,forNewNote,isShared,1);for(var i=0;i'+getMsg("close")+"");options={};options.show=true;$("#leanoteDialog").modal(options);ajaxGet("noteContentHistory/listHistories",{noteId:Note.curNoteId},function(re){if(!isArray(re)){$content.html(getMsg("noHistories"));return}var str="

    "+getMsg("historiesNum")+'

    ';note=Note.cache[Note.curNoteId];var s="div";if(note.IsMarkdown){s="pre"}for(i in re){var content=re[i];content.Ab=Note.genAbstract(content.Content,200);str+=tt('",i,+i+1,s,content.Ab,s,goNowToDatetime(content.UpdatedTime))}str+="
    #??
    '+getMsg("datetime")+': ?
    ";$content.html(str);$("#historyList .all").click(function(){$p=$(this).parent().parent();var seq=$p.attr("seq");var $c=$p.find(".each-content");var info=re[seq];if(!info.unfold){$(this).text(getMsg("fold"));$c.html(info.Content);info.unfold=true}else{$(this).text(getMsg("unfold"));$c.html(info.Ab);info.unfold=false}});$("#historyList .back").click(function(){$p=$(this).parent().parent();var seq=$p.attr("seq");if(confirm(getMsg("confirmBackup"))){Note.curChangedSaveIt();note=Note.cache[Note.curNoteId];setEditorContent(re[seq].Content,note.IsMarkdown);hideDialog()}})})};Note.html2Image=function(target){var noteId=$(target).attr("noteId");showDialog("html2ImageDialog",{title:"分享到社区",postShow:function(){ajaxGet("/note/html2Image",{noteId:noteId},function(ret){if(typeof ret=="object"&&ret.Ok){$("#leanoteDialog .weibo span").html("生成成功, 右键图片保存到本地.");$("#leanoteDialog .weibo img").attr("src",ret.Id+"?"+(new Date).getTime());$("#leanoteDialog .btn-share").removeClass("disabled");var note=Note.cache[noteId];var pic=UrlPrefix+ret.Id;var title=encodeURI(note.Title+" ("+UserInfo.Username+"分享. 来自leanote.com)");var windowParam="width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no";$("#leanoteDialog .sendWeiboBtn").click(function(){var url="http://service.weibo.com/share/share.php?title="+title;url+="&pic="+pic;window.open(url,"分享到新浪微博",windowParam)});$("#leanoteDialog .sendTxWeiboBtn").click(function(){var _appkey="801542571";var url="http://share.v.t.qq.com/index.php?c=share&a=index&appkey="+_appkey+"&title="+title+"&url=&pic="+pic;window.open(url,"分享到腾讯微博",windowParam)});$("#leanoteDialog .sendQQBtn").click(function(){var url="http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url="+UrlPrefix+"&title="+title+"&pics="+pic;window.open(url,"分享QQ空间",windowParam)});$("#leanoteDialog .sendRRBtn").click(function(){var url="http://widget.renren.com/dialog/share?resourceUrl="+UrlPrefix+"&srcUrl="+UrlPrefix+"&title="+title+"&pic="+pic;window.open(url,"分享人人网",windowParam)})}else{$("#leanoteDialog .weibo").html("对不起, 我们出错了!")}})}})};Note.showReadOnly=function(){Note.isReadOnly=true;$("#noteRead").show()};Note.hideReadOnly=function(){Note.isReadOnly=false;$("#noteRead").hide()};Note.renderNoteReadOnly=function(note){Note.showReadOnly();$("#noteReadTitle").html(note.Title);Tag.renderReadOnlyTags(note.Tags);$("#noteReadCreatedTime").html(goNowToDatetime(note.CreatedTime));$("#noteReadUpdatedTime").html(goNowToDatetime(note.UpdatedTime))};Note.renderNoteContentReadOnly=function(note){if(note.IsMarkdown){$("#noteReadContent").html('
    '+note.Content+"
    ")}else{$("#noteReadContent").html(note.Content)}};Note.lastSearch=null;Note.lastKey=null;Note.lastSearchTime=new Date;Note.isOver2Seconds=false;Note.isSameSearch=function(key){var now=new Date;var duration=now.getTime()-Note.lastSearchTime.getTime();Note.isOver2Seconds=duration>2e3?true:false;if(!Note.lastKey||Note.lastKey!=key||duration>1e3){Note.lastKey=key;Note.lastSearchTime=now;return false}if(key==Note.lastKey){return true}Note.lastSearchTime=now;Note.lastKey=key;return false};Note.searchNote=function(){var val=$("#searchNoteInput").val();if(!val){Notebook.changeNotebook("0");return}if(Note.isSameSearch(val)){return}if(Note.lastSearch){Note.lastSearch.abort()}Note.curChangedSaveIt();Note.clearAll();showLoading();Note.lastSearch=$.post("/note/searchNote",{key:val},function(notes){hideLoading();if(notes){Note.lastSearch=null;Note.renderNotes(notes);if(!isEmpty(notes)){Note.changeNote(notes[0].NoteId,false)}}else{}})};Note.setNote2Blog=function(target){var noteId=$(target).attr("noteId");var note=Note.cache[noteId];var isBlog=true;if(note.IsBlog!=undefined){isBlog=!note.IsBlog}if(isBlog){$(target).find(".item-blog").show()}else{$(target).find(".item-blog").hide()}ajaxPost("/blog/setNote2Blog",{noteId:noteId,isBlog:isBlog},function(ret){if(ret){Note.setNoteCache({NoteId:noteId,IsBlog:isBlog},false)}})};Note.setAllNoteBlogStatus=function(notebookId,isBlog){if(!notebookId){return}var notes=Note.getNotesByNotebookId(notebookId);if(!isArray(notes)){return}var len=notes.length;if(len==0){for(var i in Note.cache){if(Note.cache[i].NotebookId==notebookId){Note.cache[i].IsBlog=isBlog}}}else{for(var i=0;i'+attach.Title+"")}});self.linkAllBtnO.on("click",function(e){e.stopPropagation();var note=Note.getCurNote();if(!note){return}var src=UrlPrefix+"/attach/downloadAll?noteId="+Note.curNoteId;var title=note.Title?note.Title+".tar.gz":"all.tar.gz";if(LEA.isMarkdownEditor()&&MarkdownEditor){MarkdownEditor.insertLink(src,title)}else{tinymce.activeEditor.insertContent(''+title+"")}})},attachListO:$("#attachList"),attachNumO:$("#attachNum"),attachDropdownO:$("#attachDropdown"),downloadAllBtnO:$("#downloadAllBtn"),linkAllBtnO:$("#linkAllBtn"),clearNoteAttachNum:function(){var self=this;self.attachNumO.html("").hide()},renderNoteAttachNum:function(noteId,needHide){var self=this;var note=Note.getNote(noteId);if(note.AttachNum){self.attachNumO.html("("+note.AttachNum+")").show();self.downloadAllBtnO.show();self.linkAllBtnO.show()}else{self.attachNumO.hide();self.downloadAllBtnO.hide();self.linkAllBtnO.hide()}if(needHide){self.attachDropdownO.removeClass("open")}},_renderAttachs:function(attachs){var self=this;var html="";var attachNum=attachs.length;for(var i=0;i'+'
    '+each.Title+"
    "+'
    '+' '+' '+' '+"
    "+"";self.attachsMap[each.AttachId]=each}self.attachListO.html(html);var note=Note.getCurNote();if(note){note.AttachNum=attachNum;self.renderNoteAttachNum(note.NoteId,false)}},renderAttachs:function(noteId){var self=this;if(self.loadedNoteAttachs[noteId]){self._renderAttachs(self.loadedNoteAttachs[noteId]);return}self.attachListO.html('
  • ');ajaxGet("/attach/getAttachs",{noteId:noteId},function(ret){var list=[];if(ret.Ok){list=ret.List;if(!list){list=[]}}self.loadedNoteAttachs[noteId]=list;self._renderAttachs(list)})},addAttach:function(attachInfo){var self=this;if(!self.loadedNoteAttachs[attachInfo.NoteId]){self.loadedNoteAttachs[attachInfo.NoteId]=[]}self.loadedNoteAttachs[attachInfo.NoteId].push(attachInfo);self.renderAttachs(attachInfo.NoteId)},deleteAttach:function(attachId){var self=this;var noteId=Note.curNoteId;var attachs=self.loadedNoteAttachs[noteId];for(var i=0;i 得到该notebook的notes, 显示出来, 并选中第一个! -// 在这期间定时器还会保存, curNoteId还没换, 所以会清空curNoteId的content!!! - -// 2. note change, save cur, 立即curNoteId = ""!! - -// 3. 什么时候设置curNoteId? 是ajax得到内容之后设置 - -// note -Note.curNoteId = ""; - -Note.interval = ""; // 定时器 - -Note.itemIsBlog = '
    '; -// for render -Note.itemTplNoImg = '
  • ' -Note.itemTplNoImg += Note.itemIsBlog +'

    ?

    ? ?

    ?

  • '; - -// 有image -Note.itemTpl = '
  • ' -Note.itemTpl +=Note.itemIsBlog + '

    ?

    ? ?

    ?

  • '; - -// for new -Note.newItemTpl = '
  • ' -Note.newItemTpl += Note.itemIsBlog + '

    ?

    ? ?
    ?

  • '; - -Note.noteItemListO = $("#noteItemList"); - -// notbeookId => {"updatedTime" => [noteId1, noteId2], "title" => [noteId1, noteId2...]} 排序方式分组 -// 一旦某notebook改变了就清空, 重新排序之. (用js排) -Note.cacheByNotebookId = {all: {}}; -Note.notebookIds = {}; // notebookId => true - -Note.isReadOnly = false; -// 定时保存信息 -Note.intervalTime = 600000; // 600s, 10mins -Note.startInterval = function() { - Note.interval = setInterval(function() { - log("自动保存开始...") - changedNote = Note.curChangedSaveIt(false); - }, Note.intervalTime); // 600s, 10mins -} -// 停止, 当切换note时 -// 但过5000后自动启动 -Note.stopInterval = function() { - clearInterval(Note.interval); - - setTimeout(function() { - Note.startInterval(); - }, Note.intervalTime); -} - -// note = {NoteId, Desc, UserId,...} -Note.addNoteCache = function(note) { - Note.cache[note.NoteId] = note; - Note.clearCacheByNotebookId(note.NotebookId); -} -// content = {NoteId:, Content:} -// 还可以设置其它的值 -Note.setNoteCache = function(content, clear) { - if(!Note.cache[content.NoteId]) { - Note.cache[content.NoteId] = content; - } else { - $.extend(Note.cache[content.NoteId], content); - } - - if(clear == undefined) { - clear = true; - } - if(clear) { - Note.clearCacheByNotebookId(content.NotebookId); - } -} - -// 得到当前的笔记 -Note.getCurNote = function() { - var self = this; - if(self.curNoteId == "") { - return null; - } - return self.cache[self.curNoteId]; -} -Note.getNote = function(noteId) { - var self = this; - return self.cache[noteId]; -} - -// 每当有notebookId相应的note改变时都要重新清空之 -// 并设置该notebookId有值 -Note.clearCacheByNotebookId = function(notebookId) { - if(notebookId) { - Note.cacheByNotebookId[notebookId] = {}; - Note.cacheByNotebookId["all"] = {}; - Note.notebookIds[notebookId] = true; - } -} - -// notebook是否有notes -// called by Notebook -Note.notebookHasNotes = function(notebookId) { - var notes = Note.getNotesByNotebookId(notebookId); - return !isEmpty(notes); -} - -// 得到notebook下的notes, 按什么排序 updatedTime? -Note.getNotesByNotebookId = function(notebookId, sortBy, isAsc) { - if(!sortBy) { - sortBy = "UpdatedTime"; - } - if(isAsc == "undefined") { - isAsc = false; // 默认是降序 - } - - if(!notebookId) { - notebookId = "all"; - } - - if(!Note.cacheByNotebookId[notebookId]) { - return []; - } - - if(Note.cacheByNotebookId[notebookId][sortBy]) { - return Note.cacheByNotebookId[notebookId][sortBy]; - } else { - } - - // 从所有的notes中找到notebookId的, 并排序之 - var notes = []; - var sortBys = []; - for(var i in Note.cache) { - if(!i) { - continue; - } - var note = Note.cache[i]; - // 不要trash的not, 共享的也不要 - if(note.IsTrash || note.IsShared) { - continue; - } - if(notebookId == "all" || note.NotebookId == notebookId) { - notes.push(note); - } - } - // 排序之 - notes.sort(function(a, b) { - var t1 = a[sortBy]; - var t2 = b[sortBy]; - - if(isAsc) { - if(t1 < t2) { - return -1; - } else if (t1 > t2) { - return 1; - } - } else { - if(t1 < t2) { - return 1; - } else if (t1 > t2) { - return -1; - } - } - return 0; - }); - - // 缓存之 - Note.cacheByNotebookId[notebookId][sortBy] = notes; - return notes; -} - -// called by Notebook -// render 所有notes, 和第一个note的content -Note.renderNotesAndFirstOneContent = function(ret) { - // 错误的ret是一个Object - if(!isArray(ret)) { - return; - } - - // note 导航 - Note.renderNotes(ret); - // 渲染第一个 - if(!isEmpty(ret[0])) { - Note.changeNote(ret[0].NoteId); - } else { - } - -} - -// 当前的note是否改变过了? -// 返回已改变的信息 -// force bool true表示content比较是比较HTML, 否则比较text, 默认为true -// 定时保存用false -Note.curHasChanged = function(force) { - if(force == undefined) { - force = true; - } - var cacheNote = Note.cache[Note.curNoteId] || {}; - // 收集当前信息, 与cache比对 - var title = $("#noteTitle").val(); - var tags = Tag.getTags(); // TODO - - // 如果是markdown返回[content, preview] - var contents = getEditorContent(cacheNote.IsMarkdown); - var content, preview; - var contentText; - if (isArray(contents)) { - content = contents[0]; - preview = contents[1]; - contentText = content; - // preview可能没来得到及解析 - if (content && previewIsEmpty(preview) && Converter) { - preview = Converter.makeHtml(content); - } - if(!content) { - preview = ""; - } - cacheNote.Preview = preview; // 仅仅缓存在前台 - } else { - content = contents; - try { - contentText = $(content).text(); - } catch(e) { - } - } - - var hasChanged = { - hasChanged: false, // 总的是否有改变 - IsNew: cacheNote.IsNew, // 是否是新添加的 - IsMarkdown: cacheNote.IsMarkdown, // 是否是markdown笔记 - FromUserId: cacheNote.FromUserId, // 是否是共享新建的 - NoteId: cacheNote.NoteId, - NotebookId: cacheNote.NotebookId - }; - - if(hasChanged.IsNew) { - $.extend(hasChanged, cacheNote); - } - - if(cacheNote.Title != title) { - hasChanged.hasChanged = true; // 本页使用用小写 - hasChanged.Title = title; // 要传到后台的用大写 - if(!hasChanged.Title) { -// alert(1); - } - } - - if(!arrayEqual(cacheNote.Tags, tags)) { - hasChanged.hasChanged = true; - hasChanged.Tags = tags; - } - - // 比较text, 因为note Nav会添加dom会导致content改变 - if((force && cacheNote.Content != content) || (!force && $(cacheNote.Content).text() != contentText)) { - hasChanged.hasChanged = true; - hasChanged.Content = content; - - // 从html中得到... - var c = preview || content; - - hasChanged.Desc = Note.genDesc(c); - hasChanged.ImgSrc = Note.getImgSrc(c); - hasChanged.Abstract = Note.genAbstract(c); - - } else { - log("text相同"); - log(cacheNote.Content == content); - } - - hasChanged["UserId"] = cacheNote["UserId"] || ""; - - return hasChanged; -} - -// 由content生成desc -// 换行不要替换 -Note.genDesc = function(content) { - if(!content) { - return ""; - } - - // 将,

    替换成\n - /* - var token = "ALEALE"; - content = content.replace(/<\/p>/g, token); - content = content.replace(/<\/div>/g, token); - content = content.replace(/<\/?.+?>/g," "); - - pattern = new RegExp(token, "g"); - content = content.replace(pattern, "
    "); - content = content.replace(/
    ( *)
    /g, "
    "); // 两个
    之间可能有空白 - content = content.replace(/
    ( *)
    /g, "
    "); - - // 去掉最开始的
    或

    - content = trimLeft(content, " "); - content = trimLeft(content, "
    "); - content = trimLeft(content, "

    "); - content = trimLeft(content, ""); - */ - - // 留空格 - content = content.replace(/
    /g,"
    "); - content = content.replace(/<\/p>/g,"

    "); - content = content.replace(/<\/div>/g," "); - - // 避免其它的").html(content).text(); - - // pre下text()会将< => < > => > - content = content.replace(//g, ">"); - - if(content.length < 300) { - return content; - } - return content.substring(0, 300); -} - -// 得到摘要 -Note.genAbstract = function(content, len) { - if(len == undefined) { - len = 1000; - } - if(content.length < len) { - return content; - } - var isCode = false; - var isHTML = false; - var n = 0; - var result = ""; - var maxLen = len; - for(var i = 0; i < content.length; ++i) { - var temp = content[i] - if (temp == '<') { - isCode = true - } else if (temp == '&') { - isHTML = true - } else if (temp == '>' && isCode) { - n = n - 1 - isCode = false - } else if (temp == ';' && isHTML) { - isHTML = false - } - if (!isCode && !isHTML) { - n = n + 1 - } - result += temp - if (n >= maxLen) { - break - } - } - - var d = document.createElement("div"); - d.innerHTML = result - return d.innerHTML; -} - -Note.getImgSrc = function(content) { - if(!content) { - return ""; - } - var imgs = $(content).find("img"); - for(var i in imgs) { - var src = imgs.eq(i).attr("src"); - if(src) { - return src; - } - } - return ""; -} - -// 如果当前的改变了, 就保存它 -// 以后要定时调用 -// force , 默认是true, 表强校验内容 -// 定时保存传false -Note.curChangedSaveIt = function(force) { - // 如果当前没有笔记, 不保存 - if(!Note.curNoteId || Note.isReadOnly) { - return; - } - - var hasChanged = Note.curHasChanged(force); - - // 把已改变的渲染到左边 item-list - Note.renderChangedNote(hasChanged); - - if(hasChanged.hasChanged || hasChanged.IsNew) { - delete hasChanged.hasChanged; - - // 先缓存, 把markdown的preview也缓存起来 - Note.setNoteCache(hasChanged, false); - - // 设置更新时间 - Note.setNoteCache({"NoteId": hasChanged.NoteId, "UpdatedTime": (new Date()).format("yyyy-MM-ddThh:mm:ss.S")}, false); - - // 保存之 - showMsg(getMsg("saving")); - ajaxPost("/note/UpdateNoteOrContent", hasChanged, function(ret) { - if(hasChanged.IsNew) { - // 缓存之, 后台得到其它信息 - ret.IsNew = false; - Note.setNoteCache(ret, false); - } - showMsg(getMsg("saveSuccess"), 1000); - }); - - return hasChanged; - } - return false; -} - -// 样式 -Note.selectTarget = function(target) { - $(".item").removeClass("item-active"); - $(target).addClass("item-active"); -} - -// 改变note -// 可能改变的是share note -// 1. 保存之前的note -// 2. ajax得到现在的note -Note.showContentLoading = function() { - $("#noteMaskForLoading").css("z-index", 99999); -} -Note.hideContentLoading = function() { - $("#noteMaskForLoading").css("z-index", -1); -} -Note.contentAjax = null; -Note.contentAjaxSeq = 1; -Note.changeNote = function(selectNoteId, isShare, needSaveChanged) { - var self = this; - // -1 停止定时器 - Note.stopInterval(); - - // 0 - var target = $(tt('[noteId="?"]', selectNoteId)) - Note.selectTarget(target); - - // 1 之前的note, 判断是否已改变, 改变了就要保存之 - // 这里, 在搜索的时候总是保存, 搜索的话, 比较快, 肯定没有变化, 就不要执行该操作 - if(needSaveChanged == undefined) { - needSaveChanged = true; - } - if(needSaveChanged) { - var changedNote = Note.curChangedSaveIt(); - } - - // 2. 设空, 防止在内容得到之前又发生保存 - Note.curNoteId = ""; - - // 2 得到现在的 - // ajax之 - var cacheNote = Note.cache[selectNoteId]; - - // 判断是否是共享notes - if(!isShare) { - if(cacheNote.Perm != undefined) { - isShare = true; - } - } - var hasPerm = !isShare || Share.hasUpdatePerm(selectNoteId); // 不是共享, 或者是共享但有权限 - - // 有权限 - if(hasPerm) { - Note.hideReadOnly(); - Note.renderNote(cacheNote); - - // 这里要切换编辑器 - switchEditor(cacheNote.IsMarkdown) - } else { - Note.renderNoteReadOnly(cacheNote); - } - - Attach.renderNoteAttachNum(selectNoteId, true); - - Note.contentAjaxSeq++; - var seq = Note.contentAjaxSeq; - function setContent(ret) { - Note.contentAjax = null; - if(seq != Note.contentAjaxSeq) { - return; - } - Note.setNoteCache(ret, false); - // 把其它信息也带上 - ret = Note.cache[selectNoteId] - if(hasPerm) { - Note.renderNoteContent(ret); - } else { - Note.renderNoteContentReadOnly(ret); - } - self.hideContentLoading(); - } - - if(cacheNote.Content) { - setContent(cacheNote); - return; - } - - var url = "/note/GetNoteContent"; - var param = {noteId: selectNoteId}; - if(isShare) { - url = "/share/GetShareNoteContent"; - param.sharedUserId = cacheNote.UserId // 谁的笔记 - } - - self.showContentLoading(); - if(Note.contentAjax != null) { - Note.contentAjax.abort(); - } - note.contentAjax = ajaxGet(url, param, setContent); -} - -// 渲染 - -// 更改信息到左侧 -// 定时更改 当前正在编辑的信息到左侧导航 -// 或change select. 之前的note, 已经改变了 -Note.renderChangedNote = function(changedNote) { - if(!changedNote) { - return; - } - - // 找到左侧相应的note - var $leftNoteNav = $(tt('[noteId="?"]', changedNote.NoteId)); - if(changedNote.Title) { - $leftNoteNav.find(".item-title").html(changedNote.Title); - } - if(changedNote.Desc) { - $leftNoteNav.find(".desc").html(changedNote.Desc); - } - if(changedNote.ImgSrc) { - $thumb = $leftNoteNav.find(".item-thumb"); - // 有可能之前没有图片 - if($thumb.length > 0) { - $thumb.find("img").attr("src", changedNote.ImgSrc); - } else { - $leftNoteNav.append(tt('
    ', changedNote.ImgSrc)); - $leftNoteNav.addClass("item-image"); - } - $leftNoteNav.find(".item-desc").removeAttr("style"); - } else if(changedNote.ImgSrc == "") { - $leftNoteNav.find(".item-thumb").remove(); // 以前有, 现在没有了 - $leftNoteNav.removeClass("item-image"); - } -} - -// 清空右侧note信息, 可能是共享的, -// 此时需要清空只读的, 且切换到note edit模式下 -Note.clearNoteInfo = function() { - Note.curNoteId = ""; - Tag.clearTags(); - $("#noteTitle").val(""); - setEditorContent(""); - - // markdown editor - $("#wmd-input").val(""); - $("#wmd-preview").html(""); - - // 只隐藏即可 - $("#noteRead").hide(); -} -// 清除noteList导航 -Note.clearNoteList = function() { - Note.noteItemListO.html(""); // 清空 -} - -// 清空所有, 在转换notebook时使用 -Note.clearAll = function() { - // 当前的笔记清空掉 - Note.curNoteId = ""; - - Note.clearNoteInfo(); - Note.clearNoteList(); -} - -// render到编辑器 -// render note -Note.renderNote = function(note) { - if(!note) { - return; - } - // title - $("#noteTitle").val(note.Title); - - // 当前正在编辑的 - // tags - Tag.renderTags(note.Tags); -} - -// render content -Note.renderNoteContent = function(content) { - setEditorContent(content.Content, content.IsMarkdown, content.Preview); - // 只有在renderNoteContent时才设置curNoteId - Note.curNoteId = content.NoteId; -} - -// 初始化时渲染最初的notes -/** -
    - -*/ - -Note.showEditorMask = function() { - $("#editorMask").css("z-index", 10).show(); - // 要判断是否是垃圾筒 - if(Notebook.curNotebookIsTrashOrAll()) { - $("#editorMaskBtns").hide(); - $("#editorMaskBtnsEmpty").show(); - } else { - $("#editorMaskBtns").show(); - $("#editorMaskBtnsEmpty").hide(); - } -} -Note.hideEditorMask = function() { - $("#editorMask").css("z-index", -10).hide(); -} - -// 这里如果notes过多>100个将会很慢!!, 使用setTimeout来分解 -Note.renderNotesC = 0; -Note.renderNotes = function(notes, forNewNote, isShared) { - var renderNotesC = ++Note.renderNotesC; - - // 手机端不用 - // slimScroll使得手机端滚动不流畅 - if(!LEA.isMobile && !Mobile.isMobile()) { - $("#noteItemList").slimScroll({ scrollTo: '0px', height: "100%", onlyScrollBar: true}); - } - - if(!notes || typeof notes != "object" || notes.length <= 0) { - // 如果没有, 那么是不是应该hide editor? - if(!forNewNote) { - Note.showEditorMask(); - } - return; - } - Note.hideEditorMask(); - // 新建笔记时会先创建一个新笔记, 所以不能清空 - if(forNewNote == undefined) { - forNewNote = false; - } - if(!forNewNote) { - Note.noteItemListO.html(""); // 清空 - } - - // 20个一次 - var len = notes.length; - var c = Math.ceil(len/20); - - Note._renderNotes(notes, forNewNote, isShared, 1); - - // 先设置缓存 - for(var i = 0; i < len; ++i) { - var note = notes[i]; - // 不清空 - // 之前是addNoteCache, 如果是搜索出的, 会把内容都重置了 - Note.setNoteCache(note, false); - - // 如果是共享的笔记本, 缓存也放在Share下 - if(isShared) { - Share.setCache(note); - } - } - - for(var i = 1; i < c; ++i) { - setTimeout( - (function(i) { - // 防止还没渲染完就点击另一个notebook了 - return function() { - if(renderNotesC == Note.renderNotesC) { - Note._renderNotes(notes, forNewNote, isShared, i+1); - } - } - })(i), i*2000); - } -} -Note._renderNotes = function(notes, forNewNote, isShared, tang) { // 第几趟 - var baseClasses = "item-my"; - if(isShared) { - baseClasses = "item-shared"; - } - - var len = notes.length; - for(var i = (tang-1)*20; i < len && i < tang*20; ++i) { - var classes = baseClasses; - if(!forNewNote && i == 0) { - classes += " item-active"; - } - var note = notes[i]; - var tmp; - if(note.ImgSrc) { - tmp = tt(Note.itemTpl, classes, note.NoteId, note.ImgSrc, note.Title, Notebook.getNotebookTitle(note.NotebookId), goNowToDatetime(note.UpdatedTime), note.Desc); - } else { - tmp = tt(Note.itemTplNoImg, classes, note.NoteId, note.Title, Notebook.getNotebookTitle(note.NotebookId), goNowToDatetime(note.UpdatedTime), note.Desc); - } - if(!note.IsBlog) { - tmp = $(tmp); - tmp.find(".item-blog").hide(); - } - Note.noteItemListO.append(tmp); - - /* - // 共享的note也放在Note的cache一份 - if(isShared) { - note.IsShared = true; // 注明是共享的 - } - - // 不清空 - // 之前是addNoteCache, 如果是搜索出的, 会把内容都重置了 - Note.setNoteCache(note, false); - - // 如果是共享的笔记本, 缓存也放在Share下 - if(isShared) { - Share.setCache(note); - } - */ - } -} - -// 新建一个笔记 -// 要切换到当前的notebook下去新建笔记 -// isShare时fromUserId才有用 -// 3.8 add isMarkdown -Note.newNote = function(notebookId, isShare, fromUserId, isMarkdown) { - // 切换编辑器 - switchEditor(isMarkdown); - Note.hideEditorMask(); - - // 防止从共享read only跳到添加 - Note.hideReadOnly(); - - Note.stopInterval(); - // 保存当前的笔记 - Note.curChangedSaveIt(); - - var note = {NoteId: getObjectId(), Title: "", Tags:[], Content:"", NotebookId: notebookId, IsNew: true, FromUserId: fromUserId, IsMarkdown: isMarkdown}; // 是新的 - // 添加到缓存中 - Note.addNoteCache(note); - - // 清空附件数 - Attach.clearNoteAttachNum(); - - // 是否是为共享的notebook添加笔记, 如果是, 则还要记录fromUserId - var newItem = ""; - - var baseClasses = "item-my"; - if(isShare) { - baseClasses = "item-shared"; - } - - var notebook = Notebook.getNotebook(notebookId); - var notebookTitle = notebook ? notebook.Title : ""; - var curDate = getCurDate(); - if(isShare) { - newItem = tt(Note.newItemTpl, baseClasses, fromUserId, note.NoteId, note.Title, notebookTitle, curDate, ""); - } else { - newItem = tt(Note.newItemTpl, baseClasses, "", note.NoteId, note.Title, notebookTitle, curDate, ""); - } - - // notebook是否是Blog - if(!notebook.IsBlog) { - newItem = $(newItem); - newItem.find(".item-blog").hide(); - } - - // 是否在当前notebook下, 不是则切换过去, 并得到该notebook下所有的notes, 追加到后面! - if(!Notebook.isCurNotebook(notebookId)) { - // 先清空所有 - Note.clearAll(); - - // 插入到第一个位置 - Note.noteItemListO.prepend(newItem); - - // 改变为当前的notebookId - // 会得到该notebookId的其它笔记 - if(!isShare) { - Notebook.changeNotebookForNewNote(notebookId); - } else { - Share.changeNotebookForNewNote(notebookId); - } - } else { - // 插入到第一个位置 - Note.noteItemListO.prepend(newItem); - } - - Note.selectTarget($(tt('[noteId="?"]', note.NoteId))); - - $("#noteTitle").focus(); - - Note.renderNote(note); - Note.renderNoteContent(note); - Note.curNoteId = note.NoteId; - - // 更新数量 - Notebook.incrNotebookNumberNotes(notebookId) -} - -// 保存note ctrl + s -Note.saveNote = function(e) { - var num = e.which ? e.which : e.keyCode; - // 保存 - if((e.ctrlKey || e.metaKey) && num == 83 ) { // ctrl + s or command + s - Note.curChangedSaveIt(); - e.preventDefault(); - return false; - } else { - } -}; - -// 删除或移动笔记后, 渲染下一个或上一个 -Note.changeToNext = function(target) { - var $target = $(target); - var next = $target.next(); - if(!next.length) { - var prev = $target.prev(); - if(prev.length) { - next = prev; - } else { - // 就它一个 - Note.showEditorMask(); - return; - } - } - - Note.changeNote(next.attr("noteId")); -} - -// 删除笔记 -// 1. 先隐藏, 成功后再移除DOM -// 2. ajax之 noteId -// Share.deleteSharedNote调用 -Note.deleteNote = function(target, contextmenuItem, isShared) { - // 如果删除的是已选中的, 赶紧设置curNoteId = null - if($(target).hasClass("item-active")) { - // -1 停止定时器 - Note.stopInterval(); - // 不保存 - Note.curNoteId = null; - // 清空信息 - Note.clearNoteInfo(); - } - - noteId = $(target).attr("noteId"); - if(!noteId) { - return; - } - // 1 - $(target).hide(); - - // 2 - var note = Note.cache[noteId]; - var url = "/note/deleteNote" - if(note.IsTrash) { - url = "/note/deleteTrash"; - } else { - // 减少数量 - Notebook.minusNotebookNumberNotes(note.NotebookId); - } - - ajaxGet(url, {noteId: noteId, userId: note.UserId, isShared: isShared}, function(ret) { - if(ret) { - Note.changeToNext(target); - - $(target).remove(); - - // 删除缓存 - if(note) { - Note.clearCacheByNotebookId(note.NotebookId) - delete Note.cache[noteId] - } - - showMsg("删除成功!", 500); - } else { - // 弹出信息 popup 不用点确认的 - $(target).show(); - showMsg("删除失败!", 2000); - } - }); - -} - -// 显示共享信息 -Note.listNoteShareUserInfo = function(target) { - var noteId = $(target).attr("noteId"); - showDialogRemote("share/listNoteShareUserInfo", {noteId: noteId}); -} - -// 共享笔记 -Note.shareNote = function(target) { - var title = $(target).find(".item-title").text(); - showDialog("dialogShareNote", {title: getMsg("shareToFriends") + "-" + title}); - - setTimeout(function() { - $("#friendsEmail").focus(); - }, 500); - - var noteId = $(target).attr("noteId"); - shareNoteOrNotebook(noteId, true); -} - -// 历史记录 -Note.listNoteContentHistories = function() { - // 弹框 - $("#leanoteDialog #modalTitle").html(getMsg("history")); - $content = $("#leanoteDialog .modal-body"); - $content.html(""); - $("#leanoteDialog .modal-footer").html(''); - options = {} - options.show = true; - $("#leanoteDialog").modal(options); - - ajaxGet("noteContentHistory/listHistories", {noteId: Note.curNoteId}, function(re) { - if(!isArray(re)) {$content.html(getMsg("noHistories")); return} - // 组装成一个tab - var str = "

    " + getMsg("historiesNum") + '

    '; - note = Note.cache[Note.curNoteId]; - var s = "div" - if(note.IsMarkdown) { - s = "pre"; - } - for (i in re) { - var content = re[i] - content.Ab = Note.genAbstract(content.Content, 200); - str += tt('', i, (+i+1), s, content.Ab, s, goNowToDatetime(content.UpdatedTime)) - } - str += "
    #??
    ' + getMsg("datetime") + ': ?
    "; - $content.html(str); - $("#historyList .all").click(function() { - $p = $(this).parent().parent(); - var seq = $p.attr("seq"); - var $c = $p.find(".each-content"); - var info = re[seq]; - if(!info.unfold) { // 默认是折叠的 - $(this).text(getMsg("fold")); // 折叠 - $c.html(info.Content); - info.unfold = true; - } else { - $(this).text(getMsg("unfold")); // 展开 - $c.html(info.Ab); - info.unfold = false - } - }); - - // 还原 - $("#historyList .back").click(function() { - $p = $(this).parent().parent(); - var seq = $p.attr("seq"); - if(confirm(getMsg("confirmBackup"))) { - // 保存当前版本 - Note.curChangedSaveIt(); - // 设置之 - note = Note.cache[Note.curNoteId]; - setEditorContent(re[seq].Content, note.IsMarkdown); - // - hideDialog(); - } - }); - - }); -} - -// 长微博 -Note.html2Image = function(target) { - var noteId = $(target).attr("noteId"); - showDialog("html2ImageDialog", {title: "分享到社区", postShow: function() { - ajaxGet("/note/html2Image", {noteId: noteId}, function(ret) { - if (typeof ret == "object" && ret.Ok) { - $("#leanoteDialog .weibo span").html("生成成功, 右键图片保存到本地.") - $("#leanoteDialog .weibo img").attr("src", ret.Id + "?" + ((new Date()).getTime())); - $("#leanoteDialog .btn-share").removeClass("disabled"); - var note = Note.cache[noteId]; - var pic = UrlPrefix + ret.Id; - var title = encodeURI(note.Title + " (" + UserInfo.Username + "分享. 来自leanote.com)"); - var windowParam = 'width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no'; - $("#leanoteDialog .sendWeiboBtn").click(function() { - var url = "http://service.weibo.com/share/share.php?title=" + title; - url += "&pic=" + pic; - window.open(url, '分享到新浪微博', windowParam); - }); - $("#leanoteDialog .sendTxWeiboBtn").click(function() { - var _appkey = '801542571'; - var url = "http://share.v.t.qq.com/index.php?c=share&a=index&appkey=" + _appkey +"&title=" + title +"&url=&pic=" + pic - window.open(url, '分享到腾讯微博', windowParam); - }); - $("#leanoteDialog .sendQQBtn").click(function() { - var url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + UrlPrefix + '&title=' + title + '&pics=' + pic; - window.open(url, '分享QQ空间', windowParam); - }); - $("#leanoteDialog .sendRRBtn").click(function() { - var url = 'http://widget.renren.com/dialog/share?resourceUrl=' + UrlPrefix + '&srcUrl=' + UrlPrefix + '&title=' + title + '&pic=' + pic; - window.open(url, '分享人人网', windowParam); - }); - } else { - $("#leanoteDialog .weibo").html("对不起, 我们出错了!") - } - }); - }}); -} - -//-------------- -// read only - -Note.showReadOnly = function() { - Note.isReadOnly = true; - $("#noteRead").show(); -} -Note.hideReadOnly = function() { - Note.isReadOnly = false; - $("#noteRead").hide(); -} -// read only -Note.renderNoteReadOnly = function(note) { - Note.showReadOnly(); - $("#noteReadTitle").html(note.Title); - - Tag.renderReadOnlyTags(note.Tags); - - $("#noteReadCreatedTime").html(goNowToDatetime(note.CreatedTime)); - $("#noteReadUpdatedTime").html(goNowToDatetime(note.UpdatedTime)); -} -Note.renderNoteContentReadOnly = function(note) { - if(note.IsMarkdown) { - $("#noteReadContent").html('
    ' + note.Content + "
    "); - } else { - $("#noteReadContent").html(note.Content); - } -} - -//--------------------------- -// 搜索 -// 有点小复杂, 因为速度过快会导致没加载完, 然后就保存上一个 => 致使标题没有 -// 为什么会标题没有? -Note.lastSearch = null; -Note.lastKey = null; // 判断是否与上一个相等, 相等就不查询, 如果是等了很久再按enter? -Note.lastSearchTime = new Date(); -Note.isOver2Seconds = false; -Note.isSameSearch = function(key) { - // 判断时间是否超过了1秒, 超过了就认为是不同的 - var now = new Date(); - var duration = now.getTime() - Note.lastSearchTime.getTime(); - Note.isOver2Seconds = duration > 2000 ? true : false; - if(!Note.lastKey || Note.lastKey != key || duration > 1000) { - Note.lastKey = key; - Note.lastSearchTime = now; - return false; - } - - if(key == Note.lastKey) { - return true; - } - - Note.lastSearchTime = now; - Note.lastKey = key; - return false; -} - -Note.searchNote = function() { - var val = $("#searchNoteInput").val(); - if(!val) { - // 定位到all - Notebook.changeNotebook("0"); - return; - } - // 判断是否与上一个是相同的搜索, 是则不搜索 - if(Note.isSameSearch(val)) { - return; - } - - // 之前有, 还有结束的 - if(Note.lastSearch) { - Note.lastSearch.abort(); - } - - // 步骤与tag的搜索一样 - // 1 - Note.curChangedSaveIt(); - - // 2 先清空所有 - Note.clearAll(); - - // 发送请求之 - // 先取消上一个 - showLoading(); - Note.lastSearch = $.post("/note/searchNote", {key: val}, function(notes) { - hideLoading(); - if(notes) { - // 成功后设为空 - Note.lastSearch = null; - // renderNotes只是note列表加载, 右侧笔记详情还没加载 - // 这个时候, 定位第一个, 保存之前的, - // 如果: 第一次搜索, renderNotes OK, 还没等到changeNote时 - // 第二次搜索来到, Note.curChangedSaveIt(); - // 导致没有标题了 - // 不是这个原因, 下面的Note.changeNote会导致保存 - - // 设空, 防止发生上述情况 - // Note.curNoteId = ""; - - Note.renderNotes(notes); - if(!isEmpty(notes)) { - Note.changeNote(notes[0].NoteId, false/*, true || Note.isOver2Seconds*/); // isShare, needSaveChanged?, 超过2秒就要保存 - } - } else { - // abort的 - } - }); - // Note.lastSearch.abort(); -} - -//---------- -//设为blog/unset -Note.setNote2Blog = function(target) { - var noteId = $(target).attr("noteId"); - var note = Note.cache[noteId]; - var isBlog = true; - if(note.IsBlog != undefined) { - isBlog = !note.IsBlog; - } - // 标志添加/去掉 - if(isBlog) { - $(target).find(".item-blog").show(); - } else { - $(target).find(".item-blog").hide(); - } - ajaxPost("/blog/setNote2Blog", {noteId: noteId, isBlog: isBlog}, function(ret) { - if(ret) { - Note.setNoteCache({NoteId: noteId, IsBlog: isBlog}, false); // 不清空NotesByNotebookId缓存 - } - }); -} - -// 设置notebook的blog状态 -// 当修改notebook是否是blog时调用 -Note.setAllNoteBlogStatus = function(notebookId, isBlog) { - if(!notebookId) { - return; - } - var notes = Note.getNotesByNotebookId(notebookId); - if(!isArray(notes)) { - return; - } - var len = notes.length; - if(len == 0) { - for(var i in Note.cache) { - if(Note.cache[i].NotebookId == notebookId) { - Note.cache[i].IsBlog = isBlog; - } - } - } else { - for(var i = 0; i < len; ++i) { - notes[i].IsBlog = isBlog; - } - } -} - -// 移动 -Note.moveNote = function(target, data) { - var noteId = $(target).attr("noteId"); - var note = Note.cache[noteId]; - var notebookId = data.notebookId; - - if(!note.IsTrash && note.NotebookId == notebookId) { - return; - } - - // 修改数量 - Notebook.incrNotebookNumberNotes(notebookId); - if(!note.IsTrash) { - Notebook.minusNotebookNumberNotes(note.NotebookId); - } - - ajaxGet("/note/moveNote", {noteId: noteId, notebookId: notebookId}, function(ret) { - if(ret && ret.NoteId) { - if(note.IsTrash) { - Note.changeToNext(target); - $(target).remove(); - Note.clearCacheByNotebookId(notebookId); - } else { - // 不是trash, 移动, 那么判断是当前是否是all下 - // 不在all下, 就删除之 - // 如果当前是active, 那么clearNoteInfo之 - if(!Notebook.curActiveNotebookIsAll()) { - Note.changeToNext(target); - if($(target).hasClass("item-active")) { - Note.clearNoteInfo(); - } - $(target).remove(); - } else { - // 不移动, 那么要改变其notebook title - $(target).find(".note-notebook").html(Notebook.getNotebookTitle(notebookId)); - } - - // 重新清空cache 之前的和之后的 - Note.clearCacheByNotebookId(note.NotebookId); - Note.clearCacheByNotebookId(notebookId); - } - - // 改变缓存 - Note.setNoteCache(ret) - } - }); -} - -// 复制 -// data是自动传来的, 是contextmenu数据 -Note.copyNote = function(target, data, isShared) { - var noteId = $(target).attr("noteId"); - var note = Note.cache[noteId]; - var notebookId = data.notebookId; - - // trash不能复制, 不能复制给自己 - if(note.IsTrash || note.NotebookId == notebookId) { - return; - } - - var url = "/note/copyNote"; - var data = {noteId: noteId, notebookId: notebookId}; - if(isShared) { - url = "/note/copySharedNote"; - data.fromUserId = note.UserId; - } - - ajaxGet(url, data, function(ret) { - if(ret && ret.NoteId) { - // 重新清空cache 之后的 - Note.clearCacheByNotebookId(notebookId); - // 改变缓存, 添加之 - Note.setNoteCache(ret) - } - }); - - // 增加数量 - Notebook.incrNotebookNumberNotes(notebookId) -} - -// 这里速度不慢, 很快 -Note.getContextNotebooks = function(notebooks) { - var moves = []; - var copys = []; - var copys2 = []; - for(var i in notebooks) { - var notebook = notebooks[i]; - var move = {text: notebook.Title, notebookId: notebook.NotebookId, action: Note.moveNote} - var copy = {text: notebook.Title, notebookId: notebook.NotebookId, action: Note.copyNote} - var copy2 = {text: notebook.Title, notebookId: notebook.NotebookId, action: Share.copySharedNote} - if(!isEmpty(notebook.Subs)) { - var mc = Note.getContextNotebooks(notebook.Subs); - move.items = mc[0]; - copy.items = mc[1]; - copy2.items = mc[2]; - move.type = "group"; - move.width = 150; - copy.type = "group"; - copy.width = 150; - copy2.type = "group"; - copy2.width = 150; - } - moves.push(move); - copys.push(copy); - copys2.push(copy2); - } - return [moves, copys, copys2]; -} -// Notebook调用 -Note.contextmenu = null; -Note.notebooksCopy = []; // share会用到 -Note.initContextmenu = function() { - var self = Note; - if(Note.contextmenu) { - Note.contextmenu.destroy(); - } - // 得到可移动的notebook - var notebooks = Notebook.everNotebooks; - var mc = self.getContextNotebooks(notebooks); - - var notebooksMove = mc[0]; - var notebooksCopy = mc[1]; - self.notebooksCopy = mc[2]; - - //--------------------- - // context menu - //--------------------- - var noteListMenu = { - width: 180, - items: [ - { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Note.listNoteShareUserInfo}, - { type: "splitLine" }, - { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Note.setNote2Blog }, - { text: getMsg("cancelPublic"), alias: 'unset2Blog', faIcon: "fa-undo", action: Note.setNote2Blog }, - //{ type: "splitLine" }, - //{ text: "分享到社区", alias: 'html2Image', icon: "", action: Note.html2Image}, - { type: "splitLine" }, - { text: getMsg("delete"), icon: "", faIcon: "fa-trash-o", action: Note.deleteNote }, - { text: getMsg("move"), alias: "move", faIcon: "fa-arrow-right", - type: "group", - width: 180, - items: notebooksMove - }, - { text: getMsg("copy"), alias: "copy", icon:"", faIcon: "fa-copy", - type: "group", - width: 180, - items: notebooksCopy - } - ], - onShow: applyrule, - onContextMenu: beforeContextMenu, - - parent: "#noteItemList", - children: ".item-my", - } - - function menuAction(target) { - // $('#myModal').modal('show') - showDialog("dialogUpdateNotebook", {title: "修改笔记本", postShow: function() { - }}); - } - function applyrule(menu) { - var noteId = $(this).attr("noteId"); - var note = Note.cache[noteId]; - if(!note) { - return; - } - // 要disable的items - var items = []; - - // 如果是trash, 什么都不能做 - if(note.IsTrash) { - items.push("shareToFriends"); - items.push("shareStatus"); - items.push("unset2Blog"); - items.push("set2Blog"); - items.push("copy"); - } else { - // 是否已公开为blog - if(!note.IsBlog) { - items.push("unset2Blog"); - } else { - items.push("set2Blog"); - } - - // 移动与复制不能是本notebook下 - var notebookTitle = Notebook.getNotebookTitle(note.NotebookId); - items.push("move." + notebookTitle); - items.push("copy." + notebookTitle); - } - - menu.applyrule({ - name: "target..", - disable: true, - items: items - }); - - } - function beforeContextMenu() { - return this.id != "target3"; - } - - // 这里很慢!! - Note.contextmenu = $("#noteItemList .item-my").contextmenu(noteListMenu); -} - -// 附件 -// 笔记的附件需要ajax获取 -// 建一张附件表? attachId, noteId, 其它信息 -// note里有attach_nums字段记录个数 -// [ok] -var Attach = { - loadedNoteAttachs: {}, // noteId => [attch1Info, attach2Info...] // 按笔记 - attachsMap: {}, // attachId => attachInfo - init: function() { - var self = this; - // 显示attachs - $("#showAttach").click(function(){ - self.renderAttachs(Note.curNoteId); - }); - // 防止点击隐藏 - self.attachListO.click(function(e) { - e.stopPropagation(); - }); - // 删除 - self.attachListO.on("click", ".delete-attach", function(e) { - e.stopPropagation(); - var attachId = $(this).closest('li').data("id"); - var t = this; - if(confirm("Are you sure to delete it ?")) { - $(t).button("loading"); - ajaxPost("/attach/deleteAttach", {attachId: attachId}, function(re) { - $(t).button("reset"); - if(reIsOk(re)) { - self.deleteAttach(attachId); - } else { - alert(re.Msg); - } - }); - } - }); - // 下载 - self.attachListO.on("click", ".download-attach", function(e) { - e.stopPropagation(); - var attachId = $(this).closest('li').data("id"); - window.open(UrlPrefix + "/attach/download?attachId=" + attachId); - // location.href = "/attach/download?attachId=" + attachId; - }); - // 下载全部 - self.downloadAllBtnO.click(function() { - window.open(UrlPrefix + "/attach/downloadAll?noteId=" + Note.curNoteId); - // location.href = "/attach/downloadAll?noteId=" + Note.curNoteId; - }); - - // make link - self.attachListO.on("click", ".link-attach", function(e) { - e.stopPropagation(); - var attachId = $(this).closest('li').data("id"); - var attach = self.attachsMap[attachId]; - var src = UrlPrefix + "/attach/download?attachId=" + attachId; - if(LEA.isMarkdownEditor() && MarkdownEditor) { - MarkdownEditor.insertLink(src, attach.Title); - } else { - tinymce.activeEditor.insertContent('' + attach.Title + ''); - } - }); - - // make all link - self.linkAllBtnO.on("click",function(e) { - e.stopPropagation(); - var note = Note.getCurNote(); - if(!note) { - return; - } - var src = UrlPrefix + "/attach/downloadAll?noteId=" + Note.curNoteId - var title = note.Title ? note.Title + ".tar.gz" : "all.tar.gz"; - - if(LEA.isMarkdownEditor() && MarkdownEditor) { - MarkdownEditor.insertLink(src, title); - } else { - tinymce.activeEditor.insertContent('' + title + ''); - } - }); - }, - attachListO: $("#attachList"), - attachNumO: $("#attachNum"), - attachDropdownO: $("#attachDropdown"), - downloadAllBtnO: $("#downloadAllBtn"), - linkAllBtnO: $("#linkAllBtn"), - // 添加笔记时 - clearNoteAttachNum: function() { - var self = this; - self.attachNumO.html("").hide(); - }, - renderNoteAttachNum: function(noteId, needHide) { - var self = this; - var note = Note.getNote(noteId); - if(note.AttachNum) { - self.attachNumO.html("(" + note.AttachNum + ")").show(); - self.downloadAllBtnO.show(); - self.linkAllBtnO.show(); - } else { - self.attachNumO.hide(); - self.downloadAllBtnO.hide(); - self.linkAllBtnO.hide(); - } - - // 隐藏掉 - if(needHide) { - self.attachDropdownO.removeClass("open"); - } - }, - _renderAttachs: function(attachs) { - var self = this; - // foreach 循环之 - /* -
  • -
    leanote官abcefedafadfadfadfadfad方文档.doc
    -
    - - -
    -
  • - */ - var html = ""; - var attachNum = attachs.length; - for(var i = 0; i < attachNum; ++i) { - var each = attachs[i]; - html += '
  • ' + - '
    ' + each.Title + '
    ' + - '
    ' + - ' ' + - ' ' + - ' ' + - '
    ' + - '
  • '; - self.attachsMap[each.AttachId] = each; - } - self.attachListO.html(html); - - // 设置数量 - var note = Note.getCurNote(); - if(note) { - note.AttachNum = attachNum; - self.renderNoteAttachNum(note.NoteId, false); - } - }, - // 渲染noteId的附件 - // 当点击"附件"时加载, - // TODO 判断是否已loaded - renderAttachs: function(noteId) { - var self = this; - if(self.loadedNoteAttachs[noteId]) { - self._renderAttachs(self.loadedNoteAttachs[noteId]); - return; - } - // 显示loading - self.attachListO.html('
  • '); - // ajax获取noteAttachs - ajaxGet("/attach/getAttachs", {noteId: noteId}, function(ret) { - var list = []; - if(ret.Ok) { - list = ret.List; - if(!list) { - list = []; - } - } - // 添加到缓存中 - self.loadedNoteAttachs[noteId] = list; - self._renderAttachs(list); - }); - }, - // 添加附件, attachment_upload上传调用 - addAttach: function(attachInfo) { - var self = this; - if(!self.loadedNoteAttachs[attachInfo.NoteId]) { - self.loadedNoteAttachs[attachInfo.NoteId] = []; - } - self.loadedNoteAttachs[attachInfo.NoteId].push(attachInfo); - self.renderAttachs(attachInfo.NoteId); - }, - // 删除 - deleteAttach: function(attachId) { - var self = this; - var noteId = Note.curNoteId; - var attachs = self.loadedNoteAttachs[noteId]; - for(var i = 0; i < attachs.length; ++i) { - if(attachs[i].AttachId == attachId) { - // 删除之, 并render之 - attachs.splice(i, 1); - break; - } - } - // self.loadedNoteAttachs[noteId] = attachs; - self.renderAttachs(noteId); - }, - - // 下载 - downloadAttach: function(fileId) { - var self = this; - }, - downloadAll: function() { - } -} - -//------------------- 事件 -$(function() { - // 附件初始化 - Attach.init(); - - //----------------- - // for list nav - $("#noteItemList").on("click", ".item", function(event) { - log(event); - event.stopPropagation(); - var noteId = $(this).attr("noteId"); - - // 手机端处理 - Mobile.changeNote(noteId); - - if(!noteId) { - return; - } - // 当前的和所选的是一个, 不改变 - if(Note.curNoteId != noteId) { - Note.changeNote(noteId); - } - }); - - //------------------ - // 新建笔记 - // 1. 直接点击新建 OR - // 2. 点击nav for new note - $("#newNoteBtn, #editorMask .note").click(function() { - var notebookId = $("#curNotebookForNewNote").attr('notebookId'); - Note.newNote(notebookId); - }); - $("#newNoteMarkdownBtn, #editorMask .markdown").click(function() { - var notebookId = $("#curNotebookForNewNote").attr('notebookId'); - Note.newNote(notebookId, false, "", true); - }); - $("#notebookNavForNewNote").on("click", "li div", function() { - var notebookId = $(this).attr("notebookId"); - if($(this).hasClass("new-note-right")) { - Note.newNote(notebookId, false, "", true); - } else { - Note.newNote(notebookId); - } - }); - $("#searchNotebookForAdd").click(function(e) { - e.stopPropagation(); - }); - $("#searchNotebookForAdd").keyup(function() { - var key = $(this).val(); - Notebook.searchNotebookForAddNote(key); - }); - $("#searchNotebookForList").keyup(function() { - var key = $(this).val(); - Notebook.searchNotebookForList(key); - }); - - //--------------------------- - // 搜索, 按enter才搜索 - /* - $("#searchNoteInput").on("keyup", function(e) { - Note.searchNote(); - }); - */ - $("#searchNoteInput").on("keydown", function(e) { - var theEvent = e; // window.event || arguments.callee.caller.arguments[0]; - if(theEvent.keyCode == 13 || theEvent.keyCode == 108) { - theEvent.preventDefault(); - Note.searchNote(); - return false; - } - }); - - //-------------------- - // Note.initContextmenu(); - - //------------ - // 文档历史 - $("#contentHistory").click(function() { - Note.listNoteContentHistories() - }); - - $("#saveBtn").click(function() { - Note.curChangedSaveIt(true); - }); - - // blog - $("#noteItemList").on("click", ".item-blog", function(e) { - e.preventDefault(); - e.stopPropagation(); - // 得到ID - var noteId = $(this).parent().attr('noteId'); - window.open("/blog/view/" + noteId); - }); - - // note setting - $("#noteItemList").on("click", ".item-my .item-setting", function(e) { - e.preventDefault(); - e.stopPropagation(); - var $p = $(this).parent(); - Note.contextmenu.showMenu(e, $p); - }); -}); - -// 定时器启动 -Note.startInterval(); \ No newline at end of file diff --git a/public/js/app/notebook-min.js b/public/js/app/notebook-min.js deleted file mode 100644 index 24c8b43..0000000 --- a/public/js/app/notebook-min.js +++ /dev/null @@ -1 +0,0 @@ -Notebook.curNotebookId="";Notebook.cache={};Notebook.notebooks=[];Notebook.notebookNavForListNote="";Notebook.notebookNavForNewNote="";Notebook.setCache=function(notebook){var notebookId=notebook.NotebookId;if(!notebookId){return}if(!Notebook.cache[notebookId]){Notebook.cache[notebookId]={}}$.extend(Notebook.cache[notebookId],notebook)};Notebook.getCurNotebookId=function(){return Notebook.curNotebookId};Notebook._updateNotebookNumberNotes=function(notebookId,n){var self=this;var notebook=self.getNotebook(notebookId);if(!notebook){return}notebook.NumberNotes+=n;if(notebook.NumberNotes<0){notebook.NumberNotes=0}$("#numberNotes_"+notebookId).html(notebook.NumberNotes)};Notebook.incrNotebookNumberNotes=function(notebookId){var self=this;self._updateNotebookNumberNotes(notebookId,1)};Notebook.minusNotebookNumberNotes=function(notebookId){var self=this;self._updateNotebookNumberNotes(notebookId,-1)};Notebook.getNotebook=function(notebookId){return Notebook.cache[notebookId]};Notebook.getNotebookTitle=function(notebookId){var notebook=Notebook.cache[notebookId];if(notebook){return notebook.Title}else{return"未知"}};Notebook.getTreeSetting=function(isSearch,isShare){var noSearch=!isSearch;var self=this;function addDiyDom(treeId,treeNode){var spaceWidth=5;var switchObj=$("#"+treeId+" #"+treeNode.tId+"_switch"),icoObj=$("#"+treeId+" #"+treeNode.tId+"_ico");switchObj.remove();icoObj.before(switchObj);if(!isShare){if(!Notebook.isAllNotebookId(treeNode.NotebookId)&&!Notebook.isTrashNotebookId(treeNode.NotebookId)){icoObj.after($(''+(treeNode.NumberNotes||0)+""));icoObj.after($(''))}}else{if(!Share.isDefaultNotebookId(treeNode.NotebookId)){icoObj.after($(''))}}if(treeNode.level>1){var spaceStr="";switchObj.before(spaceStr)}}function beforeDrag(treeId,treeNodes){for(var i=0,l=treeNodes.length;i
    ?
    M
    ',classes,notebook.NotebookId,notebook.Title,notebook.NotebookId);if(!isEmpty(notebook.Subs)){eachForNew+=""}eachForNew+="";navForNewNote+=eachForNew}return navForNewNote};Notebook.everNavForNewNote="";Notebook.everNotebooks=[];Notebook.changeNav=function(){var self=Notebook;var notebooks=Notebook.tree.getNodes();var pureNotebooks=notebooks.slice(1,-1);var html=self.getChangedNotebooks(pureNotebooks);self.everNavForNewNote=html;self.everNotebooks=pureNotebooks;$("#notebookNavForNewNote").html(html);var t1=(new Date).getTime();Note.initContextmenu();Share.initContextmenu(Note.notebooksCopy);var t2=(new Date).getTime();log(t2-t1)};Notebook.renderShareNotebooks=function(sharedUserInfos,shareNotebooks){if(isEmpty(sharedUserInfos)){return}if(!shareNotebooks||typeof shareNotebooks!="object"||shareNotebooks.length<0){return}var $shareNotebooks=$("#shareNotebooks");var user2ShareNotebooks={};for(var i in shareNotebooks){var userNotebooks=shareNotebooks[i];user2ShareNotebooks[userNotebooks.UserId]=userNotebooks}for(var i in sharedUserInfos){var userInfo=sharedUserInfos[i];var userNotebooks=user2ShareNotebooks[userInfo.UserId]||{ShareNotebooks:[]};userNotebooks.ShareNotebooks=[{NotebookId:"-2",Title:"默认共享"}].concat(userNotebooks.ShareNotebooks);var username=userInfo.Username||userInfo.Email;var header=tt('
    ',username,username);var body='
      ';for(var j in userNotebooks.ShareNotebooks){var notebook=userNotebooks.ShareNotebooks[j];body+=tt('
    • ?
    • ',notebook.NotebookId,notebook.Title)}body+="
    ";$shareNotebooks.append(header+body+"
    ")}};Notebook.selectNotebook=function(target){$(".notebook-item").removeClass("curSelectedNode");$(target).addClass("curSelectedNode")};Notebook.changeNotebookNavForNewNote=function(notebookId,title){if(!notebookId){var notebook=Notebook.notebooks[0];notebookId=notebook.NotebookId;title=notebook.Title}if(!title){var notebook=Notebook.cache[0];title=notebook.Title}if(!Notebook.isAllNotebookId(notebookId)&&!Notebook.isTrashNotebookId(notebookId)){$("#curNotebookForNewNote").html(title).attr("notebookId",notebookId)}else if(!$("#curNotebookForNewNote").attr("notebookId")){if(Notebook.notebooks.length>2){var notebook=Notebook.notebooks[1];notebookId=notebook.NotebookId;title=notebook.Title;Notebook.changeNotebookNavForNewNote(notebookId,title)}}};Notebook.toggleToMyNav=function(userId,notebookId){$("#sharedNotebookNavForListNav").hide();$("#myNotebookNavForListNav").show();$("#newMyNote").show();$("#newSharedNote").hide();$("#tagSearch").hide()};Notebook.changeNotebookNav=function(notebookId){Notebook.toggleToMyNav();Notebook.selectNotebook($(tt('#notebookList [notebookId="?"]',notebookId)));var notebook=Notebook.cache[notebookId];if(!notebook){return}$("#curNotebookForListNote").html(notebook.Title);Notebook.changeNotebookNavForNewNote(notebookId,notebook.Title)};Notebook.isAllNotebookId=function(notebookId){return notebookId==Notebook.allNotebookId};Notebook.isTrashNotebookId=function(notebookId){return notebookId==Notebook.trashNotebookId};Notebook.curActiveNotebookIsAll=function(){return Notebook.isAllNotebookId($("#notebookList .active").attr("notebookId"))};Notebook.changeNotebook=function(notebookId){Notebook.changeNotebookNav(notebookId);Notebook.curNotebookId=notebookId;Note.curChangedSaveIt();Note.clearAll();var url="/note/ListNotes/";var param={notebookId:notebookId};if(Notebook.isTrashNotebookId(notebookId)){url="/note/listTrashNotes";param={}}else if(Notebook.isAllNotebookId(notebookId)){param={};cacheNotes=Note.getNotesByNotebookId();if(!isEmpty(cacheNotes)){Note.renderNotesAndFirstOneContent(cacheNotes);return}}else{cacheNotes=Note.getNotesByNotebookId(notebookId);if(!isEmpty(cacheNotes)){Note.renderNotesAndFirstOneContent(cacheNotes);return}}ajaxGet(url,param,Note.renderNotesAndFirstOneContent)};Notebook.isCurNotebook=function(notebookId){return $(tt('#notebookList [notebookId="?"], #shareNotebooks [notebookId="?"]',notebookId,notebookId)).attr("class")=="active"};Notebook.changeNotebookForNewNote=function(notebookId){if(Notebook.isTrashNotebookId(notebookId)||Notebook.isAllNotebookId(notebookId)){return}Notebook.changeNotebookNav(notebookId);Notebook.curNotebookId=notebookId;var url="/note/ListNotes/";var param={notebookId:notebookId};ajaxGet(url,param,function(ret){Note.renderNotes(ret,true)})};Notebook.listNotebookShareUserInfo=function(target){var notebookId=$(target).attr("notebookId");showDialogRemote("share/listNotebookShareUserInfo",{notebookId:notebookId})};Notebook.shareNotebooks=function(target){var title=$(target).text();showDialog("dialogShareNote",{title:"分享笔记本给好友-"+title});setTimeout(function(){$("#friendsEmail").focus()},500);var notebookId=$(target).attr("notebookId");shareNoteOrNotebook(notebookId,false)};Notebook.setNotebook2Blog=function(target){var notebookId=$(target).attr("notebookId");var notebook=Notebook.cache[notebookId];var isBlog=true;if(notebook.IsBlog!=undefined){isBlog=!notebook.IsBlog}if(Notebook.curNotebookId==notebookId){if(isBlog){$("#noteList .item-blog").show()}else{$("#noteList .item-blog").hide()}}else if(Notebook.curNotebookId==Notebook.allNotebookId){$("#noteItemList .item").each(function(){var noteId=$(this).attr("noteId");var note=Note.cache[noteId];if(note.NotebookId==notebookId){if(isBlog)$(this).find(".item-blog").show();else $(this).find(".item-blog").hide()}})}ajaxPost("blog/setNotebook2Blog",{notebookId:notebookId,isBlog:isBlog},function(ret){if(ret){Note.setAllNoteBlogStatus(notebookId,isBlog);Notebook.setCache({NotebookId:notebookId,IsBlog:isBlog})}})};Notebook.updateNotebookTitle=function(target){var self=Notebook;var notebookId=$(target).attr("notebookId");if(self.tree2){self.tree2.editName(self.tree2.getNodeByTId(notebookId))}else{self.tree.editName(self.tree.getNodeByTId(notebookId))}};Notebook.doUpdateNotebookTitle=function(notebookId,newTitle){var self=Notebook;ajaxPost("/notebook/updateNotebookTitle",{notebookId:notebookId,title:newTitle},function(ret){Notebook.cache[notebookId].Title=newTitle;Notebook.changeNav();if(self.tree2){var notebook=self.tree.getNodeByTId(notebookId);notebook.Title=newTitle;self.tree.updateNode(notebook)}})};Notebook.addNotebookSeq=1;Notebook.addNotebook=function(){var self=Notebook;if($("#myNotebooks").hasClass("closed")){$("#myNotebooks .folderHeader").trigger("click")}self.tree.addNodes(null,{Title:"",NotebookId:getObjectId(),IsNew:true},true,true)};Notebook.doAddNotebook=function(notebookId,title,parentNotebookId){var self=Notebook;ajaxPost("/notebook/addNotebook",{notebookId:notebookId,title:title,parentNotebookId:parentNotebookId},function(ret){if(ret.NotebookId){Notebook.cache[ret.NotebookId]=ret;var notebook=self.tree.getNodeByTId(notebookId);$.extend(notebook,ret);notebook.IsNew=false;Notebook.changeNotebook(notebookId);Notebook.changeNav()}})};Notebook.addChildNotebook=function(target){var self=Notebook;if($("#myNotebooks").hasClass("closed")){$("#myNotebooks .folderHeader").trigger("click")}var notebookId=$(target).attr("notebookId");self.tree.addNodes(self.tree.getNodeByTId(notebookId),{Title:"",NotebookId:getObjectId(),IsNew:true},false,true)};Notebook.deleteNotebook=function(target){var self=Notebook;var notebookId=$(target).attr("notebookId");if(!notebookId){return}ajaxGet("/notebook/deleteNotebook",{notebookId:notebookId},function(ret){if(ret.Ok){self.tree.removeNode(self.tree.getNodeByTId(notebookId));if(self.tree2){self.tree2.removeNode(self.tree2.getNodeByTId(notebookId))}delete Notebook.cache[notebookId];Notebook.changeNav()}else{alert(ret.Msg)}})};$(function(){$("#minNotebookList").on("click","li",function(){var notebookId=$(this).find("a").attr("notebookId");Notebook.changeNotebook(notebookId)});var notebookListMenu={width:180,items:[{text:getMsg("shareToFriends"),alias:"shareToFriends",icon:"",faIcon:"fa-share-square-o",action:Notebook.listNotebookShareUserInfo},{type:"splitLine"},{text:getMsg("publicAsBlog"),alias:"set2Blog",faIcon:"fa-bold",action:Notebook.setNotebook2Blog},{text:getMsg("cancelPublic"),alias:"unset2Blog",faIcon:"fa-undo",action:Notebook.setNotebook2Blog},{type:"splitLine"},{text:getMsg("addChildNotebook"),faIcon:"fa-sitemap",action:Notebook.addChildNotebook},{text:getMsg("rename"),faIcon:"fa-pencil",action:Notebook.updateNotebookTitle},{text:getMsg("delete"),icon:"",alias:"delete",faIcon:"fa-trash-o",action:Notebook.deleteNotebook}],onShow:applyrule,onContextMenu:beforeContextMenu,parent:"#notebookList ",children:"li a"};var notebookListMenu2={width:180,items:[{text:getMsg("shareToFriends"),alias:"shareToFriends",icon:"",faIcon:"fa-share-square-o",action:Notebook.listNotebookShareUserInfo},{type:"splitLine"},{text:getMsg("publicAsBlog"),alias:"set2Blog",faIcon:"fa-bold",action:Notebook.setNotebook2Blog},{text:getMsg("cancelPublic"),alias:"unset2Blog",faIcon:"fa-undo",action:Notebook.setNotebook2Blog},{type:"splitLine"},{text:getMsg("rename"),icon:"",action:Notebook.updateNotebookTitle},{text:getMsg("delete"),icon:"",alias:"delete",faIcon:"fa-trash-o",action:Notebook.deleteNotebook}],onShow:applyrule,onContextMenu:beforeContextMenu,parent:"#notebookListForSearch ",children:"li a"};function applyrule(menu){var notebookId=$(this).attr("notebookId");var notebook=Notebook.cache[notebookId];if(!notebook){return}var items=[];if(!notebook.IsBlog){items.push("unset2Blog")}else{items.push("set2Blog")}if(Note.notebookHasNotes(notebookId)){items.push("delete")}menu.applyrule({name:"target2",disable:true,items:items})}function beforeContextMenu(){var notebookId=$(this).attr("notebookId");return!Notebook.isTrashNotebookId(notebookId)&&!Notebook.isAllNotebookId(notebookId)}Notebook.contextmenu=$("#notebookList li a").contextmenu(notebookListMenu);Notebook.contextmenuSearch=$("#notebookListForSearch li a").contextmenu(notebookListMenu2);$("#addNotebookPlus").click(function(e){e.stopPropagation();Notebook.addNotebook()});$("#notebookList").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();Notebook.contextmenu.showMenu(e,$p)});$("#notebookListForSearch").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();Notebook.contextmenuSearch.showMenu(e,$p)})}); \ No newline at end of file diff --git a/public/js/app/notebook.js b/public/js/app/notebook.js deleted file mode 100644 index 36bd343..0000000 --- a/public/js/app/notebook.js +++ /dev/null @@ -1,888 +0,0 @@ -Notebook.curNotebookId = ""; -Notebook.cache = {}; // notebookId => {}; -Notebook.notebooks = []; // 按次序 -//
  • CSS
  • -Notebook.notebookNavForListNote = ""; // html 为了note list上面和新建时的ul -Notebook.notebookNavForNewNote = ""; // html 为了note list上面和新建时的ul - -// 设置缓存 -Notebook.setCache = function(notebook) { - var notebookId = notebook.NotebookId; - if(!notebookId) { - return; - } - if(!Notebook.cache[notebookId]) { - Notebook.cache[notebookId] = {}; - } - $.extend(Notebook.cache[notebookId], notebook); -} - -Notebook.getCurNotebookId = function() { - return Notebook.curNotebookId; -}; - -// 笔记本的笔记数量更新 -Notebook._updateNotebookNumberNotes = function(notebookId, n) { - var self = this; - var notebook = self.getNotebook(notebookId); - if(!notebook) { - return; - } - notebook.NumberNotes += n; - if(notebook.NumberNotes < 0) { - notebook.NumberNotes = 0; - } - $("#numberNotes_" + notebookId).html(notebook.NumberNotes); -}; -// addNote, copyNote, moveNote -Notebook.incrNotebookNumberNotes = function(notebookId) { - var self = this; - self._updateNotebookNumberNotes(notebookId, 1); -}; -// moteNote, deleteNote -Notebook.minusNotebookNumberNotes = function(notebookId) { - var self = this; - self._updateNotebookNumberNotes(notebookId, -1); -}; - -// 得到notebook标题, 给note显示其notebook标题用 -// called by Note -Notebook.getNotebook = function(notebookId) { - return Notebook.cache[notebookId]; -} -// called by Note -Notebook.getNotebookTitle = function(notebookId) { - var notebook = Notebook.cache[notebookId]; - if(notebook) { - return notebook.Title; - } else { - return "未知"; - } -} - -/** - * 我的notebooks - - */ - -Notebook.getTreeSetting = function(isSearch, isShare){ - var noSearch = !isSearch; - - var self = this; - // 添加自定义dom - function addDiyDom(treeId, treeNode) { - var spaceWidth = 5; - var switchObj = $("#" + treeId + " #" + treeNode.tId + "_switch"), - icoObj = $("#" + treeId + " #" + treeNode.tId + "_ico"); - switchObj.remove(); - icoObj.before(switchObj); - if(!isShare) { - if(!Notebook.isAllNotebookId(treeNode.NotebookId) && !Notebook.isTrashNotebookId(treeNode.NotebookId)) { - icoObj.after($('' + (treeNode.NumberNotes || 0) + '')); - icoObj.after($('')); - } - } else { - if(!Share.isDefaultNotebookId(treeNode.NotebookId)) { - icoObj.after($('')); - } - } - if (treeNode.level > 1) { - var spaceStr = ""; - switchObj.before(spaceStr); - } - } - // 拖拽 - function beforeDrag(treeId, treeNodes) { - for (var i=0,l=treeNodes.length; i
    ?
    M
    ', classes, notebook.NotebookId, notebook.Title, notebook.NotebookId); - - if(!isEmpty(notebook.Subs)) { - eachForNew += ""; - } - - eachForNew += ''; - - navForNewNote += eachForNew; - } - return navForNewNote; -} - -Notebook.everNavForNewNote = ""; -Notebook.everNotebooks = []; -Notebook.changeNav = function() { - var self = Notebook; - var notebooks = Notebook.tree.getNodes(); - var pureNotebooks = notebooks.slice(1, -1); // 不含新和垃圾 - var html = self.getChangedNotebooks(pureNotebooks); - - self.everNavForNewNote = html; - self.everNotebooks = pureNotebooks; - - $("#notebookNavForNewNote").html(html); - - // 移动, 复制重新来, 因为nav变了, 移动至-----的notebook导航也变了 - // 这里速度很慢 - var t1 = (new Date()).getTime(); - Note.initContextmenu(); - Share.initContextmenu(Note.notebooksCopy); - var t2 = (new Date()).getTime(); - log(t2-t1); -} - -/** - * 我的共享notebooks -
    - - */ -// TODO 层级 -Notebook.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { - if(isEmpty(sharedUserInfos)) { - return; - } - - if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) { - return; - } - - var $shareNotebooks = $("#shareNotebooks"); - var user2ShareNotebooks = {}; - for(var i in shareNotebooks) { - var userNotebooks = shareNotebooks[i]; - user2ShareNotebooks[userNotebooks.UserId] = userNotebooks; - } - for(var i in sharedUserInfos) { - var userInfo = sharedUserInfos[i]; - var userNotebooks = user2ShareNotebooks[userInfo.UserId] || {ShareNotebooks:[]}; - - userNotebooks.ShareNotebooks = [{NotebookId: "-2", Title: "默认共享"}].concat(userNotebooks.ShareNotebooks) - - var username = userInfo.Username || userInfo.Email; - var header = tt('
    ', username, username); - var body = '
      '; - for(var j in userNotebooks.ShareNotebooks) { - var notebook = userNotebooks.ShareNotebooks[j]; - body += tt('
    • ?
    • ', notebook.NotebookId, notebook.Title) - } - body += "
    "; - - $shareNotebooks.append(header + body + "
    ") - } -} - -// 左侧导航, 选中某个notebook -Notebook.selectNotebook = function(target) { - $(".notebook-item").removeClass("curSelectedNode"); - $(target).addClass("curSelectedNode"); -}; - -// 新建笔记导航 -Notebook.changeNotebookNavForNewNote = function(notebookId, title) { - // 没有notebookId, 则选择第1个notebook - // 第一个是全部笔记 - if(!notebookId) { - var notebook = Notebook.notebooks[0]; - notebookId = notebook.NotebookId; - title = notebook.Title; - } - if(!title) { - var notebook = Notebook.cache[0]; - title = notebook.Title; - } - - if(!Notebook.isAllNotebookId(notebookId) && !Notebook.isTrashNotebookId(notebookId)) { - $("#curNotebookForNewNote").html(title).attr("notebookId", notebookId); - } else if(!$("#curNotebookForNewNote").attr("notebookId")) { - // 但又没有一个笔记, 默认选第一个吧 - // 这里很可能会死循环, 万一用户没有其它笔记呢? - // 服务端肯定要在新建一个用户时给他创建一个默认笔记本的 - if(Notebook.notebooks.length > 2) { - var notebook = Notebook.notebooks[1]; - notebookId = notebook.NotebookId; - title = notebook.Title; - Notebook.changeNotebookNavForNewNote(notebookId, title); - } - } -} - -// 改变导航, 两处 -// 单击左侧, 单击新建下拉时调用 -// 1 选中左侧导航, -// 2 notelist上面 > -// 3 新建笔记 - js > -// 转成我的nav <-> 共享 -Notebook.toggleToMyNav = function(userId, notebookId) { - $("#sharedNotebookNavForListNav").hide(); - $("#myNotebookNavForListNav").show(); - - $("#newMyNote").show(); - $("#newSharedNote").hide(); - - // 搜索tag隐藏 - $("#tagSearch").hide(); -} -Notebook.changeNotebookNav = function(notebookId) { - Notebook.toggleToMyNav(); - - // 1 - Notebook.selectNotebook($(tt('#notebookList [notebookId="?"]', notebookId))); - - var notebook = Notebook.cache[notebookId]; - - if(!notebook) { - return; - } - - // 2 - $("#curNotebookForListNote").html(notebook.Title); - - // 3 - Notebook.changeNotebookNavForNewNote(notebookId, notebook.Title); -} - -Notebook.isAllNotebookId = function(notebookId) { - return notebookId == Notebook.allNotebookId; -} -Notebook.isTrashNotebookId = function(notebookId) { - return notebookId == Notebook.trashNotebookId; -} -// 当前选中的笔记本是否是"所有" -// called by Note -Notebook.curActiveNotebookIsAll = function() { - return Notebook.isAllNotebookId($("#notebookList .active").attr("notebookId")); -} - -// 改变笔记本 -// 0. 改变样式 -// 1. 改变note, 此时需要先保存 -// 2. ajax得到该notebook下的所有note -// 3. 使用Note.RederNotes() -Notebook.changeNotebook = function(notebookId) { - Notebook.changeNotebookNav(notebookId); - - Notebook.curNotebookId = notebookId; - - // 1 - Note.curChangedSaveIt(); - - // 2 先清空所有 - Note.clearAll(); - - var url = "/note/ListNotes/"; - var param = {notebookId: notebookId}; - - // 废纸篓 - if(Notebook.isTrashNotebookId(notebookId)) { - url = "/note/listTrashNotes"; - param = {}; - } else if(Notebook.isAllNotebookId(notebookId)) { - param = {}; - // 得到全部的... - cacheNotes = Note.getNotesByNotebookId(); - if(!isEmpty(cacheNotes)) { // 万一真的是没有呢? - Note.renderNotesAndFirstOneContent(cacheNotes); - return; - } - } else { - cacheNotes = Note.getNotesByNotebookId(notebookId); - if(!isEmpty(cacheNotes)) { // 万一真的是没有呢? - Note.renderNotesAndFirstOneContent(cacheNotes); - return; - } - } - - // 2 得到笔记本 - // 这里可以缓存起来, note按notebookId缓存 - ajaxGet(url, param, Note.renderNotesAndFirstOneContent); -} - -// 是否是当前选中的notebookId -// 还包括共享 -// called by Note -Notebook.isCurNotebook = function(notebookId) { - return $(tt('#notebookList [notebookId="?"], #shareNotebooks [notebookId="?"]', notebookId, notebookId)).attr("class") == "active"; -} - -// 改变nav, 为了新建note -// called by Note -Notebook.changeNotebookForNewNote = function(notebookId) { - // 废纸篓 - if(Notebook.isTrashNotebookId(notebookId) || Notebook.isAllNotebookId(notebookId)) { - return; - } - - Notebook.changeNotebookNav(notebookId); - Notebook.curNotebookId = notebookId; - - var url = "/note/ListNotes/"; - var param = {notebookId: notebookId}; - - // 2 得到笔记本 - // 这里可以缓存起来, note按notebookId缓存 - ajaxGet(url, param, function(ret) { - // note 导航 - Note.renderNotes(ret, true); - }); -}; - -//--------------------------- -// 显示共享信息 -Notebook.listNotebookShareUserInfo = function(target) { - var notebookId = $(target).attr("notebookId"); - showDialogRemote("share/listNotebookShareUserInfo", {notebookId: notebookId}); -} -// 共享笔记本 -Notebook.shareNotebooks= function(target) { - var title = $(target).text(); - showDialog("dialogShareNote", {title: "分享笔记本给好友-" + title}); - setTimeout(function() { - $("#friendsEmail").focus(); - }, 500); - var notebookId = $(target).attr("notebookId"); - - shareNoteOrNotebook(notebookId, false); -} - -//----------------------------- -// 设为blog/unset -Notebook.setNotebook2Blog = function(target) { - var notebookId = $(target).attr("notebookId"); - var notebook = Notebook.cache[notebookId]; - var isBlog = true; - if(notebook.IsBlog != undefined) { - isBlog = !notebook.IsBlog; - } - - // 那么, 如果当前是该notebook下, 重新渲染之 - if(Notebook.curNotebookId == notebookId) { - if(isBlog) { - $("#noteList .item-blog").show(); - } else { - $("#noteList .item-blog").hide(); - } - - // 如果当前在所有笔记本下 - } else if(Notebook.curNotebookId == Notebook.allNotebookId){ - $("#noteItemList .item").each(function(){ - var noteId = $(this).attr("noteId"); - var note = Note.cache[noteId]; - if(note.NotebookId == notebookId) { - if(isBlog) $(this).find(".item-blog").show(); - else $(this).find(".item-blog").hide(); - } - }); - } - ajaxPost("blog/setNotebook2Blog", {notebookId: notebookId, isBlog: isBlog}, function(ret) { - if(ret) { - // 这里要设置notebook下的note的blog状态 - Note.setAllNoteBlogStatus(notebookId, isBlog); - Notebook.setCache({NotebookId: notebookId, IsBlog: isBlog}); - } - }); -} - -// 添加, 修改完后都要对notebook的列表重新计算 TODO - -// 修改笔记本标题 -Notebook.updateNotebookTitle = function(target) { - var self = Notebook; - var notebookId = $(target).attr("notebookId"); - - if(self.tree2) { - self.tree2.editName(self.tree2.getNodeByTId(notebookId)); - } else { - self.tree.editName(self.tree.getNodeByTId(notebookId)); - } -} -Notebook.doUpdateNotebookTitle = function(notebookId, newTitle) { - var self = Notebook; - ajaxPost("/notebook/updateNotebookTitle", {notebookId: notebookId, title: newTitle}, function(ret) { - // 修改缓存 - Notebook.cache[notebookId].Title = newTitle; - // 改变nav - Notebook.changeNav(); - - // 同步 - if(self.tree2) { - var notebook = self.tree.getNodeByTId(notebookId); - notebook.Title = newTitle; - self.tree.updateNode(notebook); - } - }); -} - -//----------- -// 添加笔记本 -// 1 确保是展开的 -// 2 在所有后面添加
  • -Notebook.addNotebookSeq = 1; // inputId -Notebook.addNotebook = function() { - var self = Notebook; - if($("#myNotebooks").hasClass("closed")) { - $("#myNotebooks .folderHeader").trigger("click"); - } - - // 添加并修改 - self.tree.addNodes(null, {Title: "", NotebookId: getObjectId(), IsNew: true}, true, true); -} - -// rename 调用 -Notebook.doAddNotebook = function(notebookId, title, parentNotebookId) { - var self = Notebook; - ajaxPost("/notebook/addNotebook", {notebookId: notebookId, title: title, parentNotebookId: parentNotebookId}, function(ret) { - if(ret.NotebookId) { - Notebook.cache[ret.NotebookId] = ret; - var notebook = self.tree.getNodeByTId(notebookId); - $.extend(notebook, ret); - notebook.IsNew = false; - - // 选中之 - Notebook.changeNotebook(notebookId); - - // 改变nav - Notebook.changeNav(); - } - }); -} - -//------------- -// 添加子笔记本 -Notebook.addChildNotebook = function(target) { - var self = Notebook; - if($("#myNotebooks").hasClass("closed")) { - $("#myNotebooks .folderHeader").trigger("click"); - } - - var notebookId = $(target).attr("notebookId"); - - // 添加并修改 - self.tree.addNodes(self.tree.getNodeByTId(notebookId), {Title: "", NotebookId: getObjectId(), IsNew: true}, false, true); -} - -//------------- -// 删除 -Notebook.deleteNotebook = function(target) { - var self = Notebook; - - var notebookId = $(target).attr("notebookId"); - if(!notebookId) { - return; - } - - ajaxGet("/notebook/deleteNotebook", {notebookId: notebookId}, function(ret) { - if(ret.Ok) { - /* - $(target).parent().remove(); - */ - self.tree.removeNode(self.tree.getNodeByTId(notebookId)); - if(self.tree2) { - self.tree2.removeNode(self.tree2.getNodeByTId(notebookId)); - } - delete Notebook.cache[notebookId]; - - // 改变nav - Notebook.changeNav(); - } else { - alert(ret.Msg); - } - }); -} - -$(function() { - //------------------- - // 点击notebook - /* - $("#myNotebooks").on("click", "ul.folderBody li a", function() { - var notebookId = $(this).attr("notebookId"); - Notebook.changeNotebook(notebookId); - }); - */ - // min - $("#minNotebookList").on("click", "li", function() { - var notebookId = $(this).find("a").attr("notebookId"); - Notebook.changeNotebook(notebookId); - }); - - // 修改笔记本标题, blur后修改标题之 - /* - enterBlur("#notebookList", "input#editNotebookTitle"); - $("#notebookList").on("blur", "input#editNotebookTitle", Notebook.doUpdateNotebookTitle); - */ - - //------------------- - // 右键菜单 - var notebookListMenu = { - width: 180, - items: [ - { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Notebook.listNotebookShareUserInfo}, - { type: "splitLine" }, - { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Notebook.setNotebook2Blog }, - { text: getMsg("cancelPublic"), alias: 'unset2Blog',faIcon: "fa-undo", action: Notebook.setNotebook2Blog }, // Unset - { type: "splitLine" }, - { text: getMsg("addChildNotebook"), faIcon: "fa-sitemap", action: Notebook.addChildNotebook }, - { text: getMsg("rename"), faIcon: "fa-pencil", action: Notebook.updateNotebookTitle }, - { text: getMsg("delete"), icon: "", alias: 'delete', faIcon: "fa-trash-o", action: Notebook.deleteNotebook } - ], - onShow: applyrule, - onContextMenu: beforeContextMenu, - parent: "#notebookList ", - children: "li a" - } - - // for search - var notebookListMenu2 = { - width: 180, - items: [ - { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Notebook.listNotebookShareUserInfo}, - { type: "splitLine" }, - { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Notebook.setNotebook2Blog }, - { text: getMsg("cancelPublic"), alias: 'unset2Blog',faIcon: "fa-undo", action: Notebook.setNotebook2Blog }, // Unset - { type: "splitLine" }, - { text: getMsg("rename"), icon: "", action: Notebook.updateNotebookTitle }, - { text: getMsg("delete"), icon: "", alias: 'delete', faIcon: "fa-trash-o", action: Notebook.deleteNotebook } - ], - onShow: applyrule, - onContextMenu: beforeContextMenu, - parent: "#notebookListForSearch ", - children: "li a" - } - - function applyrule(menu) { - var notebookId = $(this).attr("notebookId"); - var notebook = Notebook.cache[notebookId]; - if(!notebook) { - return; - } - // disabled的items - var items = []; - // 是否已公开为blog - if(!notebook.IsBlog) { - items.push("unset2Blog"); - } else { - items.push("set2Blog"); - } - // 是否还有笔记 - if(Note.notebookHasNotes(notebookId)) { - items.push("delete"); - } - menu.applyrule({ - name: "target2", - disable: true, - items: items - }); - } - // 哪个不能 - function beforeContextMenu() { - var notebookId = $(this).attr("notebookId"); - return !Notebook.isTrashNotebookId(notebookId) && !Notebook.isAllNotebookId(notebookId); - } - - Notebook.contextmenu = $("#notebookList li a").contextmenu(notebookListMenu); - - Notebook.contextmenuSearch = $("#notebookListForSearch li a").contextmenu(notebookListMenu2); - - // 添加笔记本 - $("#addNotebookPlus").click(function(e) { - e.stopPropagation(); - Notebook.addNotebook(); - }); - - // notebook setting - $("#notebookList").on("click", ".notebook-setting", function(e) { - e.preventDefault(); - e.stopPropagation(); - var $p = $(this).parent(); - Notebook.contextmenu.showMenu(e, $p); - }); - $("#notebookListForSearch").on("click", ".notebook-setting", function(e) { - e.preventDefault(); - e.stopPropagation(); - var $p = $(this).parent(); - Notebook.contextmenuSearch.showMenu(e, $p); - }); -}); \ No newline at end of file diff --git a/public/js/app/page-min.js b/public/js/app/page-min.js deleted file mode 100644 index c9b445d..0000000 --- a/public/js/app/page-min.js +++ /dev/null @@ -1 +0,0 @@ -function editorMode(){this.writingHash="#writing";this.normalHash="#normal";this.isWritingMode=location.hash==this.writingHash;this.toggleA=null}editorMode.prototype.toggleAText=function(isWriting){var self=this;setTimeout(function(){toggleA=$("#toggleEditorMode a");if(isWriting){toggleA.attr("href",self.normalHash).text(getMsg("normalMode"))}else{toggleA.attr("href",self.writingHash).text(getMsg("writingMode"))}},0)};editorMode.prototype.isWriting=function(hash){return hash==this.writingHash};editorMode.prototype.init=function(){this.changeMode(this.isWritingMode);var self=this;$("#toggleEditorMode").click(function(){saveBookmark();var $a=$(this).find("a");var isWriting=self.isWriting($a.attr("href"));self.changeMode(isWriting);restoreBookmark()})};editorMode.prototype.changeMode=function(isWritingMode){this.toggleAText(isWritingMode);if(isWritingMode){this.writtingMode()}else{this.normalMode()}$("#moreBtn i").removeClass("fa-angle-up").addClass("fa-angle-down")};editorMode.prototype.resizeEditor=function(){setTimeout(function(){resizeEditor()},10);setTimeout(function(){resizeEditor()},20);setTimeout(function(){resizeEditor()},500)};editorMode.prototype.normalMode=function(){var $c=$("#editorContent_ifr").contents();$c.contents().find("#writtingMode").remove();$c.contents().find('link[href$="editor-writting-mode.css"]').remove();$("#noteItemListWrap, #notesAndSort").show();$("#noteList").unbind("mouseenter").unbind("mouseleave");var theme=UserInfo.Theme||"default";theme+=".css";$("#themeLink").attr("href","/css/theme/"+theme);$("#mceToolbar").css("height","30px");this.resizeEditor();$("#noteList").width(UserInfo.NoteListWidth);$("#note").css("left",UserInfo.NoteListWidth)};editorMode.prototype.writtingMode=function(){$("#themeLink").attr("href","/css/theme/writting-overwrite.css");setTimeout(function(){var $c=$("#editorContent_ifr").contents();$c.contents().find("head").append('')},0);$("#noteItemListWrap, #notesAndSort").fadeOut();$("#noteList").hover(function(){$("#noteItemListWrap, #notesAndSort").fadeIn()},function(){$("#noteItemListWrap, #notesAndSort").fadeOut()});$("#mceToolbar").css("height","40px");this.resizeEditor();$("#noteList").width(250);$("#note").css("left",0)};editorMode.prototype.getWritingCss=function(){if(this.isWritingMode){return["css/editor/editor-writting-mode.css"]}return[]};var em=new editorMode;var Resize={lineMove:false,mdLineMove:false,target:null,leftNotebook:$("#leftNotebook"),notebookSplitter:$("#notebookSplitter"),noteList:$("#noteList"),noteAndEditor:$("#noteAndEditor"),noteSplitter:$("#noteSplitter"),note:$("#note"),body:$("body"),leftColumn:$("#left-column"),rightColumn:$("#right-column"),mdSplitter:$("#mdSplitter"),init:function(){var self=this;self.initEvent()},initEvent:function(){var self=this;$(".noteSplit").bind("mousedown",function(event){event.preventDefault();self.lineMove=true;$(this).css("background-color","#ccc");self.target=$(this).attr("id");$("#noteMask").css("z-index",99999)});self.mdSplitter.bind("mousedown",function(event){event.preventDefault();self.mdLineMove=true;$(this).css("background-color","#ccc")});self.body.bind("mousemove",function(event){if(self.lineMove){event.preventDefault();self.resize3Columns(event)}else if(self.mdLineMove){event.preventDefault();self.resizeMdColumns(event)}});self.body.bind("mouseup",function(event){self.stopResize();$("#noteMask").css("z-index",-1)})},stopResize:function(){var self=this;if(self.lineMove||self.mdLineMove){ajaxGet("/user/updateColumnWidth",{mdEditorWidth:UserInfo.MdEditorWidth,notebookWidth:UserInfo.NotebookWidth,noteListWidth:UserInfo.NoteListWidth},function(){})}self.lineMove=false;self.mdLineMove=false;$(".noteSplit").css("background","none");self.mdSplitter.css("background","none")},set3ColumnsWidth:function(notebookWidth,noteListWidth){var self=this;if(notebookWidth<150||noteListWidth<100){return}var noteWidth=self.body.width()-notebookWidth-noteListWidth;if(noteWidth<400){return}self.leftNotebook.width(notebookWidth);self.notebookSplitter.css("left",notebookWidth);self.noteAndEditor.css("left",notebookWidth);self.noteList.width(noteListWidth);self.noteSplitter.css("left",noteListWidth);self.note.css("left",noteListWidth);UserInfo.NotebookWidth=notebookWidth;UserInfo.NoteListWidth=noteListWidth},resize3Columns:function(event,isFromeIfr){var self=this;if(isFromeIfr){event.clientX+=self.body.width()-self.note.width()}var notebookWidth,noteListWidth;if(self.lineMove){if(self.target=="notebookSplitter"){notebookWidth=event.clientX;noteListWidth=self.noteList.width();self.set3ColumnsWidth(notebookWidth,noteListWidth)}else{notebookWidth=self.leftNotebook.width();noteListWidth=event.clientX-notebookWidth;self.set3ColumnsWidth(notebookWidth,noteListWidth)}resizeEditor()}},resizeMdColumns:function(event){var self=this;if(self.mdLineMove){var mdEditorWidth=event.clientX-self.leftNotebook.width()-self.noteList.width();self.setMdColumnWidth(mdEditorWidth)}},setMdColumnWidth:function(mdEditorWidth){var self=this;if(mdEditorWidth>100){UserInfo.MdEditorWidth=mdEditorWidth;self.leftColumn.width(mdEditorWidth);self.rightColumn.css("left",mdEditorWidth);self.mdSplitter.css("left",mdEditorWidth)}}};Mobile={noteO:$("#note"),bodyO:$("body"),setMenuO:$("#setMenu"),hashChange:function(){var self=Mobile;var hash=location.hash;if(hash.indexOf("noteId")!=-1){self.toEditor(false);var noteId=hash.substr(8);Note.changeNote(noteId,false,false)}else{self.toNormal(false)}},init:function(){var self=this;self.isMobile();$(window).on("hashchange",self.hashChange);self.hashChange()},isMobile:function(){var u=navigator.userAgent;LEA.isMobile=false;LEA.isMobile=/Mobile|Android|iPhone/i.test(u);if(!LEA.isMobile&&$(document).width()<=700){LEA.isMobile=true}return LEA.isMobile},changeNote:function(noteId){var self=this;if(!LEA.isMobile){return true}self.toEditor(true,noteId);return false},toEditor:function(changeHash,noteId){var self=this;self.bodyO.addClass("full-editor");self.noteO.addClass("editor-show");if(changeHash){if(!noteId){noteId=Note.curNoteId}location.hash="noteId="+noteId}},toNormal:function(changeHash){var self=this;self.bodyO.removeClass("full-editor");self.noteO.removeClass("editor-show");if(changeHash){location.hash="notebookAndNote"}},switchPage:function(){var self=this;if(!LEA.isMobile){return true}if(self.bodyO.hasClass("full-editor")){self.toNormal(true)}else{self.toEditor(true)}return false}};function initSlimScroll(){if(Mobile.isMobile()){return}$("#notebook").slimScroll({height:"100%"});$("#noteItemList").slimScroll({height:"100%"});$("#wmd-input").slimScroll({height:"100%"});$("#wmd-input").css("width","100%");$("#wmd-panel-preview").slimScroll({height:"100%"});$("#wmd-panel-preview").css("width","100%")}function initEditor(){var mceToobarEverHeight=0;$("#moreBtn").click(function(){saveBookmark();var height=$("#mceToolbar").height();if(height<$("#popularToolbar").height()){$("#mceToolbar").height($("#popularToolbar").height());$(this).find("i").removeClass("fa-angle-down").addClass("fa-angle-up");mceToobarEverHeight=height}else{$("#mceToolbar").height(mceToobarEverHeight);$(this).find("i").removeClass("fa-angle-up").addClass("fa-angle-down")}resizeEditor();restoreBookmark()});tinymce.init({setup:function(ed){ed.on("keydown",Note.saveNote);ed.on("keydown",function(e){var num=e.which?e.which:e.keyCode;if(num==9){if(!e.shiftKey){var node=ed.selection.getNode();if(node.nodeName=="PRE"){ed.execCommand("mceInsertRawHTML",false," ")}else{ed.execCommand("mceInsertRawHTML",false,"    ")}}else{}e.preventDefault();e.stopPropagation();return false}});ed.on("click",function(e){$("body").trigger("click")});ed.on("click",function(){log(ed.selection.getNode())})},convert_urls:true,relative_urls:false,remove_script_host:false,selector:"#editorContent",content_css:["css/bootstrap.css","css/editor/editor.css"].concat(em.getWritingCss()),skin:"custom",language:LEA.locale,plugins:["autolink link leaui_image lists charmap hr","paste","searchreplace leanote_nav leanote_code tabfocus","table directionality textcolor codemirror"],toolbar1:"formatselect | forecolor backcolor | bold italic underline strikethrough | leaui_image | leanote_code | bullist numlist | alignleft aligncenter alignright alignjustify",toolbar2:"outdent indent blockquote | link unlink | table | hr removeformat | subscript superscript |searchreplace | code | pastetext pasteCopyImage | fontselect fontsizeselect",menubar:false,toolbar_items_size:"small",statusbar:false,url_converter:false,font_formats:"Arial=arial,helvetica,sans-serif;"+"Arial Black=arial black,avant garde;"+"Times New Roman=times new roman,times;"+"Courier New=courier new,courier;"+"Tahoma=tahoma,arial,helvetica,sans-serif;"+"Verdana=verdana,geneva;"+"宋体=SimSun;"+"新宋体=NSimSun;"+"黑体=SimHei;"+"微软雅黑=Microsoft YaHei",block_formats:"Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p",codemirror:{indentOnInit:true,path:"CodeMirror",config:{lineNumbers:true},jsFiles:[]},paste_data_images:true});window.onbeforeunload=function(e){Note.curChangedSaveIt()};$("body").on("keydown",Note.saveNote)}var random=1;function scrollTo(self,tagName,text){var iframe=$("#editorContent_ifr").contents();var target=iframe.find(tagName+":contains("+text+")");random++;var navs=$('#leanoteNavContent [data-a="'+tagName+"-"+encodeURI(text)+'"]');var len=navs.size();for(var i=0;i=i+1){target=target.eq(i);var top=target.offset().top;var nowTop=iframe.scrollTop();var d=200;for(var i=0;i'); - }, 0); - - $("#noteItemListWrap, #notesAndSort").fadeOut(); - $("#noteList").hover(function() { - $("#noteItemListWrap, #notesAndSort").fadeIn(); - }, function() { - $("#noteItemListWrap, #notesAndSort").fadeOut(); - }); - - // 点击扩展会使html的height生成, 切换后会覆盖css文件的 - $("#mceToolbar").css("height", "40px"); - - //$("#pageInner").addClass("animated fadeInUp"); - - this.resizeEditor(); - - $("#noteList").width(250); - $("#note").css("left", 0); -} - -editorMode.prototype.getWritingCss = function() { - if(this.isWritingMode) { - return ["css/editor/editor-writting-mode.css"]; - } - return []; -} -var em = new editorMode(); - -//---------------- -// 拖拉改变变宽度 -var Resize = { - lineMove: false, - mdLineMove: false, - target: null, - - leftNotebook: $("#leftNotebook"), - notebookSplitter: $("#notebookSplitter"), - noteList: $("#noteList"), - noteAndEditor: $("#noteAndEditor"), - noteSplitter: $("#noteSplitter"), - note: $("#note"), - body: $("body"), - leftColumn: $("#left-column"), - rightColumn: $("#right-column"), - mdSplitter: $("#mdSplitter"), - - init: function() { - var self = this; - self.initEvent(); - }, - - initEvent: function() { - var self = this; - - // 鼠标点下 - $(".noteSplit").bind("mousedown", function(event) { - event.preventDefault(); // 防止选择文本 - self.lineMove = true; - $(this).css("background-color", "#ccc"); - self.target = $(this).attr("id"); - // 防止iframe捕获不了事件 - $("#noteMask").css("z-index", 99999); // .css("background-color", // "#ccc"); - }); - - // 鼠标点下 - self.mdSplitter.bind("mousedown", function(event) { - event.preventDefault(); // 防止选择文本 - self.mdLineMove = true; - $(this).css("background-color", "#ccc"); - }); - - // 鼠标移动时 - self.body.bind("mousemove", function(event) { - if(self.lineMove) { // 如果没有这个if会导致不能选择文本 - event.preventDefault(); - self.resize3Columns(event); - } else if(self.mdLineMove) { - event.preventDefault(); - self.resizeMdColumns(event); - } - }); - - // 鼠标放开, 结束 - self.body.bind("mouseup", function(event) { - self.stopResize(); - // 取消遮罩 - $("#noteMask").css("z-index", -1); - }); - }, - // 停止, 保存数据 - stopResize: function() { - var self = this; - if(self.lineMove || self.mdLineMove) { - // ajax保存 - ajaxGet("/user/updateColumnWidth", {mdEditorWidth: UserInfo.MdEditorWidth, notebookWidth: UserInfo.NotebookWidth, noteListWidth: UserInfo.NoteListWidth}, function() { - }); - } - self.lineMove = false; - self.mdLineMove = false; - $(".noteSplit").css("background", "none"); - self.mdSplitter.css("background", "none"); - }, - - // 最终调用该方法 - set3ColumnsWidth: function(notebookWidth, noteListWidth) { - var self = this; - if(notebookWidth < 150 || noteListWidth < 100) { - return; - } - var noteWidth = self.body.width() - notebookWidth - noteListWidth; - if(noteWidth < 400) { - return; - } - - self.leftNotebook.width(notebookWidth); - self.notebookSplitter.css("left", notebookWidth); - - self.noteAndEditor.css("left", notebookWidth); - self.noteList.width(noteListWidth); - self.noteSplitter.css("left", noteListWidth); - self.note.css("left", noteListWidth); - - UserInfo.NotebookWidth = notebookWidth; - UserInfo.NoteListWidth = noteListWidth; - }, - resize3Columns: function(event, isFromeIfr) { - var self = this; - if (isFromeIfr) { - event.clientX += self.body.width() - self.note.width(); - } - - var notebookWidth, noteListWidth; - if(self.lineMove) { - if (self.target == "notebookSplitter") { - notebookWidth = event.clientX; - noteListWidth = self.noteList.width(); - self.set3ColumnsWidth(notebookWidth, noteListWidth); - } else { - notebookWidth = self.leftNotebook.width(); - noteListWidth = event.clientX - notebookWidth; - self.set3ColumnsWidth(notebookWidth, noteListWidth); - } - - resizeEditor(); - } - }, - - // mdeditor - resizeMdColumns: function(event) { - var self = this; - if (self.mdLineMove) { - var mdEditorWidth = event.clientX - self.leftNotebook.width() - self.noteList.width(); - self.setMdColumnWidth(mdEditorWidth); - } - }, - // 设置宽度 - setMdColumnWidth: function(mdEditorWidth) { - var self = this; - if(mdEditorWidth > 100) { - UserInfo.MdEditorWidth = mdEditorWidth; - self.leftColumn.width(mdEditorWidth); - self.rightColumn.css("left", mdEditorWidth); - self.mdSplitter.css("left", mdEditorWidth); - } - } -} - -//-------------------------- -// 手机端访问之 -Mobile = { - // 点击之笔记 - // 切换到编辑器模式 - noteO: $("#note"), - bodyO: $("body"), - setMenuO: $("#setMenu"), - hashChange: function() { - var self = Mobile; - var hash = location.hash; - // noteId - if(hash.indexOf("noteId") != -1) { - self.toEditor(false); - var noteId = hash.substr(8); - Note.changeNote(noteId, false, false); - } else { - // 笔记本和笔记列表 - self.toNormal(false); - } - }, - init: function() { - var self = this; - self.isMobile(); - $(window).on("hashchange", self.hashChange); - self.hashChange(); - /* - $("#noteItemList").on("tap", ".item", function(event) { - $(this).click(); - }); - $(document).on("swipeleft",function(e){ - e.stopPropagation(); - e.preventDefault(); - self.toEditor(); - }); - $(document).on("swiperight",function(e){ - e.stopPropagation(); - e.preventDefault(); - self.toNormal(); - }); - */ - }, - isMobile: function() { - var u = navigator.userAgent; - LEA.isMobile = false; - LEA.isMobile = /Mobile|Android|iPhone/i.test(u); - if(!LEA.isMobile && $(document).width() <= 700){ - LEA.isMobile = true - } - return LEA.isMobile; - }, - changeNote: function(noteId) { - var self = this; - if(!LEA.isMobile) {return true;} - self.toEditor(true, noteId); - return false; - }, - - toEditor: function(changeHash, noteId) { - var self = this; - self.bodyO.addClass("full-editor"); - self.noteO.addClass("editor-show"); - if(changeHash) { - if(!noteId) { - noteId = Note.curNoteId; - } - location.hash = "noteId=" + noteId; - } - }, - toNormal: function(changeHash) { - var self = this; - self.bodyO.removeClass("full-editor"); - self.noteO.removeClass("editor-show"); - - if(changeHash) { - location.hash = "notebookAndNote"; - } - }, - switchPage: function() { - var self = this; - if(!LEA.isMobile) {return true;} - if(self.bodyO.hasClass("full-editor")) { - self.toNormal(true); - } else { - self.toEditor(true); - } - return false; - } -} - - -function initSlimScroll() { - if(Mobile.isMobile()) { - return; - } - $("#notebook").slimScroll({ - height: "100%", // $("#leftNotebook").height()+"px" - }); - $("#noteItemList").slimScroll({ - height: "100%", // ($("#leftNotebook").height()-42)+"px" - }); - $("#wmd-input").slimScroll({ - height: "100%", // $("#wmd-input").height()+"px" - }); - $("#wmd-input").css("width", "100%"); - - $("#wmd-panel-preview").slimScroll({ - height: "100%", // $("#wmd-panel-preview").height()+"px" - }); - - $("#wmd-panel-preview").css("width", "100%"); -} - -//----------- -// 初始化编辑器 -function initEditor() { - // editor - // toolbar 下拉扩展, 也要resizeEditor - var mceToobarEverHeight = 0; - $("#moreBtn").click(function() { - saveBookmark(); - - var height = $("#mceToolbar").height(); - - // 现在是折叠的 - if (height < $("#popularToolbar").height()) { - $("#mceToolbar").height($("#popularToolbar").height()); - $(this).find("i").removeClass("fa-angle-down").addClass("fa-angle-up"); - mceToobarEverHeight = height; - } else { - $("#mceToolbar").height(mceToobarEverHeight); - $(this).find("i").removeClass("fa-angle-up").addClass("fa-angle-down"); - } - - resizeEditor(); - - restoreBookmark(); - }); - - // 初始化编辑器 - tinymce.init({ - setup: function(ed) { - ed.on('keydown', Note.saveNote); - // indent outdent - ed.on('keydown', function(e) { - var num = e.which ? e.which : e.keyCode; - if (num == 9) { // tab pressed - - if(!e.shiftKey) { -// ed.execCommand('Indent'); - // TODO 如果当前在li, ul, ol下不执行!! - // 如果在pre下就加tab - var node = ed.selection.getNode(); - if(node.nodeName == "PRE") { - ed.execCommand('mceInsertRawHTML', false, '\x09'); // inserts tab - } else { - ed.execCommand('mceInsertRawHTML', false, "    "); // inserts 空格 - } - } else { - // delete 4 个空格 -// ed.execCommand('Outdent'); - } - - e.preventDefault(); - e.stopPropagation(); - return false; - } - }); - - // 为了把下拉菜单关闭 - ed.on("click", function(e) { - $("body").trigger("click"); - }); - - // 鼠标移上时 - ed.on("click", function() { - log(ed.selection.getNode()) - }); - }, - - // fix TinyMCE Removes site base url - // http://stackoverflow.com/questions/3360084/tinymce-removes-site-base-urls - convert_urls:true, - relative_urls:false, - remove_script_host:false, - - selector : "#editorContent", - // height: 100,//这个应该是文档的高度, 而其上层的高度是$("#content").height(), - // parentHeight: $("#content").height(), - content_css : ["css/bootstrap.css", "css/editor/editor.css"].concat(em.getWritingCss()), - skin : "custom", - language: LEA.locale, // 语言 - plugins : [ - "autolink link leaui_image lists charmap hr", "paste", - "searchreplace leanote_nav leanote_code tabfocus", - "table directionality textcolor codemirror" ], // nonbreaking - - toolbar1 : "formatselect | forecolor backcolor | bold italic underline strikethrough | leaui_image | leanote_code | bullist numlist | alignleft aligncenter alignright alignjustify", - toolbar2 : "outdent indent blockquote | link unlink | table | hr removeformat | subscript superscript |searchreplace | code | pastetext pasteCopyImage | fontselect fontsizeselect", - - // 使用tab键: http://www.tinymce.com/wiki.php/Plugin3x:nonbreaking - // http://stackoverflow.com/questions/13543220/tiny-mce-how-to-allow-people-to-indent - // nonbreaking_force_tab : true, - - menubar : false, - toolbar_items_size : 'small', - statusbar : false, - url_converter: false, - font_formats : "Arial=arial,helvetica,sans-serif;" - + "Arial Black=arial black,avant garde;" - + "Times New Roman=times new roman,times;" - + "Courier New=courier new,courier;" - + "Tahoma=tahoma,arial,helvetica,sans-serif;" - + "Verdana=verdana,geneva;" + "宋体=SimSun;" - + "新宋体=NSimSun;" + "黑体=SimHei;" - + "微软雅黑=Microsoft YaHei", - block_formats : "Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p", - codemirror: { - indentOnInit: true, // Whether or not to indent code on init. - path: 'CodeMirror', // Path to CodeMirror distribution - config: { // CodeMirror config object - //mode: 'application/x-httpd-php', - lineNumbers: true - }, - jsFiles: [ // Additional JS files to load - // 'mode/clike/clike.js', - //'mode/php/php.js' - ] - }, - // This option specifies whether data:url images (inline images) should be removed or not from the pasted contents. - // Setting this to "true" will allow the pasted images, and setting this to "false" will disallow pasted images. - // For example, Firefox enables you to paste images directly into any contentEditable field. This is normally not something people want, so this option is "false" by default. - paste_data_images: true - }); - - // 刷新时保存 参考autosave插件 - window.onbeforeunload = function(e) { - Note.curChangedSaveIt(); - } - - // 全局ctrl + s - $("body").on('keydown', Note.saveNote); -} - -//----------------------- -// 导航 -var random = 1; -function scrollTo(self, tagName, text) { - var iframe = $("#editorContent_ifr").contents(); - var target = iframe.find(tagName + ":contains(" + text + ")"); - random++; - - // 找到是第几个 - // 在nav是第几个 - var navs = $('#leanoteNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]'); -// alert('#leanoteNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]') - var len = navs.size(); - for(var i = 0; i < len; ++i) { - if(navs[i] == self) { - break; - } - } - - if (target.size() >= i+1) { - target = target.eq(i); - // 之前插入, 防止多行定位不准 - var top = target.offset().top; - var nowTop = iframe.scrollTop(); - - // iframe.scrollTop(top); - // $(iframe).animate({scrollTop: top}, 300); // 有问题 - - var d = 200; // 时间间隔 - for(var i = 0; i < d; i++) { - setTimeout( - (function(top) { - return function() { - iframe.scrollTop(top); - } - })(nowTop + 1.0*i*(top-nowTop)/d), i); - } - // 最后必然执行 - setTimeout(function() { - iframe.scrollTop(top); - }, d+5); - return; - } -} - -//-------------- -// 调用之 -$(function() { - // 窗口缩放时 - $(window).resize(function() { - Mobile.isMobile(); - resizeEditor(); - }); - - // 初始化编辑器 - initEditor(); - - // 左侧, folder 展开与关闭 - $(".folderHeader").click(function() { - var body = $(this).next(); - var p = $(this).parent(); - if (!body.is(":hidden")) { - $(".folderNote").removeClass("opened").addClass("closed"); -// body.hide(); - p.removeClass("opened").addClass("closed"); - $(this).find(".fa-angle-down").removeClass("fa-angle-down").addClass("fa-angle-right"); - } else { - $(".folderNote").removeClass("opened").addClass("closed"); -// body.show(); - p.removeClass("closed").addClass("opened"); - $(this).find(".fa-angle-right").removeClass("fa-angle-right").addClass("fa-angle-down"); - } - }); - - // 导航隐藏与显示 - $("#leanoteNav h1").on("click", function(e) { - if (!$("#leanoteNav").hasClass("unfolder")) { - $("#leanoteNav").addClass("unfolder"); - } else { - $("#leanoteNav").removeClass("unfolder"); - } - }); - - // 打开设置 - function openSetInfoDialog(whichTab) { - showDialogRemote("/user/account", {tab: whichTab}); - } - // 帐号设置 - $("#setInfo").click(function() { - openSetInfoDialog(0); - }); - // 邮箱验证 - $("#wrongEmail").click(function() { - openSetInfoDialog(1); - }); - - $("#setAvatarMenu").click(function() { - showDialog2("#avatarDialog", {title: "头像设置", postShow: function() { - }}); - }); - $("#setTheme").click(function() { - showDialog2("#setThemeDialog", {title: "主题设置", postShow: function() { - if (!UserInfo.Theme) { - UserInfo.Theme = "default"; - } - $("#themeForm input[value='" + UserInfo.Theme + "']").attr("checked", true); - }}); - }); - - //--------- - // 主题 - $("#themeForm").on("click", "input", function(e) { - var val = $(this).val(); - $("#themeLink").attr("href", "/css/theme/" + val + ".css"); - - ajaxPost("/user/updateTheme", {theme: val}, function(re) { - if(reIsOk(re)) { - UserInfo.Theme = val - } - }); - }); - - //------------- - // 邮箱验证 - if(!UserInfo.Verified) { -// $("#leanoteMsg").hide(); -// $("#verifyMsg").show(); - } - - // 禁止双击选中文字 - $("#notebook, #newMyNote, #myProfile, #topNav, #notesAndSort", "#leanoteNavTrigger").bind("selectstart", function(e) { - e.preventDefault(); - return false; - }); - - // 左侧隐藏或展示 - function updateLeftIsMin(is) { - ajaxGet("/user/updateLeftIsMin", {leftIsMin: is}) - } - function minLeft(save) { - $("#leftNotebook").width(30); - $("#notebook").hide(); - // 左侧 - $("#noteAndEditor").css("left", 30) - $("#notebookSplitter").hide(); - -// $("#leftSwitcher").removeClass("fa-angle-left").addClass("fa-angle-right"); - - // logo - $("#logo").hide(); - $("#leftSwitcher").hide(); - $("#leftSwitcher2").show(); - $("#leftNotebook .slimScrollDiv").hide(); - - if(save) { - updateLeftIsMin(true); - } - } - - function maxLeft(save) { - $("#noteAndEditor").css("left", UserInfo.NotebookWidth); - $("#leftNotebook").width(UserInfo.NotebookWidth); - $("#notebook").show(); - $("#notebookSplitter").show(); - -// $("#leftSwitcher").removeClass("fa-angle-right").addClass("fa-angle-left"); - - $("#leftSwitcher2").hide(); - $("#logo").show(); - $("#leftSwitcher").show(); - $("#leftNotebook .slimScrollDiv").show(); - - if(save) { - updateLeftIsMin(false); - } - } - - $("#leftSwitcher2").click(function() { - maxLeft(true); - }); - $("#leftSwitcher").click(function() { - if(Mobile.switchPage()) { - minLeft(true); - } - }); - - // 得到最大dropdown高度 - // 废弃 - function getMaxDropdownHeight(obj) { - var offset = $(obj).offset(); - var maxHeight = $(document).height()-offset.top; - maxHeight -= 70; - if(maxHeight < 0) { - maxHeight = 0; - } - - var preHeight = $(obj).find("ul").height(); - return preHeight < maxHeight ? preHeight : maxHeight; - } - - // mini版 - // 点击展开 - $("#notebookMin div.minContainer").click(function() { - var target = $(this).attr("target"); - maxLeft(true); - if(target == "#notebookList") { - if($("#myNotebooks").hasClass("closed")) { - $("#myNotebooks .folderHeader").trigger("click"); - } - } else if(target == "#tagNav") { - if($("#myTag").hasClass("closed")) { - $("#myTag .folderHeader").trigger("click"); - } - } else { - if($("#myShareNotebooks").hasClass("closed")) { - $("#myShareNotebooks .folderHeader").trigger("click"); - } - } - }); - - //------------------------ - // 界面设置, 左侧是否是隐藏的 - UserInfo.NotebookWidth = UserInfo.NotebookWidth || $("#notebook").width(); - UserInfo.NoteListWidth = UserInfo.NoteListWidth || $("#noteList").width(); - - Resize.init(); - Resize.set3ColumnsWidth(UserInfo.NotebookWidth, UserInfo.NoteListWidth); - Resize.setMdColumnWidth(UserInfo.MdEditorWidth); - - if (UserInfo.LeftIsMin) { - minLeft(false); - } - - // end - // 开始时显示loading...... - // 隐藏mask - $("#mainMask").html(""); - $("#mainMask").hide(100); - - // 4/25 防止dropdown太高 - // dropdown - $('.dropdown').on('shown.bs.dropdown', function () { - var $ul = $(this).find("ul"); - // $ul.css("max-height", getMaxDropdownHeight(this)); - }); - - //-------- - // 编辑器帮助 - $("#tipsBtn").click(function() { - showDialog2("#tipsDialog"); - }); - - //-------- - // 建议 - $("#yourSuggestions").click(function() { - showDialog2("#suggestionsDialog"); - }); - $("#suggestionBtn").click(function(e) { - e.preventDefault(); - var suggestion = $.trim($("#suggestionTextarea").val()); - if(!suggestion) { - $("#suggestionMsg").html("请输入您的建议, 谢谢!").show().addClass("alert-warning").removeClass("alert-success"); - $("#suggestionTextarea").focus(); - return; - } - $("#suggestionBtn").html("正在处理...").addClass("disabled"); - $("#suggestionMsg").html("正在处理..."); - $.post("/suggestion", {suggestion: suggestion}, function(ret) { - $("#suggestionBtn").html("提交").removeClass("disabled"); - if(ret.Ok) { - $("#suggestionMsg").html("谢谢反馈, 我们会第一时间处理, 祝您愉快!").addClass("alert-success").removeClass("alert-warning").show(); - } else { - $("#suggestionMsg").html("出错了").show().addClass("alert-warning").removeClass("alert-success"); - } - }); - }); - - // 编辑器模式 - em.init(); - - // 手机端? - Mobile.init(); -}); - diff --git a/public/js/app/share-min.js b/public/js/app/share-min.js deleted file mode 100644 index f959a81..0000000 --- a/public/js/app/share-min.js +++ /dev/null @@ -1 +0,0 @@ -Share.defaultNotebookId="share0";Share.defaultNotebookTitle=getMsg("defaulthhare");Share.sharedUserInfos={};Share.userNavs={};Share.notebookCache={};Share.cache={};Share.dialogIsNote=true;Share.setCache=function(note){if(!note||!note.NoteId){return}Share.cache[note.NoteId]=note};Share.getNotebooksForNew=function(userId,notebooks){var self=this;var navForNewNote="";var len=notebooks.length;for(var i=0;i
    ?
    M
    ',classes,userId,notebook.NotebookId,notebook.Title);if(subs){eachForNew+=""}eachForNew+=""}navForNewNote+=eachForNew}return navForNewNote};Share.trees={};Share.renderShareNotebooks=function(sharedUserInfos,shareNotebooks){var self=Share;if(isEmpty(sharedUserInfos)){return}if(!shareNotebooks||typeof shareNotebooks!="object"||shareNotebooks.length<0){shareNotebooks={}}var $shareNotebooks=$("#shareNotebooks");for(var i in sharedUserInfos){var userInfo=sharedUserInfos[i];var userNotebooksPre=shareNotebooks[userInfo.UserId]||[];userNotebooks=[{NotebookId:self.defaultNotebookId,Title:Share.defaultNotebookTitle}].concat(userNotebooksPre);self.notebookCache[self.defaultNotebookId]=userNotebooks[0];var username=userInfo.Username||userInfo.Email;userInfo.Username=username;Share.sharedUserInfos[userInfo.UserId]=userInfo;var userId=userInfo.UserId;var header=tt('
  • ?
    ',userInfo.UserId,username);var friendId="friendContainer_"+userId;var body='
      ';$shareNotebooks.append(header+body+"
    • ");self.trees[userId]=$.fn.zTree.init($("#"+friendId),Notebook.getTreeSetting(true,true),userNotebooks);self.userNavs[userId]={forNew:self.getNotebooksForNew(userId,userNotebooksPre)};log(self.userNavs)}$(".friend-notebooks").hover(function(){if(!$(this).hasClass("showIcon")){$(this).addClass("showIcon")}},function(){$(this).removeClass("showIcon")});$(".friend-header i").click(function(){var $this=$(this);var $tree=$(this).parent().next();if($tree.is(":hidden")){$tree.slideDown("fast");$this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-down")}else{$tree.slideUp("fast");$this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-right")}});var shareNotebookMenu={width:180,items:[{text:getMsg("deleteSharedNotebook"),icon:"",faIcon:"fa-trash-o",action:Share.deleteShareNotebook}],onShow:applyrule,onContextMenu:beforeContextMenu,parent:"#shareNotebooks",children:".notebook-item"};function applyrule(menu){return}function beforeContextMenu(){var notebookId=$(this).attr("notebookId");return!Share.isDefaultNotebookId(notebookId)}var menuNotebooks=$("#shareNotebooks").contextmenu(shareNotebookMenu);var shareUserMenu={width:180,items:[{text:getMsg("deleteAllShared"),icon:"",faIcon:"fa-trash-o",action:Share.deleteUserShareNoteAndNotebook}],parent:"#shareNotebooks",children:".friend-header"};var menuUser=$("#shareNotebooks").contextmenu(shareUserMenu);$(".friend-header").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();menuUser.showMenu(e,$p)});$("#shareNotebooks .notebook-item").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();menuNotebooks.showMenu(e,$p)})};Share.isDefaultNotebookId=function(notebookId){return Share.defaultNotebookId==notebookId};Share.toggleToSharedNav=function(userId,notebookId){var self=this;$("#curNotebookForListNote").html(Share.notebookCache[notebookId].Title+"("+Share.sharedUserInfos[userId].Username+")");var forNew=Share.userNavs[userId].forNew;if(forNew){$("#notebookNavForNewSharedNote").html(forNew);var curNotebookId="";var curNotebookTitle="";if(Share.notebookCache[notebookId].Perm){curNotebookId=notebookId;curNotebookTitle=Share.notebookCache[notebookId].Title}else{var $f=$("#notebookNavForNewSharedNote li").eq(0);curNotebookId=$f.attr("notebookId");curNotebookTitle=$f.find(".new-note-left").text()}$("#curNotebookForNewSharedNote").html(curNotebookTitle+"("+Share.sharedUserInfos[userId].Username+")");$("#curNotebookForNewSharedNote").attr("notebookId",curNotebookId);$("#curNotebookForNewSharedNote").attr("userId",userId);$("#newSharedNote").show();$("#newMyNote").hide()}else{$("#newMyNote").show();$("#newSharedNote").hide()}$("#tagSearch").hide()};Share.changeNotebook=function(userId,notebookId){Notebook.selectNotebook($(tt('#friendContainer_? a[notebookId="?"]',userId,notebookId)));Share.toggleToSharedNav(userId,notebookId);Note.curChangedSaveIt();Note.clearAll();var url="/share/ListShareNotes/";var param={userId:userId};if(!Share.isDefaultNotebookId(notebookId)){param.notebookId=notebookId}ajaxGet(url,param,function(ret){if(param.notebookId){}Note.renderNotes(ret,false,true);if(!isEmpty(ret)){Note.changeNote(ret[0].NoteId,true)}else{}})};Share.hasUpdatePerm=function(notebookId){var note=Share.cache[notebookId];if(!note||!note.Perm){return false}return true};Share.deleteShareNotebook=function(target){if(confirm("Are you sure to delete it?")){var notebookId=$(target).attr("notebookId");var fromUserId=$(target).closest(".friend-notebooks").attr("fromUserId");ajaxGet("/share/DeleteShareNotebookBySharedUser",{notebookId:notebookId,fromUserId:fromUserId},function(ret){if(ret){$(target).parent().remove()}})}};Share.deleteShareNote=function(target){var noteId=$(target).attr("noteId");var fromUserId=$(target).attr("fromUserId");ajaxGet("/share/DeleteShareNoteBySharedUser",{noteId:noteId,fromUserId:fromUserId},function(ret){if(ret){$(target).remove()}})};Share.deleteUserShareNoteAndNotebook=function(target){if(confirm("Are you sure to delete all shared notebooks and notes?")){var fromUserId=$(target).attr("fromUserId");ajaxGet("/share/deleteUserShareNoteAndNotebook",{fromUserId:fromUserId},function(ret){if(ret){$(target).parent().remove()}})}};Share.changeNotebookForNewNote=function(notebookId){Notebook.selectNotebook($(tt('#shareNotebooks [notebookId="?"]',notebookId)));var userId=Share.notebookCache[notebookId].UserId;Share.toggleToSharedNav(userId,notebookId);var url="/share/ListShareNotes/";var param={userId:userId,notebookId:notebookId};ajaxGet(url,param,function(ret){Note.renderNotes(ret,true,true)})};Share.deleteSharedNote=function(target,contextmenuItem){Note.deleteNote(target,contextmenuItem,true)};Share.copySharedNote=function(target,contextmenuItem){Note.copyNote(target,contextmenuItem,true)};Share.contextmenu=null;Share.initContextmenu=function(notebooksCopy){if(Share.contextmenu){Share.contextmenu.destroy()}var noteListMenu={width:180,items:[{text:getMsg("copyToMyNotebook"),alias:"copy",faIcon:"fa-copy",type:"group",width:180,items:notebooksCopy},{type:"splitLine"},{text:getMsg("delete"),alias:"delete",icon:"",faIcon:"fa-trash-o",action:Share.deleteSharedNote}],onShow:applyrule,parent:"#noteItemList",children:".item-shared"};function applyrule(menu){var noteId=$(this).attr("noteId");var note=Share.cache[noteId];if(!note){return}var items=[];if(!(note.Perm&¬e.CreatedUserId==UserInfo.UserId)){items.push("delete")}menu.applyrule({name:"target...",disable:true,items:items})}Share.contextmenu=$("#noteItemList .item-shared").contextmenu(noteListMenu)};$(function(){$("#noteItemList").on("click",".item-shared .item-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();Share.contextmenu.showMenu(e,$p)});$("#newSharedNoteBtn").click(function(){var notebookId=$("#curNotebookForNewSharedNote").attr("notebookId");var userId=$("#curNotebookForNewSharedNote").attr("userId");Note.newNote(notebookId,true,userId)});$("#newShareNoteMarkdownBtn").click(function(){var notebookId=$("#curNotebookForNewSharedNote").attr("notebookId");var userId=$("#curNotebookForNewSharedNote").attr("userId");Note.newNote(notebookId,true,userId,true)});$("#notebookNavForNewSharedNote").on("click","li div",function(){var notebookId=$(this).parent().attr("notebookId");var userId=$(this).parent().attr("userId");if($(this).text()=="M"){Note.newNote(notebookId,true,userId,true)}else{Note.newNote(notebookId,true,userId)}});$("#leanoteDialogRemote").on("click",".change-perm",function(){var self=this;var perm=$(this).attr("perm");var noteOrNotebookId=$(this).attr("noteOrNotebookId");var toUserId=$(this).attr("toUserId");var toHtml=getMsg("writable");var toPerm="1";if(perm=="1"){toHtml=getMsg("readOnly");toPerm="0"}var url="/share/UpdateShareNotebookPerm";var param={perm:toPerm,toUserId:toUserId};if(Share.dialogIsNote){url="/share/UpdateShareNotePerm";param.noteId=noteOrNotebookId}else{param.notebookId=noteOrNotebookId}ajaxGet(url,param,function(ret){if(ret){$(self).html(toHtml);$(self).attr("perm",toPerm)}})});$("#leanoteDialogRemote").on("click",".delete-share",function(){var self=this;var noteOrNotebookId=$(this).attr("noteOrNotebookId");var toUserId=$(this).attr("toUserId");var url="/share/DeleteShareNotebook";var param={toUserId:toUserId};if(Share.dialogIsNote){url="/share/DeleteShareNote";param.noteId=noteOrNotebookId}else{param.notebookId=noteOrNotebookId}ajaxGet(url,param,function(ret){if(ret){$(self).parent().parent().remove()}})});var seq=1;$("#leanoteDialogRemote").on("click","#addShareNotebookBtn",function(){seq++;var tpl='#';tpl+='";tpl+=' ";tpl+='";tpl+=' ";tpl+="";$("#shareNotebookTable tbody").prepend(tpl);$("#tr"+seq+" #friendsEmail").focus()});$("#registerEmailBtn").click(function(){var content=$("#emailContent").val();var toEmail=$("#toEmail").val();if(!content){showAlert("#registerEmailMsg",getMsg("emailBodyRequired"),"danger");return}post("/user/sendRegisterEmail",{content:content,toEmail:toEmail},function(ret){showAlert("#registerEmailMsg",getMsg("sendSuccess"),"success");hideDialog2("#sendRegisterEmailDialog",1e3)},this)})});function addShareNoteOrNotebook(trSeq){var trId="#tr"+trSeq;var id=Share.dialogNoteOrNotebookId;var emails=isEmailFromInput(trId+" #friendsEmail","#shareMsg",getMsg("inputFriendEmail"));if(!emails){return}var shareNotePerm=$(trId+' input[name="perm'+trSeq+'"]:checked').val()||0;var perm=shareNotePerm;var url="share/addShareNote";var data={noteId:id,emails:[emails],perm:shareNotePerm};if(!Share.dialogIsNote){url="share/addShareNotebook";data={notebookId:id,emails:[emails],perm:shareNotePerm}}hideAlert("#shareMsg");post(url,data,function(ret){var ret=ret[emails];if(ret){if(ret.Ok){var tpl=tt("?","#");tpl+=tt("?",emails);tpl+=tt('?',id,perm,ret.Id,!perm||perm=="0"?getMsg("readOnly"):getMsg("writable"));tpl+=tt(''+getMsg("delete")+"",id,ret.Id);$(trId).html(tpl)}else{var shareUrl=UrlPrefix+"/register?from="+UserInfo.Username;showAlert("#shareMsg",getMsg("friendNotExits",[getMsg("app"),shareUrl])+' '+getMsg("clickToCopy")+'
      '+getMsg("sendInviteEmailToYourFriend")+', "+getMsg("send"),"warning");$("#copyDiv").text(shareUrl);initCopy("shareCopy",function(args){if(args.text){showMsg2("#copyStatus",getMsg("copySuccess"),1e3)}else{showMsg2("#copyStatus",getMsg("copyFailed"),1e3)}})}}},trId+" .btn-success")}function sendRegisterEmail(email){showDialog2("#sendRegisterEmailDialog",{postShow:function(){$("#emailContent").val(getMsg("inviteEmailBody",[UserInfo.Username,getMsg("app")]));setTimeout(function(){$("#emailContent").focus()},500);$("#toEmail").val(email)}})}function deleteShareNoteOrNotebook(trSeq){$("#tr"+trSeq).remove()} \ No newline at end of file diff --git a/public/js/app/share.js b/public/js/app/share.js deleted file mode 100644 index c0aaf3f..0000000 --- a/public/js/app/share.js +++ /dev/null @@ -1,583 +0,0 @@ -//------------------------------------ -// 共享, notbeook, note -//------------------------------------ - -// 默认共享notebook id -Share.defaultNotebookId = "share0"; -Share.defaultNotebookTitle = getMsg("defaulthhare"); -Share.sharedUserInfos = {}; // userId => {} - -// 在render时就创建, 以后复用之 -Share.userNavs = {}; // userId => {"forList":html, "forNew":html} - -// 缓存都不要, 统一放在Note.cache中 -// 放在这里, 只是为了debug, 分离 -Share.notebookCache = {}; // notebooks 的cache -Share.cache = {}; // note的cache - -// 分享的弹出框是note的 -Share.dialogIsNote = true; - -// 设置缓存 note -Share.setCache = function(note) { - if(!note || !note.NoteId) { - return; - } - Share.cache[note.NoteId] = note; -} - -/** - * 我的共享notebooks -
      - - */ -// TODO 层级 -// shareNotebooks = {userId => {}} -Share.getNotebooksForNew = function(userId, notebooks) { - var self = this; - var navForNewNote = ""; - - var len = notebooks.length; - for(var i = 0; i < len; ++i) { - var notebook = notebooks[i]; - notebook.IsShared = true; - notebook.UserId = userId; - self.notebookCache[notebook.NotebookId] = notebook; - // notebook的cache也缓存一份, 为了显示标题 - Notebook.cache[notebook.NotebookId] = notebook; - - var classes = ""; - var subs = false; - if(!isEmpty(notebook.Subs)) { - log(11); - log(notebook.Subs); - var subs = self.getNotebooksForNew(userId, notebook.Subs); - if(subs) { - classes = "dropdown-submenu"; - } - } - - var eachForNew = ""; - if(notebook.Perm) { - var eachForNew = tt(''; - } - - navForNewNote += eachForNew; - } - return navForNewNote; -} -Share.trees = {}; -Share.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { - var self = Share; - if(isEmpty(sharedUserInfos)) { - return; - } - - if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) { - shareNotebooks = {}; - } - - var $shareNotebooks = $("#shareNotebooks"); - - // render每一个用户的share给我的笔记本, 之前先建一个默认共享 - for(var i in sharedUserInfos) { - var userInfo = sharedUserInfos[i]; - var userNotebooksPre = shareNotebooks[userInfo.UserId] || []; - - userNotebooks = [{NotebookId: self.defaultNotebookId, Title: Share.defaultNotebookTitle}].concat(userNotebooksPre) - - self.notebookCache[self.defaultNotebookId] = userNotebooks[0]; - - var username = userInfo.Username || userInfo.Email; - userInfo.Username = username; - Share.sharedUserInfos[userInfo.UserId] = userInfo; - var userId = userInfo.UserId; - var header = tt('
    • ?
      ', userInfo.UserId, username); - var friendId = "friendContainer_" + userId; - var body = '
        '; - $shareNotebooks.append(header + body + "
      • ") - - self.trees[userId] = $.fn.zTree.init($("#" + friendId), Notebook.getTreeSetting(true, true), userNotebooks); - - self.userNavs[userId] = {"forNew": self.getNotebooksForNew(userId, userNotebooksPre)}; - log(self.userNavs); - } - - $(".friend-notebooks").hover(function () { - if (!$(this).hasClass("showIcon")) { - $(this).addClass("showIcon"); - } - }, function() { - $(this).removeClass("showIcon"); - }); - - $(".friend-header i").click(function() { - var $this = $(this); - var $tree = $(this).parent().next(); - if($tree.is(":hidden")) { - $tree.slideDown("fast"); - $this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-down"); - } else { - $tree.slideUp("fast"); - $this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-right"); - } - }); - - //----------------------------- - // contextmenu shareNotebooks - // 删除共享笔记本 - var shareNotebookMenu = { - width: 180, - items: [ - { text: getMsg("deleteSharedNotebook"), icon: "", faIcon: "fa-trash-o", action: Share.deleteShareNotebook } - ], - onShow: applyrule, - onContextMenu: beforeContextMenu, - - parent: "#shareNotebooks", - children: ".notebook-item", - }; - function applyrule(menu) { - return; - } - // 默认共享不能删除 - function beforeContextMenu() { - var notebookId = $(this).attr("notebookId"); - return !Share.isDefaultNotebookId(notebookId); - } - - var menuNotebooks = $("#shareNotebooks").contextmenu(shareNotebookMenu); - - //--------------------------- - // contextmenu shareNotebooks - // 删除某用户所有的 - var shareUserMenu = { - width: 180, - items: [ - { text: getMsg("deleteAllShared"), icon: "", faIcon: "fa-trash-o", action: Share.deleteUserShareNoteAndNotebook } - ], - parent: "#shareNotebooks", - children: ".friend-header", - }; - - var menuUser = $("#shareNotebooks").contextmenu(shareUserMenu); - - $(".friend-header").on("click", ".notebook-setting", function(e) { - e.preventDefault(); - e.stopPropagation(); - var $p = $(this).parent(); - menuUser.showMenu(e, $p); - }); - $("#shareNotebooks .notebook-item").on("click", ".notebook-setting", function(e) { - e.preventDefault(); - e.stopPropagation(); - var $p = $(this).parent(); - menuNotebooks.showMenu(e, $p); - }); -}; - -Share.isDefaultNotebookId = function(notebookId) { - return Share.defaultNotebookId == notebookId; -} - -// 转成共享的nav -// for list和for new -// 如果forNew没有, 那么还是保持我的nav -Share.toggleToSharedNav = function(userId, notebookId) { - var self = this; - // for list - $("#curNotebookForListNote").html(Share.notebookCache[notebookId].Title + '(' + Share.sharedUserInfos[userId].Username + ")"); - - // for new - // 如果该用户下有新建的note, 那么列出, 如果没有, 则列出我的笔记 - var forNew = Share.userNavs[userId].forNew; - if(forNew) { - $("#notebookNavForNewSharedNote").html(forNew); - // 新建之, 可能当前选择的没有权限新建. 此时需要得到第一个 - var curNotebookId = ""; - var curNotebookTitle = ""; - if(Share.notebookCache[notebookId].Perm) { - curNotebookId = notebookId; - curNotebookTitle = Share.notebookCache[notebookId].Title; - } else { - // 得到第一个 - var $f = $("#notebookNavForNewSharedNote li").eq(0); - curNotebookId = $f.attr("notebookId"); - curNotebookTitle = $f.find(".new-note-left").text(); - } - - $("#curNotebookForNewSharedNote").html(curNotebookTitle + '(' + Share.sharedUserInfos[userId].Username + ')'); - $("#curNotebookForNewSharedNote").attr("notebookId", curNotebookId); - $("#curNotebookForNewSharedNote").attr("userId", userId); - - $("#newSharedNote").show(); - $("#newMyNote").hide(); - - } else { - // 展示出我的笔记 - $("#newMyNote").show(); - $("#newSharedNote").hide(); - } - - // 隐藏tag - $("#tagSearch").hide(); -} - -//改变笔记本 -//0. 改变样式 -//1. 改变note, 此时需要先保存 -//2. ajax得到该notebook下的所有note -//3. 使用Note.RederNotes() -Share.changeNotebook = function(userId, notebookId) { - // 选中 - Notebook.selectNotebook($(tt('#friendContainer_? a[notebookId="?"]', userId, notebookId))); - - // 改变nav!!!! TODO - Share.toggleToSharedNav(userId, notebookId); - - // 1 - Note.curChangedSaveIt(); - - // 2 先清空所有 - Note.clearAll(); - - var url = "/share/ListShareNotes/"; - var param = {userId: userId}; - if(!Share.isDefaultNotebookId(notebookId)) { - param.notebookId = notebookId; - } - - // 2 得到笔记本 - // 这里可以缓存起来, note按notebookId缓存 - ajaxGet(url, param, function(ret) { - // note 导航 - // - // 如果是特定笔记本下的notes, 那么传过来的没有权限信息, 此时权限由notebookId决定 - if(param.notebookId) { - - } - Note.renderNotes(ret, false, true); - // 渲染第一个 - // 这里, 有点小复杂, 还要判断权限... - if(!isEmpty(ret)) { - // 定位 - Note.changeNote(ret[0].NoteId, true); - } else { - } - }); -} - -// 是否有更新权限 -// called by Note -Share.hasUpdatePerm = function(notebookId) { - var note = Share.cache[notebookId]; - if(!note || !note.Perm) { - return false; - } - return true; -} - -//--------------------------- -// 我删除别人共享给我的笔记本 -Share.deleteShareNotebook = function(target) { - if(confirm("Are you sure to delete it?")) { - var notebookId = $(target).attr("notebookId"); - var fromUserId = $(target).closest(".friend-notebooks").attr("fromUserId"); // 谁共享给了我 from - ajaxGet("/share/DeleteShareNotebookBySharedUser", {notebookId: notebookId, fromUserId: fromUserId}, function(ret) { - if(ret) { - $(target).parent().remove(); - } - }); - } -} -Share.deleteShareNote = function(target) { - var noteId = $(target).attr("noteId"); - var fromUserId = $(target).attr("fromUserId"); // 谁共享给了我 from - ajaxGet("/share/DeleteShareNoteBySharedUser", {noteId: noteId, fromUserId: fromUserId}, function(ret) { - if(ret) { - $(target).remove(); - } - }); -} -Share.deleteUserShareNoteAndNotebook = function(target) { - if(confirm("Are you sure to delete all shared notebooks and notes?")) { - var fromUserId = $(target).attr("fromUserId"); // 谁共享给了我 from - ajaxGet("/share/deleteUserShareNoteAndNotebook", {fromUserId: fromUserId}, function(ret) { - if(ret) { - $(target).parent().remove(); - } - }); - } -} - -// 新建shared note -Share.changeNotebookForNewNote = function(notebookId) { - // 改变nav for list, for new - Notebook.selectNotebook($(tt('#shareNotebooks [notebookId="?"]', notebookId))); - var userId = Share.notebookCache[notebookId].UserId; - Share.toggleToSharedNav(userId, notebookId); - - // 得到笔记本 - var url = "/share/ListShareNotes/"; - var param = {userId: userId, notebookId: notebookId}; - - // 2 得到笔记本 - // 这里可以缓存起来, note按notebookId缓存 - ajaxGet(url, param, function(ret) { - // note 导航 - Note.renderNotes(ret, true, true); - }); -} - -// 删除笔记, 我有权限, 且是我创建的笔记 -Share.deleteSharedNote = function(target, contextmenuItem) { - Note.deleteNote(target, contextmenuItem, true); -} -Share.copySharedNote = function(target, contextmenuItem) { - Note.copyNote(target, contextmenuItem, true); -} - -Share.contextmenu = null; -Share.initContextmenu = function(notebooksCopy) { - if(Share.contextmenu) { - Share.contextmenu.destroy(); - } - - //--------------------- - // context menu - //--------------------- - var noteListMenu = { - width: 180, - items: [ - { text: getMsg("copyToMyNotebook"), alias: "copy", faIcon: "fa-copy", - type: "group", - width: 180, - items: notebooksCopy - }, - { type: "splitLine" }, - { text: getMsg("delete"), alias: "delete", icon: "", faIcon: "fa-trash-o", action: Share.deleteSharedNote } - ], - onShow: applyrule, - parent: "#noteItemList", - children: ".item-shared", - } - function applyrule(menu) { - var noteId = $(this).attr("noteId"); - var note = Share.cache[noteId]; - if(!note) { - return; - } - var items = []; - if(!(note.Perm && note.CreatedUserId == UserInfo.UserId)) { - items.push("delete"); - } - // 不是自己的创建的不能删除 - menu.applyrule({ - name: "target...", - disable: true, - items: items - }); - - } - - Share.contextmenu = $("#noteItemList .item-shared").contextmenu(noteListMenu); -} - -$(function() { - // note setting - $("#noteItemList").on("click", ".item-shared .item-setting", function(e) { - e.preventDefault(); - e.stopPropagation(); - // 得到ID - var $p = $(this).parent(); - Share.contextmenu.showMenu(e, $p); - }); - - - - //--------------------------- - // 新建笔记 - // 1. 直接点击新建 OR - // 2. 点击nav for new note - $("#newSharedNoteBtn").click(function() { - var notebookId = $("#curNotebookForNewSharedNote").attr('notebookId'); - var userId = $("#curNotebookForNewSharedNote").attr('userId'); - Note.newNote(notebookId, true, userId); - }); - $("#newShareNoteMarkdownBtn").click(function() { - var notebookId = $("#curNotebookForNewSharedNote").attr('notebookId'); - var userId = $("#curNotebookForNewSharedNote").attr('userId'); - Note.newNote(notebookId, true, userId, true); - }); - $("#notebookNavForNewSharedNote").on("click", "li div", function() { - var notebookId = $(this).parent().attr("notebookId"); - var userId = $(this).parent().attr("userId"); - - if($(this).text() == "M") { - Note.newNote(notebookId, true, userId, true); - } else { - Note.newNote(notebookId, true, userId); - } - }); - - //------------------ - // 添加共享 - $("#leanoteDialogRemote").on("click", ".change-perm", function() { - var self = this; - var perm = $(this).attr("perm"); - var noteOrNotebookId = $(this).attr("noteOrNotebookId"); - var toUserId = $(this).attr("toUserId"); - var toHtml = getMsg("writable"); - var toPerm = "1"; - if(perm == "1") { - toHtml = getMsg("readOnly"); - toPerm = "0"; - } - var url = "/share/UpdateShareNotebookPerm"; - var param = {perm: toPerm, toUserId: toUserId}; - if(Share.dialogIsNote) { - url = "/share/UpdateShareNotePerm"; - param.noteId = noteOrNotebookId; - } else { - param.notebookId = noteOrNotebookId; - } - ajaxGet(url, param, function(ret) { - if(ret) { - $(self).html(toHtml); - $(self).attr("perm", toPerm); - } - }); - }); - - $("#leanoteDialogRemote").on("click", ".delete-share", function() { - var self = this; - var noteOrNotebookId = $(this).attr("noteOrNotebookId"); - var toUserId = $(this).attr("toUserId"); - - var url = "/share/DeleteShareNotebook"; - var param = {toUserId: toUserId}; - if(Share.dialogIsNote) { - url = "/share/DeleteShareNote"; - param.noteId = noteOrNotebookId; - } else { - param.notebookId = noteOrNotebookId; - } - - ajaxGet(url, param, function(ret) { - if(ret) { - $(self).parent().parent().remove(); - } - }); - }); - - // 添加共享 - var seq = 1; - $("#leanoteDialogRemote").on("click", "#addShareNotebookBtn", function() { - seq++; - var tpl = '#'; - tpl += ''; - tpl += ' '; - tpl += ''; - tpl += ' '; - tpl += ""; - $("#shareNotebookTable tbody").prepend(tpl); - - $("#tr" + seq + " #friendsEmail").focus(); - }); - - //------------------- - // 发送邀请邮件 - $("#registerEmailBtn").click(function() { - var content = $("#emailContent").val(); - var toEmail = $("#toEmail").val(); - if(!content) { - showAlert("#registerEmailMsg", getMsg("emailBodyRequired"), "danger"); - return; - } - post("/user/sendRegisterEmail", {content: content, toEmail: toEmail}, function(ret) { - showAlert("#registerEmailMsg", getMsg("sendSuccess"), "success"); - hideDialog2("#sendRegisterEmailDialog", 1000); - }, this); - }); -}); - -// trSeq 1,2,3... -function addShareNoteOrNotebook(trSeq) { - var trId = "#tr" + trSeq; - var id = Share.dialogNoteOrNotebookId; - - var emails = isEmailFromInput(trId + " #friendsEmail", "#shareMsg", getMsg("inputFriendEmail")); - if(!emails) { - return; - } - var shareNotePerm = $(trId + ' input[name="perm' + trSeq + '"]:checked').val() || 0; - var perm = shareNotePerm; - // emails = emails.split(";"); - var url = "share/addShareNote"; - var data = {noteId: id, emails: [emails], perm: shareNotePerm}; - if(!Share.dialogIsNote) { - url = "share/addShareNotebook"; - data = {notebookId: id, emails: [emails], perm: shareNotePerm}; - } - hideAlert("#shareMsg"); - post(url, data, function(ret) { - var ret = ret[emails]; - if(ret) { - // 成功 - // 成功了则去掉输入框 - if(ret.Ok) { - var tpl = tt('?', '#'); - tpl += tt('?', emails); - tpl += tt('?', id, perm, ret.Id, !perm || perm == '0' ? getMsg("readOnly") : getMsg("writable")); - tpl += tt('' + getMsg("delete") +'', id, ret.Id); - $(trId).html(tpl); - } else { - var shareUrl = UrlPrefix + '/register?from=' + UserInfo.Username; - showAlert("#shareMsg", getMsg('friendNotExits', [getMsg("app"), shareUrl]) + ' ' + getMsg("clickToCopy") + '
        ' + getMsg("sendInviteEmailToYourFriend") + ', ' + getMsg("send"), "warning"); - $("#copyDiv").text(shareUrl); - initCopy("shareCopy", function(args) { - if(args.text) { - showMsg2("#copyStatus", getMsg("copySuccess"), 1000); - } else { - showMsg2("#copyStatus", getMsg("copyFailed"), 1000); - } - }); - } - } - }, trId + " .btn-success"); -} - -// 发送邀请邮件 -function sendRegisterEmail(email) { - showDialog2("#sendRegisterEmailDialog", {postShow: function() { - $("#emailContent").val(getMsg("inviteEmailBody", [UserInfo.Username, getMsg("app")])); - setTimeout(function() { - $("#emailContent").focus(); - }, 500); - $("#toEmail").val(email); - }}); -} - -function deleteShareNoteOrNotebook(trSeq) { - $("#tr" + trSeq).remove(); -} diff --git a/public/js/app/tag-min.js b/public/js/app/tag-min.js deleted file mode 100644 index 0b50a63..0000000 --- a/public/js/app/tag-min.js +++ /dev/null @@ -1 +0,0 @@ -Tag.classes={"蓝色":"label label-blue","红色":"label label-red","绿色":"label label-green","黄色":"label label-yellow",blue:"label label-blue",red:"label label-red",green:"label label-green",yellow:"label label-yellow"};Tag.mapCn2En={"蓝色":"blue","红色":"red","绿色":"green","黄色":"yellow"};Tag.mapEn2Cn={blue:"蓝色",red:"红色",green:"绿色",yellow:"黄色"};Tag.t=$("#tags");Tag.getTags=function(){var tags=[];Tag.t.children().each(function(){var text=$(this).text();text=text.substring(0,text.length-1);text=Tag.mapCn2En[text]||text;tags.push(text)});return tags};Tag.clearTags=function(){Tag.t.html("")};Tag.renderTags=function(tags){Tag.t.html("");if(isEmpty(tags)){return}for(var i=0;i?',classes,text);$("#noteReadTags").append(tag)}};Tag.appendTag=function(tag){var isColor=false;var classes,text;if(typeof tag=="object"){classes=tag.classes;text=tag.text;if(!text){return}}else{tag=$.trim(tag);text=tag;if(!text){return}var classes=Tag.classes[text];if(classes){isColor=true}else{classes="label label-default"}}if(LEA.locale=="zh"){text=Tag.mapEn2Cn[text]||text}tag=tt('?X',classes,text);$("#tags").children().each(function(){if(isColor){var tagHtml=$("
        ").append($(this).clone()).html();if(tagHtml==tag){$(this).remove()}}else if(text+"X"==$(this).text()){$(this).remove()}});$("#tags").append(tag);hideTagList();if(!isColor){reRenderTags()}};function reRenderTags(){var defautClasses=["label label-default","label label-info"];var i=0;$("#tags").children().each(function(){var thisClasses=$(this).attr("class");if(thisClasses=="label label-default"||thisClasses=="label label-info"){$(this).removeClass(thisClasses).addClass(defautClasses[i%2]);i++}})}Tag.renderTagNav=function(tags){tags=tags||[];for(var i in tags){var tag=tags[i];if(tag=="red"||tag=="blue"||tag=="yellow"||tag=="green"){continue}var text=Tag.mapEn2Cn[tag]||tag;var classes=Tag.classes[tag]||"label label-default";$("#tagNav").append(tt('
      • ?
      • ',text,classes,text))}};$(function(){$("#addTagTrigger").click(function(){$(this).hide();$("#addTagInput").show().focus().val("")});$("#addTagInput").click(function(event){showTagList(event)});$("#addTagInput").blur(function(){var val=$(this).val();if(val){Tag.appendTag(val,true)}return;$("#addTagTrigger").show();$("#addTagInput").hide()});$("#addTagInput").keydown(function(e){if(e.keyCode==13){hideTagList();if($("#addTagInput").val()){$(this).trigger("blur");$("#addTagTrigger").trigger("click")}else{$(this).trigger("blur")}}});$("#tagColor li").click(function(event){var a;if($(this).attr("role")){a=$(this).find("span")}else{a=$(this)}Tag.appendTag({classes:a.attr("class"),text:a.text()})});$("#tags").on("click","i",function(){$(this).parent().remove();reRenderTags()});function searchTag(){var tag=$.trim($(this).data("tag"));Note.curChangedSaveIt();Note.clearAll();$("#tagSearch").html($(this).html()).show();showLoading();ajaxGet("/note/searchNoteByTags",{tags:[tag]},function(notes){hideLoading();if(notes){Note.renderNotes(notes);if(!isEmpty(notes)){Note.changeNote(notes[0].NoteId)}}})}$("#myTag .folderBody").on("click","li",searchTag);$("#minTagNav").on("click","li",searchTag)}); \ No newline at end of file diff --git a/public/js/app/tag.js b/public/js/app/tag.js deleted file mode 100644 index 0a8c27f..0000000 --- a/public/js/app/tag.js +++ /dev/null @@ -1,300 +0,0 @@ -// Tag - -// 蓝色, 红色怎么存到数据库中? 直接存蓝色 - -Tag.classes = { - "蓝色": "label label-blue", - "红色": "label label-red", - "绿色": "label label-green", - "黄色": "label label-yellow", - "blue": "label label-blue", - "red": "label label-red", - "green": "label label-green", - "yellow": "label label-yellow" -} - -// 数据库中统一存En -Tag.mapCn2En = { - "蓝色": "blue", - "红色": "red", - "绿色": "green", - "黄色": "yellow", -} -Tag.mapEn2Cn = { - "blue": "蓝色", - "red": "红色", - "green": "绿色", - "yellow": "黄色", -} - -Tag.t = $("#tags"); - -// called by Note -Tag.getTags = function() { - var tags = []; - Tag.t.children().each(function(){ - var text = $(this).text(); - text = text.substring(0, text.length - 1); // 把X去掉 - text = Tag.mapCn2En[text] || text; - tags.push(text); - }); - // 需要去重吗? 正常情况下不会重复 - return tags; -} - -// called by Note -Tag.clearTags = function() { - Tag.t.html(""); -} - -// 设置tags -// called by Note -Tag.renderTags = function(tags) { - Tag.t.html(""); - if(isEmpty(tags)) { - return; - } - // TODO 重构, 这样不高效 - for(var i = 0; i < tags.length; ++i) { - var tag = tags[i]; - Tag.appendTag(tag); - } -} - -// tag最初状态 -function revertTagStatus() { - $("#addTagTrigger").show(); - $("#addTagInput").hide(); - // hideTagList(); -} - -function hideTagList(event) { - $("#tagDropdown").removeClass("open"); - if (event) { - event.stopPropagation() - } -} -function showTagList(event) { - $("#tagDropdown").addClass("open"); - if (event) { - event.stopPropagation() - } -} - -// 只读模式下显示tags -// called by Note -Tag.renderReadOnlyTags = function(tags) { - // 先清空 - $("#noteReadTags").html(""); - if(isEmpty(tags)) { - $("#noteReadTags").html(getMsg("noTag")); - } - - var i = true; - function getNextDefaultClasses() { - if (i) { - return "label label-default"; - i = false - } else { - i = true; - return "label label-info"; - } - } - - for(var i in tags) { - var text = tags[i]; - text = Tag.mapEn2Cn[text] || text; - var classes = Tag.classes[text]; - if(!classes) { - classes = getNextDefaultClasses(); - } - tag = tt('?', classes, text); - - $("#noteReadTags").append(tag); - } -} - -// 添加tag -// tag = {classes:"label label-red", text:"红色"} -// tag = life -Tag.appendTag = function(tag) { - var isColor = false; - var classes, text; - - if (typeof tag == "object") { - classes = tag.classes; - text = tag.text; - if(!text) { - return; - } - } else { - tag = $.trim(tag); - text = tag; - if(!text) { - return; - } - var classes = Tag.classes[text]; - if(classes) { - isColor = true; - } else { - classes = "label label-default"; - } - } - - if(LEA.locale == "zh") { - text = Tag.mapEn2Cn[text] || text; - } - tag = tt('?X', classes, text); - - // 避免重复 - $("#tags").children().each(function() { - if (isColor) { - var tagHtml = $("
        ").append($(this).clone()).html(); - if (tagHtml == tag) { - $(this).remove(); - } - } else if (text + "X" == $(this).text()) { - $(this).remove(); - } - }); - - $("#tags").append(tag); - - hideTagList(); - - if (!isColor) { - reRenderTags(); - } -} - -// 为了颜色间隔, add, delete时调用 -function reRenderTags() { - var defautClasses = [ "label label-default", "label label-info" ]; - var i = 0; - $("#tags").children().each( - function() { - var thisClasses = $(this).attr("class"); - if (thisClasses == "label label-default" - || thisClasses == "label label-info") { - $(this).removeClass(thisClasses).addClass( - defautClasses[i % 2]); - i++; - } - }); -} - -//----------- -// 左侧nav en -> cn -Tag.renderTagNav = function(tags) { - tags = tags || []; - for(var i in tags) { - var tag = tags[i]; - if(tag == "red" || tag == "blue" || tag == "yellow" || tag == "green") { - continue; - } - var text = Tag.mapEn2Cn[tag] || tag; - var classes = Tag.classes[tag] || "label label-default"; - $("#tagNav").append(tt('
      • ?
      • ', text, classes, text)); - } -} - - -// 事件 -$(function() { - // tag - $("#addTagTrigger").click(function() { - $(this).hide(); - $("#addTagInput").show().focus().val(""); - }); - - $("#addTagInput").click(function(event) { - showTagList(event); - }); - - $("#addTagInput").blur(function() { - var val = $(this).val(); - if(val) { - Tag.appendTag(val, true); - } - return; - // 下面不能有, 有就有问题 - $("#addTagTrigger").show(); - $("#addTagInput").hide(); - // revertTagStatus(); - }); - $('#addTagInput').keydown(function(e) { - if (e.keyCode == 13) { - hideTagList(); - // 如果有值, 再生成, 没值直接隐藏 - if ($("#addTagInput").val()) { - $(this).trigger("blur"); - $("#addTagTrigger").trigger("click"); - } else { - $(this).trigger("blur"); - } - } - }); - // 点击下拉时也会触发input的blur事件 - $("#tagColor li").click(function(event) { - var a; - if($(this).attr("role")) { - a = $(this).find("span"); - } else { - a = $(this); - } - Tag.appendTag({ - classes : a.attr("class"), - text : a.text() - }); - }); - // 这是个问题, 为什么? 捕获不了事件?, input的blur造成 - /* - $(".label").click(function(event) { - var a = $(this); - Tag.appendTag({ - classes : a.attr("class"), - text : a.text() - }); - // event.stopPropagation(); - }); - */ - - $("#tags").on("click", "i", function() { - $(this).parent().remove(); - reRenderTags(); - }); - - //------------- - // nav 标签搜索 - function searchTag() { - var tag = $.trim($(this).data("tag")); - // tag = Tag.mapCn2En[tag] || tag; - - // 学习changeNotebook - - // 1 - Note.curChangedSaveIt(); - - // 2 先清空所有 - // 也会把curNoteId清空 - Note.clearAll(); - - $("#tagSearch").html($(this).html()).show(); - showLoading(); - ajaxGet("/note/searchNoteByTags", {tags: [tag]}, function(notes) { - hideLoading(); - if(notes) { - // 和note搜索一样 - // 设空, 防止发生上述情况 - // Note.curNoteId = ""; - - Note.renderNotes(notes); - if(!isEmpty(notes)) { - Note.changeNote(notes[0].NoteId); - } - } - }); - } - $("#myTag .folderBody").on("click", "li", searchTag); - $("#minTagNav").on("click", "li", searchTag); -}); \ No newline at end of file From 8ef91b74189d6b7fef240c6615e55f011e9b29c5 Mon Sep 17 00:00:00 2001 From: life Date: Sun, 9 Nov 2014 22:14:59 +0800 Subject: [PATCH 05/12] test --- public/js/app/attachment_upload.js | 212 ++++ public/js/app/blog/common.js | 207 ++++ public/js/app/blog/view.js | 509 +++++++++ public/js/app/import_theme.js | 114 ++ public/js/app/note-min.js | 1 + public/js/app/note.js | 1674 ++++++++++++++++++++++++++++ public/js/app/notebook-min.js | 1 + public/js/app/notebook.js | 888 +++++++++++++++ public/js/app/page-min.js | 1 + public/js/app/page.js | 795 +++++++++++++ public/js/app/share-min.js | 1 + public/js/app/share.js | 583 ++++++++++ public/js/app/tag-min.js | 1 + public/js/app/tag.js | 300 +++++ 14 files changed, 5287 insertions(+) create mode 100644 public/js/app/attachment_upload.js create mode 100644 public/js/app/blog/common.js create mode 100644 public/js/app/blog/view.js create mode 100644 public/js/app/import_theme.js create mode 100644 public/js/app/note-min.js create mode 100644 public/js/app/note.js create mode 100644 public/js/app/notebook-min.js create mode 100644 public/js/app/notebook.js create mode 100644 public/js/app/page-min.js create mode 100644 public/js/app/page.js create mode 100644 public/js/app/share-min.js create mode 100644 public/js/app/share.js create mode 100644 public/js/app/tag-min.js create mode 100644 public/js/app/tag.js diff --git a/public/js/app/attachment_upload.js b/public/js/app/attachment_upload.js new file mode 100644 index 0000000..8b25956 --- /dev/null +++ b/public/js/app/attachment_upload.js @@ -0,0 +1,212 @@ +// upload attachment +// 依赖note +var urlPrefix = UrlPrefix; +define('attachment_upload', ['jquery.ui.widget', 'fileupload'], function(){ + // Helper function that formats the file sizes + function formatFileSize(bytes) { + if (typeof bytes !== 'number') { + return ''; + } + if (bytes >= 1000000000) { + return (bytes / 1000000000).toFixed(2) + ' GB'; + } + if (bytes >= 1000000) { + return (bytes / 1000000).toFixed(2) + ' MB'; + } + return (bytes / 1000).toFixed(2) + ' KB'; + } + + function setDropStyle(dropzoneId, formId) { + // drag css + var dropZone = $(dropzoneId); + $(formId).bind('dragover', function (e) { + e.preventDefault(); + var timeout = window.dropZoneTimeoutAttach; + if(timeout) { + clearTimeout(timeout); + } + + var found = false, + node = e.target; + do { + if (node === dropZone[0]) { + found = true; + break; + } + node = node.parentNode; + } while (node != null); + if (found) { + dropZone.addClass('hover'); + } else { + dropZone.removeClass('hover'); + } + window.dropZoneTimeoutAttach = setTimeout(function () { + window.dropZoneTimeoutAttach = null; + dropZone.removeClass('in hover'); + }, 100); + }); + } + + setDropStyle("#dropAttach", "#uploadAttach"); + setDropStyle("#dropAvatar", "#uploadAvatar"); + + var initUploader = function() { + $('.dropzone .btn-choose-file').click(function() { + $(this).parent().find('input').click(); + }); + + var $msg = $('#attachUploadMsg'); + // Initialize the jQuery File Upload plugin + $('#uploadAttach').fileupload({ + dataType: 'json', + // This element will accept file drag/drop uploading + dropZone: $('#dropAttach'), + formData: function(form) { + return [{name: 'noteId', value: Note.curNoteId}] // 传递笔记本过去 + }, + // This function is called when a file is added to the queue; + // either via the browse button, or via drag/drop: + add: function(e, data) { + var note = Note.getCurNote(); + if(!note || note.IsNew) { + alert("This note hasn't saved, please save it firstly!") + return; + } + var tpl = $(''); + + // Append the file name and file size + tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); + + // Add the HTML to the UL element + $msg.html(tpl); + data.context = $msg; + + // 检查文件大小 + var size = data.files[0].size; + var maxFileSize = +GlobalConfigs["uploadAttachSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { + tpl.find("img").remove(); + tpl.removeClass("alert-info").addClass("alert-danger"); + tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + return; + } + + // Automatically upload the file once it is added to the queue + var jqXHR; + setTimeout(function() { + jqXHR = data.submit(); + }, 10); + }, + /* + progress: function (e, data) { + }, + */ + done: function(e, data) { + if (data.result.Ok == true) { + data.context.html(""); + Attach.addAttach(data.result.Item); + } else { + var re = data.result; + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + $("#uploadAttachMsg").scrollTop(1000); + }, + fail: function(e, data) { + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + + $("#uploadAttachMsg").scrollTop(1000); + } + }); + + //------------------- + + var $msg2 = $('#avatarUploadMsg'); + $('#uploadAvatar').fileupload({ + dataType: 'json', + dropZone: $('#dropAvatar'), + add: function(e, data) { + var tpl = $(''); + + // Append the file name and file size + tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); + + // Add the HTML to the UL element + $msg2.html(tpl); + data.context = $msg2; + + // 检查文件大小 + var size = data.files[0].size; + var maxFileSize = +GlobalConfigs["uploadAvatarSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { + tpl.find("img").remove(); + tpl.removeClass("alert-info").addClass("alert-danger"); + tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + return; + } + + // Automatically upload the file once it is added to the queue + var jqXHR; + setTimeout(function() { + jqXHR = data.submit(); + }, 10); + }, + done: function(e, data) { + if (data.result.Ok == true) { + data.context.html(""); + var re = data.result; + $("#avatar").attr("src", UrlPrefix + "/" + re.Id); + } else { + var re = data.result; + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + }, + fail: function(e, data) { + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + }); + } + + initUploader(); +}); \ No newline at end of file diff --git a/public/js/app/blog/common.js b/public/js/app/blog/common.js new file mode 100644 index 0000000..be4e505 --- /dev/null +++ b/public/js/app/blog/common.js @@ -0,0 +1,207 @@ +// 返回是否是re.Ok == true +function reIsOk(re) { + return re && typeof re == "object" && re.Ok; +} +function showAlert(id, msg, type, id2Focus) { + $(id).html(msg).removeClass("alert-danger").removeClass("alert-success").removeClass("alert-warning").addClass("alert-" + type).show(); + if(id2Focus) { + $(id2Focus).focus(); + } +} +function hideAlert(id, timeout) { + if(timeout) { + setTimeout(function() { + $(id).hide(); + }, timeout); + } else { + $(id).hide(); + } +} +function ajaxGet(url, param, func) { + $.get(url, param, func); +} +function ajaxPost(url, param, func) { + $.post(url, param, func); +} +function goLogin(){ + var loginUrl = urlPrefix + '/login?from=' + encodeURI(location.href); + location.href = loginUrl; +} +function goRegister() { + var registerUrl = urlPrefix + '/register?from=' + encodeURI(location.href); + location.href = registerUrl; +} +function needLogin() { + if(typeof visitUserInfo == "undefined" || !visitUserInfo || !visitUserInfo.UserId) { + // 弹框之 + var loginUrl = urlPrefix + '/login?from=' + encodeURI(location.href); + var registerUrl = urlPrefix + '/register?from=' + encodeURI(location.href); + var modal = BootstrapDialog.show({ + title: "你还未登录", + message: '
        立即登录, 发表评论.
        没有帐号? 立即注册', + nl2br: false + }); + return true; + } + return false; +} +function scrollToTarget(t, fixed) { + if(!fixed) { + fixed = 0; + } + var $t = $(t) + var targetOffset = $t.offset().top + fixed; + $('html,body').animate({scrollTop: targetOffset}, 300); +} + +var windowParam = 'width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no'; +function getShareUrl(noteId) { + return viewUrl + "/" + noteId; +} +function getShareTitle(title) { + return encodeURI(title + " (来自leanote.com)"); +} +function shareSinaWeibo(noteId, title, pic) { + var url = "http://service.weibo.com/share/share.php?title=" + getShareTitle(title) + "&url=" + getShareUrl(noteId); + window.open(url, 'Share', windowParam); +} +function shareTencentWeibo(noteId, title, pic) { + var _appkey = '801542571'; + var url = "http://share.v.t.qq.com/index.php?c=share&a=index&appkey=" + _appkey +"&title=" + getShareTitle(title) + "&url=" + getShareUrl(noteId) +"&pic=" + pic; + window.open(url, 'Share', windowParam); +} +function shareQQ(noteId, title, pic) { + var url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + getShareUrl(noteId) + '&title=' + title + '&pics=' + pic; + window.open(url, 'Share', windowParam); +} +function shareRenRen(noteId, title, pic) { + var url = 'http://widget.renren.com/dialog/share?resourceUrl=' + getShareUrl(noteId) + '&srcUrl=' + getShareUrl(noteId) + '&title=' + getShareTitle(title) + '&pic=' + pic; + window.open(url, 'Share', windowParam); +} + +// https://twitter.com/intent/tweet?text=&pic= +function shareTwitter(noteId, title, pic) { + var url = 'https://twitter.com/intent/tweet?text=' + getShareTitle(title) + '&pic=' + pic; + window.open(url, 'Share', windowParam); +} +// http://www.facebook.com/sharer.php?u=&t=” +function shareFacebook(noteId, title, pic) { + var url = ' http://www.facebook.com/sharer.php?t=' + getShareTitle(title) + '&pic=' + pic; + window.open(url, 'Share', windowParam); +} + +//JavaScript函数: +var minute = 1000 * 60; +var hour = minute * 60; +var day = hour * 24; +var halfamonth = day * 15; +var month = day * 30; +// 2014-01-06T18:29:48.802+08:00 + +function goNowToDatetime(goNow) { + if(!goNow) { + return ""; + } + return goNow.substr(0, 10) + " " + goNow.substr(11, 8); +} +function getDateDiff(dateTimeStamp){ + var now = new Date().getTime(); + var diffValue = now - dateTimeStamp; + if(diffValue < 0){ + return ""; + } + var monthC =diffValue/month; + var weekC =diffValue/(7*day); + var dayC =diffValue/day; + var hourC =diffValue/hour; + var minC =diffValue/minute; + if(monthC>=1){ + result=parseInt(monthC) + getMsg("monthsAgo"); + } + else if(weekC>=1){ + result=parseInt(weekC) + getMsg("weeksAgo"); + } + else if(dayC>=1){ + result=parseInt(dayC) + getMsg("daysAgo"); + } + else if(hourC>=1){ + result=parseInt(hourC) + getMsg("hoursAgo"); + } + else if(minC>=1){ + result=parseInt(minC) + getMsg("minutesAgo"); + }else { + result=getMsg("justNow"); + } + return result; +} + +function weixin() { + var local=window.location.href; + var title = $.trim($(".title").text()); + var desc = $.trim($("#desc").text()); + var imgUrl = $("#content img").eq(0).attr('src'); + window.shareData = { + "imgUrl": imgUrl, + "timeLineLink":local, + "sendFriendLink": local, + "weiboLink":local, + "tTitle": title, + "tContent": desc, + "fTitle": title, + "fContent": desc, + "wContent": desc + }; + document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() { + // 发送给好友 + WeixinJSBridge.on('menu:share:appmessage', function (argv) { + WeixinJSBridge.invoke('sendAppMessage', { + "img_url": window.shareData.imgUrl, + "img_width": "200", + "link": window.shareData.sendFriendLink, + "desc": window.shareData.fContent, + "title": window.shareData.fTitle + }, function (res) { + hs_guide('none'); + _report('send_msg', res.err_msg); + }) + }); + + // 分享到朋友圈 + WeixinJSBridge.on('menu:share:timeline', function (argv) { + WeixinJSBridge.invoke('shareTimeline', { + "img_url": window.shareData.imgUrl, + "img_width": "200", + "link": window.shareData.timeLineLink, + "desc": window.shareData.tContent, + "title": window.shareData.tTitle + }, function (res) { + hs_guide('none'); + _report('timeline', res.err_msg); + }); + }); + + // 分享到微博 + WeixinJSBridge.on('menu:share:weibo', function (argv) { + WeixinJSBridge.invoke('shareWeibo', { + "content": window.shareData.wContent, + "url": window.shareData.weiboLink, + }, function (res) { + hs_guide('none'); + _report('weibo', res.err_msg); + }); + }); + }, false); +} + +var LEA = {isMobile: false}; +function isMobile() { + var u = navigator.userAgent; + LEA.isMobile = false; + LEA.isMobile = /Mobile|Android|iPhone/i.test(u); + if(!LEA.isMobile && $(document).width() <= 600){ + LEA.isMobile = true + } +} +$(function() { + isMobile(); +}); \ No newline at end of file diff --git a/public/js/app/blog/view.js b/public/js/app/blog/view.js new file mode 100644 index 0000000..8bb7b09 --- /dev/null +++ b/public/js/app/blog/view.js @@ -0,0 +1,509 @@ +function scrollTo(self, tagName, text) { + var iframe = $("#content"); + var target = iframe.find(tagName + ":contains(" + text + ")"); + + // 找到是第几个 + // 在nav是第几个 + var navs = $('#blogNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]'); + var len = navs.size(); + for(var i = 0; i < len; ++i) { + if(navs[i] == self) { + break; + } + } + + if (target.size() >= i+1) { + target = target.eq(i); + // 之前插入, 防止多行定位不准 + var top = target.offset().top; + if(LEA.isMobile) { + top -= 50; + } + var nowTop = $(document).scrollTop(); + // 用$("body").scrllTop(10)没反应 firefox下 + $('html,body').animate({scrollTop: top}, 200); + return; + } +} +function genNav() { + var $con = $("#content"); + var html = $con.html(); + // 构造一棵树 + // {"h1-title":{h2-title:{}}} + var tree = [];//[{title: "xx", children:[{}]}, {title:"xx2"}]; + var hs = $con.find("h1,h2,h3,h4,h5,h6").toArray(); + var titles = '
          '; + for(var i = 0; i < hs.length; ++i) { + var text = $(hs[i]).text(); + var tagName = hs[i].tagName.toLowerCase(); + // scrollTo在page.js中定义 + titles += ''; + } + titles += "
        "; + $("#blogNavContent").html(titles); + if(!hs.length) { + $("#blogNavContent").html(getMsg("none")); + return false; + } + return true; +} + +function initNav() { + var hasNav = genNav(); + if(!hasNav) { + return; + } + + var $title = $(".title"); + var titlePos = $title.offset(); + var top = titlePos.top + 10;// - $title.height(); + // 手机下不要与标题在同一高度 + if(LEA.isMobile){ + top += 30; + } + if(top < 0) { + top = 10; + } + + var left = $title.width() + titlePos.left - 100; + $("#blogNav").css("top", top).css("left", left); + $("#blogNav").show(); + + $("#blogNavNav").click(function() { + var $o = $("#blogNavContent"); + if($o.is(":hidden")) { + $o.show(); + } else { + $o.hide(); + } + }); + + var $d = $(document); + function reNav() { + var vtop = $d.scrollTop(); + if(vtop <= top) { + $("#blogNav").css("top", top-vtop); + } else { + // 差距很磊了 + if(LEA.isMobile) { + $("#blogNav").css("top", 50); + } else { + $("#blogNav").css("top", 10); + } + } + } + reNav(); + $(window).scroll(reNav); +} + +var C = { + info: null, + noteId: noteId, + preLikeNum: preLikeNum, + commentNum: commentNum, + likeBtnO: $("#likeBtn"), + likeNumO: $("#likeNum"), + tLikersO: $("#tLikers"), + likersO: $("#likers"), + tCommentsO: $("#tComments"), + commentsO: $("#comments"), + + commentBtnO: $("#commentBtn"), + + commentsLoadingO: $(".comments-loading"), + commentsMoreO: $(".comments-more"), + + commentBoxO: $(".comment-box"), + init: function() { + var self = this; + if(UserBlogInfo.CanComment && UserBlogInfo.CommentType != "disqus") { + self.initLikeAndComments(); + } else { + self.initLike(); + } + self.initEvent(); + self.incReadNum(); + }, + incReadNum: function() { + var self = this; + if(!$.cookie(self.noteId)) { + $.cookie(self.noteId, 1); + ajaxGet(staticUrl + "/blog/incReadNum", {noteId: self.noteId}); + } + }, + initLike: function() { + var self = this; + ajaxGet(staticUrl + "/blog/getLike", {noteId: self.noteId}, function(ret) { + self.info = ret; + self.toggleLikeBtnActive(); + self.renderLikers(); + }); + }, + initLikeAndComments: function() { + var self = this; + ajaxGet(staticUrl + "/blog/getLikeAndComments", {noteId: self.noteId}, function(ret) { + self.info = ret; + self.toggleLikeBtnActive(); + self.renderLikers(); + // 是否需要renderComments? + self.info.commentUserInfo = self.info.commentUserInfo || {}; + // 为了防止第一条评论找不到用户信息情况 + if(visitUserInfo.UserId) { + self.info.commentUserInfo[visitUserInfo.UserId] = visitUserInfo; + } + self.renderComments(); + + self.commentBoxO.removeClass("hide"); + self.commentsLoadingO.addClass("hide"); + if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) { + self.commentsMoreO.removeClass("hide"); + self.initMoreComments(); + } + }); + }, + initMoreComments: function() { + var self = this; + self.commentsMoreO.find("a").click(function(){ + if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) { + self.commentsMoreO.addClass("hide"); + self.commentsLoadingO.removeClass("hide"); + ajaxGet(staticUrl + "/blog/listComments", {noteId: self.noteId, page: self.info.pageInfo.CurPage+1}, function(ret) { + var pageInfo = ret.pageInfo; + var comments = ret.comments; + var commentUserInfo = ret.commentUserInfo; + + $.extend(self.info.commentUserInfo, commentUserInfo); + + // 渲染之 + for(var i in comments) { + var comment = comments[i]; + comment = self.parseComment(comment); + } + var html = self.tCommentsO.render({comments: comments, visitUserInfo: visitUserInfo}); + self.commentsO.append(html); + + self.info.pageInfo = pageInfo; + + if(self.info.pageInfo.TotalPage > self.info.pageInfo.CurPage) { + self.commentsMoreO.removeClass("hide"); + } else { + self.commentsMoreO.addClass("hide"); + } + + self.commentsLoadingO.addClass("hide"); + }); + } + }); + }, + addCommentRender: function(comment){ + var self = this; + comment = self.parseComment(comment); + var html = self.tCommentsO.render({blogUrl: blogUrl, comments: [comment], visitUserInfo: visitUserInfo}); + self.commentsO.prepend(html); + var li = self.commentsO.find("li").eq(0); + li.hide(); + li.show(500); + li.addClass("item-highlight"); + setTimeout(function() { + li.removeClass("item-highlight"); + }, 2000); + }, + parseComment: function(comment) { + var self = this; + var authorUserId = UserInfo.UserId; + commentUserInfo = self.info.commentUserInfo; + comment.UserInfo = commentUserInfo[comment.UserId]; + // 是作者自己 + if(visitUserInfo.UserId == UserInfo.UserId) { + comment.IsMyNote = true; + } + if(comment.UserId == authorUserId) { + comment.IsAuthorComment = true; + } + if(comment.UserId == visitUserInfo.UserId) { + comment.IsMyComment = true; + } + // 不是回复自己 + if(comment.ToUserId && comment.ToUserId != comment.UserId) { + comment.ToUserInfo = commentUserInfo[comment.ToUserId]; + if(comment.ToUserInfo.UserId == UserInfo.UserId) { + comment.ToUserIsAuthor = true; + } + } + comment.PublishDate = getDateDiff(Date.parse(goNowToDatetime(comment.CreatedTime))); + return comment; + }, + // 渲染评论 + renderComments: function() { + var self = this; + var comments = self.info.comments || []; + if(comments.length == 0) { + return; + } + + // 整理数据 + // 回复谁, 是否是作者? + // 回复日期, 几天前, 刚刚 + for(var i in comments) { + var comment = comments[i]; + comment = self.parseComment(comment); + } + var html = self.tCommentsO.render({blogUrl: blogUrl, comments: comments, visitUserInfo: visitUserInfo}); + self.commentsO.html(html); + }, + + // 重新渲染likers + reRenderLikers: function(addMe) { + var self = this; + var likedUsers = self.info.likedUsers || []; + for(var i = 0; i < likedUsers.length; ++i) { + var user = likedUsers[i]; + if(user.UserId == visitUserInfo.UserId) { + likedUsers.splice(i, 1); + break; + } + } + if(addMe) { + likedUsers = [visitUserInfo].concat(likedUsers); + self.info.likedUsers = likedUsers; + } + self.renderLikers(); + }, + renderLikers: function() { + var self = this; + var users = self.info.likedUsers || []; + var html = self.tLikersO.render({blogUrl: blogUrl, users: users}); + self.likersO.html(html); + }, + toggleLikeBtnActive: function() { + var self = this; + if(self.info.isILikeIt) { + self.likeBtnO.addClass("active"); + } else { + self.likeBtnO.removeClass("active"); + } + }, + commentNumO: $("#commentNum"), + bindCommentNum: function(fix) { + var self = this; + self.commentNum += fix; + self.commentNumO.text(self.commentNum); + }, + initEvent: function() { + var self = this; + + // like or not + self.likeBtnO.click(function() { + if(!visitUserInfo.UserId) { + needLogin(); + return; + } + ajaxPost(staticUrl + "/blog/likeBlog", {noteId: self.noteId}, function(ret) { + if(ret.Ok) { + // like + if(ret.Item) { + var num = self.preLikeNum+1; + } else { + var num = self.preLikeNum-1; + } + self.preLikeNum = num >= 0 ? num : 0; + self.likeNumO.text(self.preLikeNum); + self.info.isILikeIt = ret.Item; + self.toggleLikeBtnActive(); + + // 重新render likers + // 我是否在列表中 + self.reRenderLikers(ret.Item); + } + }); + }); + + // 显示回复回复 + $("#comments").on("click", ".comment-reply", function() { + var form = $(this).closest("li").find("form"); + if(form.is(":hidden")) { + form.show(); + form.find("textarea").focus(); + } else { + form.hide(); + } + }); + $("#comments").on("click", ".reply-cancel", function() { + $(this).closest("form").hide(); + }); + + // 回复 + $(".comment-box").on("click", ".reply-comment-btn", function(e) { + e.preventDefault(); + var commentId = $(this).data("comment-id"); + var $form = $(this).closest("form"); + var $content = $form.find("textarea"); + var content = $.trim($content.val()); + if(!content) { + $content.focus(); + return; + } + var t = $(this); + t.button("loading"); + var data = {noteId: self.noteId, toCommentId: commentId, content: content}; + ajaxPost(staticUrl + "/blog/comment", data, function(ret) { + t.button("reset"); + $content.val(""); + self.bindCommentNum(1); + if(commentId) { + $form.hide(); + } + + if(commentId) { + scrollToTarget("#comments", -200); + } + + // 添加一个 + self.addCommentRender(ret.Item); + }); + }); + + // 删除 + $(".comment-box").on("click", ".comment-trash", function(e) { + var commentId = $(this).parent().data("comment-id"); + var t = this; + BootstrapDialog.confirm(getMsg("confirmDeleteComment"), function(yes) { + if(yes) { + ajaxPost(staticUrl + "/blog/deleteComment", {noteId: self.noteId, commentId: commentId}, function(ret) { + if(ret.Ok) { + var li = $(t).closest("li"); + li.hide(500); // remove(); + setTimeout(function() { + li.remove(); + }, 300); + + self.bindCommentNum(-1); + } + }); + } + }); + }); + + // 点zan + $(".comment-box").on("click", ".comment-like", function(e) { + var commentId = $(this).parent().data("comment-id"); + var t = this; + + ajaxPost(staticUrl + "/blog/likeComment", {commentId: commentId}, function(re) { + if(re.Ok) { + var ret = re.Item; + if(ret.Num <= 0) { + $(t).parent().find(".like-num").addClass("hide"); + } else { + $(t).parent().find(".like-num").removeClass("hide"); + $(t).parent().find(".like-num-i").text(ret.Num) + } + if(ret.IsILikeIt) { + $(t).find(".like-text").text(getMsg("unlike")); + } else { + $(t).find(".like-text").text(getMsg('like')); + } + } + }); + }); + + // 举报 + function report(commentId, noteId, title) { + var form = $("#reportMsg").html(); + var body; + var input; + var isOver = false; + var modal = BootstrapDialog.show({ + title: title, + message: form, + nl2br: false, + buttons: [{ + label: getMsg("cancel"), + action: function(dialog) { + dialog.close(); + } + }, { + label: getMsg("confirm"), + cssClass: 'btn-primary', + action: function(dialog) { + if(isOver) { + dialog.close(); + } + var val = body.find("input[type='radio']:checked").val(); + if(!val) { + var val = body.find(".input-container input").val(); + } + if(!val) { + body.find(".footnote").html(getMsg("chooseReason")); + return; + } + ajaxPost(staticUrl + "/blog/report", {commentId: commentId, noteId: noteId, reason: val}, function(re) { + isOver = true; + if(reIsOk(re)) { + body.html(getMsg("reportSuccess")); + } else { + body.html(getMsg("error")); + } + setTimeout(function() { + dialog.close(); + }, 3000); + }); + } + }] + }); + body = modal.getModalBody(); + input = body.find(".input-container"); + body.find("input[type='radio']").click(function(){ + if(!$(this).val()) { + input.show(); + input.find("input").focus(); + } else { + input.hide(); + } + }); + } + $(".comment-box").on("click", ".comment-report", function() { + if(needLogin()) { + return; + } + var commentId = $(this).parent().data("comment-id"); + report(commentId, self.noteId, getMsg("reportComment?")); + }); + $("#reportBtn").click(function() { + if(needLogin()) { + return; + } + report("", self.noteId, getMsg("reportBlog?")); + }); + + self.initShare(); + }, + weixinQRCodeO: $("#weixinQRCode"), + initShare: function() { + var self = this; + $(".btn-weixin").click(function() { + if(!self.weixinQRCodeO.html()) { + self.weixinQRCodeO.qrcode(viewUrl + "/" + self.noteId); + } + BootstrapDialog.show({ + title: getMsg('scanQRCode'), + message: self.weixinQRCodeO + }); + }); + + $(".btn-share").click(function() { + var $this = $(this); + var map = {"btn-weibo": shareSinaWeibo, "tencent-weibo": shareTencentWeibo, "qq": shareQQ, "renren": shareRenRen}; + for(var i in map) { + if($this.hasClass(i)) { + map[i](self.noteId, document.title); + break; + } + } + }); + } +} + +$(function() { + C.init(); +}); \ No newline at end of file diff --git a/public/js/app/import_theme.js b/public/js/app/import_theme.js new file mode 100644 index 0000000..83f7b52 --- /dev/null +++ b/public/js/app/import_theme.js @@ -0,0 +1,114 @@ +define('import_theme', ['jquery.ui.widget', 'fileupload'], function(){ + // Helper function that formats the file sizes + function formatFileSize(bytes) { + if (typeof bytes !== 'number') { + return ''; + } + if (bytes >= 1000000000) { + return (bytes / 1000000000).toFixed(2) + ' GB'; + } + if (bytes >= 1000000) { + return (bytes / 1000000).toFixed(2) + ' MB'; + } + return (bytes / 1000).toFixed(2) + ' KB'; + } + + function setDropStyle(dropzoneId, formId) { + // drag css + var dropZone = $(dropzoneId); + $(formId).bind('dragover', function (e) { + e.preventDefault(); + var timeout = window.dropZoneTimeoutAttach; + if(timeout) { + clearTimeout(timeout); + } + + var found = false, + node = e.target; + do { + if (node === dropZone[0]) { + found = true; + break; + } + node = node.parentNode; + } while (node != null); + if (found) { + dropZone.addClass('hover'); + } else { + dropZone.removeClass('hover'); + } + window.dropZoneTimeoutAttach = setTimeout(function () { + window.dropZoneTimeoutAttach = null; + dropZone.removeClass('in hover'); + }, 100); + }); + } + + setDropStyle("#dropAvatar", "#uploadAvatar"); + + var initUploader = function() { + $('.dropzone .btn-choose-file').click(function() { + $(this).parent().find('input').click(); + }); + + var $msg2 = $('#avatarUploadMsg'); + $('#uploadAvatar').fileupload({ + dataType: 'json', + dropZone: $('#dropAvatar'), + add: function(e, data) { + var tpl = $(''); + + // Append the file name and file size + tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); + + // Add the HTML to the UL element + $msg2.html(tpl); + data.context = $msg2; + + // 检查文件大小 + var size = data.files[0].size; + if(typeof size == 'number' && size > 10 * 1024 * 1024) { + tpl.find("img").remove(); + tpl.removeClass("alert-info").addClass("alert-danger"); + tpl.append("Warning: File size is bigger than 10M"); + return; + } + + // Automatically upload the file once it is added to the queue + var jqXHR; + setTimeout(function() { + jqXHR = data.submit(); + }, 10); + }, + done: function(e, data) { + if (data.result.Ok == true) { + data.context.html(""); + var re = data.result; + art.tips("Success"); + setTimeout(function() { + location.reload(); + }, 1000); + } else { + var re = data.result; + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); + data.context.html(tpl); + } + }, + fail: function(e, data) { + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + }); + } + + initUploader(); +}); \ No newline at end of file diff --git a/public/js/app/note-min.js b/public/js/app/note-min.js new file mode 100644 index 0000000..639279c --- /dev/null +++ b/public/js/app/note-min.js @@ -0,0 +1 @@ +Note.curNoteId="";Note.interval="";Note.itemIsBlog='
        ';Note.itemTplNoImg='
      • ';Note.itemTplNoImg+=Note.itemIsBlog+'

        ?

        ? ?

        ?

      • ';Note.itemTpl='
      • ';Note.itemTpl+=Note.itemIsBlog+'

        ?

        ? ?

        ?

      • ';Note.newItemTpl='
      • ';Note.newItemTpl+=Note.itemIsBlog+'

        ?

        ? ?
        ?

      • ';Note.noteItemListO=$("#noteItemList");Note.cacheByNotebookId={all:{}};Note.notebookIds={};Note.isReadOnly=false;Note.intervalTime=6e5;Note.startInterval=function(){Note.interval=setInterval(function(){log("自动保存开始...");changedNote=Note.curChangedSaveIt(false)},Note.intervalTime)};Note.stopInterval=function(){clearInterval(Note.interval);setTimeout(function(){Note.startInterval()},Note.intervalTime)};Note.addNoteCache=function(note){Note.cache[note.NoteId]=note;Note.clearCacheByNotebookId(note.NotebookId)};Note.setNoteCache=function(content,clear){if(!Note.cache[content.NoteId]){Note.cache[content.NoteId]=content}else{$.extend(Note.cache[content.NoteId],content)}if(clear==undefined){clear=true}if(clear){Note.clearCacheByNotebookId(content.NotebookId)}};Note.getCurNote=function(){var self=this;if(self.curNoteId==""){return null}return self.cache[self.curNoteId]};Note.getNote=function(noteId){var self=this;return self.cache[noteId]};Note.clearCacheByNotebookId=function(notebookId){if(notebookId){Note.cacheByNotebookId[notebookId]={};Note.cacheByNotebookId["all"]={};Note.notebookIds[notebookId]=true}};Note.notebookHasNotes=function(notebookId){var notes=Note.getNotesByNotebookId(notebookId);return!isEmpty(notes)};Note.getNotesByNotebookId=function(notebookId,sortBy,isAsc){if(!sortBy){sortBy="UpdatedTime"}if(isAsc=="undefined"){isAsc=false}if(!notebookId){notebookId="all"}if(!Note.cacheByNotebookId[notebookId]){return[]}if(Note.cacheByNotebookId[notebookId][sortBy]){return Note.cacheByNotebookId[notebookId][sortBy]}else{}var notes=[];var sortBys=[];for(var i in Note.cache){if(!i){continue}var note=Note.cache[i];if(note.IsTrash||note.IsShared){continue}if(notebookId=="all"||note.NotebookId==notebookId){notes.push(note)}}notes.sort(function(a,b){var t1=a[sortBy];var t2=b[sortBy];if(isAsc){if(t1t2){return 1}}else{if(t1t2){return-1}}return 0});Note.cacheByNotebookId[notebookId][sortBy]=notes;return notes};Note.renderNotesAndFirstOneContent=function(ret){if(!isArray(ret)){return}Note.renderNotes(ret);if(!isEmpty(ret[0])){Note.changeNote(ret[0].NoteId)}else{}};Note.curHasChanged=function(force){if(force==undefined){force=true}var cacheNote=Note.cache[Note.curNoteId]||{};var title=$("#noteTitle").val();var tags=Tag.getTags();var contents=getEditorContent(cacheNote.IsMarkdown);var content,preview;var contentText;if(isArray(contents)){content=contents[0];preview=contents[1];contentText=content;if(content&&previewIsEmpty(preview)&&Converter){preview=Converter.makeHtml(content)}if(!content){preview=""}cacheNote.Preview=preview}else{content=contents;try{contentText=$(content).text()}catch(e){}}var hasChanged={hasChanged:false,IsNew:cacheNote.IsNew,IsMarkdown:cacheNote.IsMarkdown,FromUserId:cacheNote.FromUserId,NoteId:cacheNote.NoteId,NotebookId:cacheNote.NotebookId};if(hasChanged.IsNew){$.extend(hasChanged,cacheNote)}if(cacheNote.Title!=title){hasChanged.hasChanged=true;hasChanged.Title=title;if(!hasChanged.Title){}}if(!arrayEqual(cacheNote.Tags,tags)){hasChanged.hasChanged=true;hasChanged.Tags=tags}if(force&&cacheNote.Content!=content||!force&&$(cacheNote.Content).text()!=contentText){hasChanged.hasChanged=true;hasChanged.Content=content;var c=preview||content;hasChanged.Desc=Note.genDesc(c);hasChanged.ImgSrc=Note.getImgSrc(c);hasChanged.Abstract=Note.genAbstract(c)}else{log("text相同");log(cacheNote.Content==content)}hasChanged["UserId"]=cacheNote["UserId"]||"";return hasChanged};Note.genDesc=function(content){if(!content){return""}content=content.replace(/
        /g,"
        ");content=content.replace(/<\/p>/g,"

        ");content=content.replace(/<\/div>/g,"
        ");content=$("
        ").html(content).text();content=content.replace(//g,">");if(content.length<300){return content}return content.substring(0,300)};Note.genAbstract=function(content,len){if(len==undefined){len=1e3}if(content.length"&&isCode){n=n-1;isCode=false}else if(temp==";"&&isHTML){isHTML=false}if(!isCode&&!isHTML){n=n+1}result+=temp;if(n>=maxLen){break}}var d=document.createElement("div");d.innerHTML=result;return d.innerHTML};Note.getImgSrc=function(content){if(!content){return""}var imgs=$(content).find("img");for(var i in imgs){var src=imgs.eq(i).attr("src");if(src){return src}}return""};Note.curChangedSaveIt=function(force){if(!Note.curNoteId||Note.isReadOnly){return}var hasChanged=Note.curHasChanged(force);Note.renderChangedNote(hasChanged);if(hasChanged.hasChanged||hasChanged.IsNew){delete hasChanged.hasChanged;Note.setNoteCache(hasChanged,false);Note.setNoteCache({NoteId:hasChanged.NoteId,UpdatedTime:(new Date).format("yyyy-MM-ddThh:mm:ss.S")},false);showMsg(getMsg("saving"));ajaxPost("/note/UpdateNoteOrContent",hasChanged,function(ret){if(hasChanged.IsNew){ret.IsNew=false;Note.setNoteCache(ret,false)}showMsg(getMsg("saveSuccess"),1e3)});return hasChanged}return false};Note.selectTarget=function(target){$(".item").removeClass("item-active");$(target).addClass("item-active")};Note.showContentLoading=function(){$("#noteMaskForLoading").css("z-index",99999)};Note.hideContentLoading=function(){$("#noteMaskForLoading").css("z-index",-1)};Note.contentAjax=null;Note.contentAjaxSeq=1;Note.changeNote=function(selectNoteId,isShare,needSaveChanged){var self=this;Note.stopInterval();var target=$(tt('[noteId="?"]',selectNoteId));Note.selectTarget(target);if(needSaveChanged==undefined){needSaveChanged=true}if(needSaveChanged){var changedNote=Note.curChangedSaveIt()}Note.curNoteId="";var cacheNote=Note.cache[selectNoteId];if(!isShare){if(cacheNote.Perm!=undefined){isShare=true}}var hasPerm=!isShare||Share.hasUpdatePerm(selectNoteId);if(hasPerm){Note.hideReadOnly();Note.renderNote(cacheNote);switchEditor(cacheNote.IsMarkdown)}else{Note.renderNoteReadOnly(cacheNote)}Attach.renderNoteAttachNum(selectNoteId,true);Note.contentAjaxSeq++;var seq=Note.contentAjaxSeq;function setContent(ret){Note.contentAjax=null;if(seq!=Note.contentAjaxSeq){return}Note.setNoteCache(ret,false);ret=Note.cache[selectNoteId];if(hasPerm){Note.renderNoteContent(ret)}else{Note.renderNoteContentReadOnly(ret)}self.hideContentLoading()}if(cacheNote.Content){setContent(cacheNote);return}var url="/note/GetNoteContent";var param={noteId:selectNoteId};if(isShare){url="/share/GetShareNoteContent";param.sharedUserId=cacheNote.UserId}self.showContentLoading();if(Note.contentAjax!=null){Note.contentAjax.abort()}note.contentAjax=ajaxGet(url,param,setContent)};Note.renderChangedNote=function(changedNote){if(!changedNote){return}var $leftNoteNav=$(tt('[noteId="?"]',changedNote.NoteId));if(changedNote.Title){$leftNoteNav.find(".item-title").html(changedNote.Title)}if(changedNote.Desc){$leftNoteNav.find(".desc").html(changedNote.Desc)}if(changedNote.ImgSrc){$thumb=$leftNoteNav.find(".item-thumb");if($thumb.length>0){$thumb.find("img").attr("src",changedNote.ImgSrc)}else{$leftNoteNav.append(tt('
        ',changedNote.ImgSrc));$leftNoteNav.addClass("item-image")}$leftNoteNav.find(".item-desc").removeAttr("style")}else if(changedNote.ImgSrc==""){$leftNoteNav.find(".item-thumb").remove();$leftNoteNav.removeClass("item-image")}};Note.clearNoteInfo=function(){Note.curNoteId="";Tag.clearTags();$("#noteTitle").val("");setEditorContent("");$("#wmd-input").val("");$("#wmd-preview").html("");$("#noteRead").hide()};Note.clearNoteList=function(){Note.noteItemListO.html("")};Note.clearAll=function(){Note.curNoteId="";Note.clearNoteInfo();Note.clearNoteList()};Note.renderNote=function(note){if(!note){return}$("#noteTitle").val(note.Title);Tag.renderTags(note.Tags)};Note.renderNoteContent=function(content){setEditorContent(content.Content,content.IsMarkdown,content.Preview);Note.curNoteId=content.NoteId};Note.showEditorMask=function(){$("#editorMask").css("z-index",10).show();if(Notebook.curNotebookIsTrashOrAll()){$("#editorMaskBtns").hide();$("#editorMaskBtnsEmpty").show()}else{$("#editorMaskBtns").show();$("#editorMaskBtnsEmpty").hide()}};Note.hideEditorMask=function(){$("#editorMask").css("z-index",-10).hide()};Note.renderNotesC=0;Note.renderNotes=function(notes,forNewNote,isShared){var renderNotesC=++Note.renderNotesC;if(!LEA.isMobile&&!Mobile.isMobile()){$("#noteItemList").slimScroll({scrollTo:"0px",height:"100%",onlyScrollBar:true})}if(!notes||typeof notes!="object"||notes.length<=0){if(!forNewNote){Note.showEditorMask()}return}Note.hideEditorMask();if(forNewNote==undefined){forNewNote=false}if(!forNewNote){Note.noteItemListO.html("")}var len=notes.length;var c=Math.ceil(len/20);Note._renderNotes(notes,forNewNote,isShared,1);for(var i=0;i'+getMsg("close")+"");options={};options.show=true;$("#leanoteDialog").modal(options);ajaxGet("noteContentHistory/listHistories",{noteId:Note.curNoteId},function(re){if(!isArray(re)){$content.html(getMsg("noHistories"));return}var str="

        "+getMsg("historiesNum")+'

        ';note=Note.cache[Note.curNoteId];var s="div";if(note.IsMarkdown){s="pre"}for(i in re){var content=re[i];content.Ab=Note.genAbstract(content.Content,200);str+=tt('",i,+i+1,s,content.Ab,s,goNowToDatetime(content.UpdatedTime))}str+="
        #??
        '+getMsg("datetime")+': ?
        ";$content.html(str);$("#historyList .all").click(function(){$p=$(this).parent().parent();var seq=$p.attr("seq");var $c=$p.find(".each-content");var info=re[seq];if(!info.unfold){$(this).text(getMsg("fold"));$c.html(info.Content);info.unfold=true}else{$(this).text(getMsg("unfold"));$c.html(info.Ab);info.unfold=false}});$("#historyList .back").click(function(){$p=$(this).parent().parent();var seq=$p.attr("seq");if(confirm(getMsg("confirmBackup"))){Note.curChangedSaveIt();note=Note.cache[Note.curNoteId];setEditorContent(re[seq].Content,note.IsMarkdown);hideDialog()}})})};Note.html2Image=function(target){var noteId=$(target).attr("noteId");showDialog("html2ImageDialog",{title:"分享到社区",postShow:function(){ajaxGet("/note/html2Image",{noteId:noteId},function(ret){if(typeof ret=="object"&&ret.Ok){$("#leanoteDialog .weibo span").html("生成成功, 右键图片保存到本地.");$("#leanoteDialog .weibo img").attr("src",ret.Id+"?"+(new Date).getTime());$("#leanoteDialog .btn-share").removeClass("disabled");var note=Note.cache[noteId];var pic=UrlPrefix+ret.Id;var title=encodeURI(note.Title+" ("+UserInfo.Username+"分享. 来自leanote.com)");var windowParam="width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no";$("#leanoteDialog .sendWeiboBtn").click(function(){var url="http://service.weibo.com/share/share.php?title="+title;url+="&pic="+pic;window.open(url,"分享到新浪微博",windowParam)});$("#leanoteDialog .sendTxWeiboBtn").click(function(){var _appkey="801542571";var url="http://share.v.t.qq.com/index.php?c=share&a=index&appkey="+_appkey+"&title="+title+"&url=&pic="+pic;window.open(url,"分享到腾讯微博",windowParam)});$("#leanoteDialog .sendQQBtn").click(function(){var url="http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url="+UrlPrefix+"&title="+title+"&pics="+pic;window.open(url,"分享QQ空间",windowParam)});$("#leanoteDialog .sendRRBtn").click(function(){var url="http://widget.renren.com/dialog/share?resourceUrl="+UrlPrefix+"&srcUrl="+UrlPrefix+"&title="+title+"&pic="+pic;window.open(url,"分享人人网",windowParam)})}else{$("#leanoteDialog .weibo").html("对不起, 我们出错了!")}})}})};Note.showReadOnly=function(){Note.isReadOnly=true;$("#noteRead").show()};Note.hideReadOnly=function(){Note.isReadOnly=false;$("#noteRead").hide()};Note.renderNoteReadOnly=function(note){Note.showReadOnly();$("#noteReadTitle").html(note.Title);Tag.renderReadOnlyTags(note.Tags);$("#noteReadCreatedTime").html(goNowToDatetime(note.CreatedTime));$("#noteReadUpdatedTime").html(goNowToDatetime(note.UpdatedTime))};Note.renderNoteContentReadOnly=function(note){if(note.IsMarkdown){$("#noteReadContent").html('
        '+note.Content+"
        ")}else{$("#noteReadContent").html(note.Content)}};Note.lastSearch=null;Note.lastKey=null;Note.lastSearchTime=new Date;Note.isOver2Seconds=false;Note.isSameSearch=function(key){var now=new Date;var duration=now.getTime()-Note.lastSearchTime.getTime();Note.isOver2Seconds=duration>2e3?true:false;if(!Note.lastKey||Note.lastKey!=key||duration>1e3){Note.lastKey=key;Note.lastSearchTime=now;return false}if(key==Note.lastKey){return true}Note.lastSearchTime=now;Note.lastKey=key;return false};Note.searchNote=function(){var val=$("#searchNoteInput").val();if(!val){Notebook.changeNotebook("0");return}if(Note.isSameSearch(val)){return}if(Note.lastSearch){Note.lastSearch.abort()}Note.curChangedSaveIt();Note.clearAll();showLoading();Note.lastSearch=$.post("/note/searchNote",{key:val},function(notes){hideLoading();if(notes){Note.lastSearch=null;Note.renderNotes(notes);if(!isEmpty(notes)){Note.changeNote(notes[0].NoteId,false)}}else{}})};Note.setNote2Blog=function(target){var noteId=$(target).attr("noteId");var note=Note.cache[noteId];var isBlog=true;if(note.IsBlog!=undefined){isBlog=!note.IsBlog}if(isBlog){$(target).find(".item-blog").show()}else{$(target).find(".item-blog").hide()}ajaxPost("/note/setNote2Blog",{noteId:noteId,isBlog:isBlog},function(ret){if(ret){Note.setNoteCache({NoteId:noteId,IsBlog:isBlog},false)}})};Note.setAllNoteBlogStatus=function(notebookId,isBlog){if(!notebookId){return}var notes=Note.getNotesByNotebookId(notebookId);if(!isArray(notes)){return}var len=notes.length;if(len==0){for(var i in Note.cache){if(Note.cache[i].NotebookId==notebookId){Note.cache[i].IsBlog=isBlog}}}else{for(var i=0;i'+attach.Title+"")}});self.linkAllBtnO.on("click",function(e){e.stopPropagation();var note=Note.getCurNote();if(!note){return}var src=UrlPrefix+"/attach/downloadAll?noteId="+Note.curNoteId;var title=note.Title?note.Title+".tar.gz":"all.tar.gz";if(LEA.isMarkdownEditor()&&MarkdownEditor){MarkdownEditor.insertLink(src,title)}else{tinymce.activeEditor.insertContent(''+title+"")}})},attachListO:$("#attachList"),attachNumO:$("#attachNum"),attachDropdownO:$("#attachDropdown"),downloadAllBtnO:$("#downloadAllBtn"),linkAllBtnO:$("#linkAllBtn"),clearNoteAttachNum:function(){var self=this;self.attachNumO.html("").hide()},renderNoteAttachNum:function(noteId,needHide){var self=this;var note=Note.getNote(noteId);if(note.AttachNum){self.attachNumO.html("("+note.AttachNum+")").show();self.downloadAllBtnO.show();self.linkAllBtnO.show()}else{self.attachNumO.hide();self.downloadAllBtnO.hide();self.linkAllBtnO.hide()}if(needHide){self.attachDropdownO.removeClass("open")}},_renderAttachs:function(attachs){var self=this;var html="";var attachNum=attachs.length;for(var i=0;i'+'
        '+each.Title+"
        "+'
        '+' '+' '+' '+"
        "+"";self.attachsMap[each.AttachId]=each}self.attachListO.html(html);var note=Note.getCurNote();if(note){note.AttachNum=attachNum;self.renderNoteAttachNum(note.NoteId,false)}},renderAttachs:function(noteId){var self=this;if(self.loadedNoteAttachs[noteId]){self._renderAttachs(self.loadedNoteAttachs[noteId]);return}self.attachListO.html('
      • ');ajaxGet("/attach/getAttachs",{noteId:noteId},function(ret){var list=[];if(ret.Ok){list=ret.List;if(!list){list=[]}}self.loadedNoteAttachs[noteId]=list;self._renderAttachs(list)})},addAttach:function(attachInfo){var self=this;if(!self.loadedNoteAttachs[attachInfo.NoteId]){self.loadedNoteAttachs[attachInfo.NoteId]=[]}self.loadedNoteAttachs[attachInfo.NoteId].push(attachInfo);self.renderAttachs(attachInfo.NoteId)},deleteAttach:function(attachId){var self=this;var noteId=Note.curNoteId;var attachs=self.loadedNoteAttachs[noteId];for(var i=0;i 得到该notebook的notes, 显示出来, 并选中第一个! +// 在这期间定时器还会保存, curNoteId还没换, 所以会清空curNoteId的content!!! + +// 2. note change, save cur, 立即curNoteId = ""!! + +// 3. 什么时候设置curNoteId? 是ajax得到内容之后设置 + +// note +Note.curNoteId = ""; + +Note.interval = ""; // 定时器 + +Note.itemIsBlog = '
        '; +// for render +Note.itemTplNoImg = '
      • ' +Note.itemTplNoImg += Note.itemIsBlog +'

        ?

        ? ?

        ?

      • '; + +// 有image +Note.itemTpl = '
      • ' +Note.itemTpl +=Note.itemIsBlog + '

        ?

        ? ?

        ?

      • '; + +// for new +Note.newItemTpl = '
      • ' +Note.newItemTpl += Note.itemIsBlog + '

        ?

        ? ?
        ?

      • '; + +Note.noteItemListO = $("#noteItemList"); + +// notbeookId => {"updatedTime" => [noteId1, noteId2], "title" => [noteId1, noteId2...]} 排序方式分组 +// 一旦某notebook改变了就清空, 重新排序之. (用js排) +Note.cacheByNotebookId = {all: {}}; +Note.notebookIds = {}; // notebookId => true + +Note.isReadOnly = false; +// 定时保存信息 +Note.intervalTime = 600000; // 600s, 10mins +Note.startInterval = function() { + Note.interval = setInterval(function() { + log("自动保存开始...") + changedNote = Note.curChangedSaveIt(false); + }, Note.intervalTime); // 600s, 10mins +} +// 停止, 当切换note时 +// 但过5000后自动启动 +Note.stopInterval = function() { + clearInterval(Note.interval); + + setTimeout(function() { + Note.startInterval(); + }, Note.intervalTime); +} + +// note = {NoteId, Desc, UserId,...} +Note.addNoteCache = function(note) { + Note.cache[note.NoteId] = note; + Note.clearCacheByNotebookId(note.NotebookId); +} +// content = {NoteId:, Content:} +// 还可以设置其它的值 +Note.setNoteCache = function(content, clear) { + if(!Note.cache[content.NoteId]) { + Note.cache[content.NoteId] = content; + } else { + $.extend(Note.cache[content.NoteId], content); + } + + if(clear == undefined) { + clear = true; + } + if(clear) { + Note.clearCacheByNotebookId(content.NotebookId); + } +} + +// 得到当前的笔记 +Note.getCurNote = function() { + var self = this; + if(self.curNoteId == "") { + return null; + } + return self.cache[self.curNoteId]; +} +Note.getNote = function(noteId) { + var self = this; + return self.cache[noteId]; +} + +// 每当有notebookId相应的note改变时都要重新清空之 +// 并设置该notebookId有值 +Note.clearCacheByNotebookId = function(notebookId) { + if(notebookId) { + Note.cacheByNotebookId[notebookId] = {}; + Note.cacheByNotebookId["all"] = {}; + Note.notebookIds[notebookId] = true; + } +} + +// notebook是否有notes +// called by Notebook +Note.notebookHasNotes = function(notebookId) { + var notes = Note.getNotesByNotebookId(notebookId); + return !isEmpty(notes); +} + +// 得到notebook下的notes, 按什么排序 updatedTime? +Note.getNotesByNotebookId = function(notebookId, sortBy, isAsc) { + if(!sortBy) { + sortBy = "UpdatedTime"; + } + if(isAsc == "undefined") { + isAsc = false; // 默认是降序 + } + + if(!notebookId) { + notebookId = "all"; + } + + if(!Note.cacheByNotebookId[notebookId]) { + return []; + } + + if(Note.cacheByNotebookId[notebookId][sortBy]) { + return Note.cacheByNotebookId[notebookId][sortBy]; + } else { + } + + // 从所有的notes中找到notebookId的, 并排序之 + var notes = []; + var sortBys = []; + for(var i in Note.cache) { + if(!i) { + continue; + } + var note = Note.cache[i]; + // 不要trash的not, 共享的也不要 + if(note.IsTrash || note.IsShared) { + continue; + } + if(notebookId == "all" || note.NotebookId == notebookId) { + notes.push(note); + } + } + // 排序之 + notes.sort(function(a, b) { + var t1 = a[sortBy]; + var t2 = b[sortBy]; + + if(isAsc) { + if(t1 < t2) { + return -1; + } else if (t1 > t2) { + return 1; + } + } else { + if(t1 < t2) { + return 1; + } else if (t1 > t2) { + return -1; + } + } + return 0; + }); + + // 缓存之 + Note.cacheByNotebookId[notebookId][sortBy] = notes; + return notes; +} + +// called by Notebook +// render 所有notes, 和第一个note的content +Note.renderNotesAndFirstOneContent = function(ret) { + // 错误的ret是一个Object + if(!isArray(ret)) { + return; + } + + // note 导航 + Note.renderNotes(ret); + // 渲染第一个 + if(!isEmpty(ret[0])) { + Note.changeNote(ret[0].NoteId); + } else { + } + +} + +// 当前的note是否改变过了? +// 返回已改变的信息 +// force bool true表示content比较是比较HTML, 否则比较text, 默认为true +// 定时保存用false +Note.curHasChanged = function(force) { + if(force == undefined) { + force = true; + } + var cacheNote = Note.cache[Note.curNoteId] || {}; + // 收集当前信息, 与cache比对 + var title = $("#noteTitle").val(); + var tags = Tag.getTags(); // TODO + + // 如果是markdown返回[content, preview] + var contents = getEditorContent(cacheNote.IsMarkdown); + var content, preview; + var contentText; + if (isArray(contents)) { + content = contents[0]; + preview = contents[1]; + contentText = content; + // preview可能没来得到及解析 + if (content && previewIsEmpty(preview) && Converter) { + preview = Converter.makeHtml(content); + } + if(!content) { + preview = ""; + } + cacheNote.Preview = preview; // 仅仅缓存在前台 + } else { + content = contents; + try { + contentText = $(content).text(); + } catch(e) { + } + } + + var hasChanged = { + hasChanged: false, // 总的是否有改变 + IsNew: cacheNote.IsNew, // 是否是新添加的 + IsMarkdown: cacheNote.IsMarkdown, // 是否是markdown笔记 + FromUserId: cacheNote.FromUserId, // 是否是共享新建的 + NoteId: cacheNote.NoteId, + NotebookId: cacheNote.NotebookId + }; + + if(hasChanged.IsNew) { + $.extend(hasChanged, cacheNote); + } + + if(cacheNote.Title != title) { + hasChanged.hasChanged = true; // 本页使用用小写 + hasChanged.Title = title; // 要传到后台的用大写 + if(!hasChanged.Title) { +// alert(1); + } + } + + if(!arrayEqual(cacheNote.Tags, tags)) { + hasChanged.hasChanged = true; + hasChanged.Tags = tags; + } + + // 比较text, 因为note Nav会添加dom会导致content改变 + if((force && cacheNote.Content != content) || (!force && $(cacheNote.Content).text() != contentText)) { + hasChanged.hasChanged = true; + hasChanged.Content = content; + + // 从html中得到... + var c = preview || content; + + hasChanged.Desc = Note.genDesc(c); + hasChanged.ImgSrc = Note.getImgSrc(c); + hasChanged.Abstract = Note.genAbstract(c); + + } else { + log("text相同"); + log(cacheNote.Content == content); + } + + hasChanged["UserId"] = cacheNote["UserId"] || ""; + + return hasChanged; +} + +// 由content生成desc +// 换行不要替换 +Note.genDesc = function(content) { + if(!content) { + return ""; + } + + // 将
        ,

        替换成\n + /* + var token = "ALEALE"; + content = content.replace(/<\/p>/g, token); + content = content.replace(/<\/div>/g, token); + content = content.replace(/<\/?.+?>/g," "); + + pattern = new RegExp(token, "g"); + content = content.replace(pattern, "
        "); + content = content.replace(/
        ( *)
        /g, "
        "); // 两个
        之间可能有空白 + content = content.replace(/
        ( *)
        /g, "
        "); + + // 去掉最开始的
        或

        + content = trimLeft(content, " "); + content = trimLeft(content, "
        "); + content = trimLeft(content, "

        "); + content = trimLeft(content, "
        "); + */ + + // 留空格 + content = content.replace(/
        /g,"
        "); + content = content.replace(/<\/p>/g,"

        "); + content = content.replace(/<\/div>/g,"
        "); + + // 避免其它的").html(content).text(); + + // pre下text()会将< => < > => > + content = content.replace(//g, ">"); + + if(content.length < 300) { + return content; + } + return content.substring(0, 300); +} + +// 得到摘要 +Note.genAbstract = function(content, len) { + if(len == undefined) { + len = 1000; + } + if(content.length < len) { + return content; + } + var isCode = false; + var isHTML = false; + var n = 0; + var result = ""; + var maxLen = len; + for(var i = 0; i < content.length; ++i) { + var temp = content[i] + if (temp == '<') { + isCode = true + } else if (temp == '&') { + isHTML = true + } else if (temp == '>' && isCode) { + n = n - 1 + isCode = false + } else if (temp == ';' && isHTML) { + isHTML = false + } + if (!isCode && !isHTML) { + n = n + 1 + } + result += temp + if (n >= maxLen) { + break + } + } + + var d = document.createElement("div"); + d.innerHTML = result + return d.innerHTML; +} + +Note.getImgSrc = function(content) { + if(!content) { + return ""; + } + var imgs = $(content).find("img"); + for(var i in imgs) { + var src = imgs.eq(i).attr("src"); + if(src) { + return src; + } + } + return ""; +} + +// 如果当前的改变了, 就保存它 +// 以后要定时调用 +// force , 默认是true, 表强校验内容 +// 定时保存传false +Note.curChangedSaveIt = function(force) { + // 如果当前没有笔记, 不保存 + if(!Note.curNoteId || Note.isReadOnly) { + return; + } + + var hasChanged = Note.curHasChanged(force); + + // 把已改变的渲染到左边 item-list + Note.renderChangedNote(hasChanged); + + if(hasChanged.hasChanged || hasChanged.IsNew) { + delete hasChanged.hasChanged; + + // 先缓存, 把markdown的preview也缓存起来 + Note.setNoteCache(hasChanged, false); + + // 设置更新时间 + Note.setNoteCache({"NoteId": hasChanged.NoteId, "UpdatedTime": (new Date()).format("yyyy-MM-ddThh:mm:ss.S")}, false); + + // 保存之 + showMsg(getMsg("saving")); + ajaxPost("/note/UpdateNoteOrContent", hasChanged, function(ret) { + if(hasChanged.IsNew) { + // 缓存之, 后台得到其它信息 + ret.IsNew = false; + Note.setNoteCache(ret, false); + } + showMsg(getMsg("saveSuccess"), 1000); + }); + + return hasChanged; + } + return false; +} + +// 样式 +Note.selectTarget = function(target) { + $(".item").removeClass("item-active"); + $(target).addClass("item-active"); +} + +// 改变note +// 可能改变的是share note +// 1. 保存之前的note +// 2. ajax得到现在的note +Note.showContentLoading = function() { + $("#noteMaskForLoading").css("z-index", 99999); +} +Note.hideContentLoading = function() { + $("#noteMaskForLoading").css("z-index", -1); +} +Note.contentAjax = null; +Note.contentAjaxSeq = 1; +Note.changeNote = function(selectNoteId, isShare, needSaveChanged) { + var self = this; + // -1 停止定时器 + Note.stopInterval(); + + // 0 + var target = $(tt('[noteId="?"]', selectNoteId)) + Note.selectTarget(target); + + // 1 之前的note, 判断是否已改变, 改变了就要保存之 + // 这里, 在搜索的时候总是保存, 搜索的话, 比较快, 肯定没有变化, 就不要执行该操作 + if(needSaveChanged == undefined) { + needSaveChanged = true; + } + if(needSaveChanged) { + var changedNote = Note.curChangedSaveIt(); + } + + // 2. 设空, 防止在内容得到之前又发生保存 + Note.curNoteId = ""; + + // 2 得到现在的 + // ajax之 + var cacheNote = Note.cache[selectNoteId]; + + // 判断是否是共享notes + if(!isShare) { + if(cacheNote.Perm != undefined) { + isShare = true; + } + } + var hasPerm = !isShare || Share.hasUpdatePerm(selectNoteId); // 不是共享, 或者是共享但有权限 + + // 有权限 + if(hasPerm) { + Note.hideReadOnly(); + Note.renderNote(cacheNote); + + // 这里要切换编辑器 + switchEditor(cacheNote.IsMarkdown) + } else { + Note.renderNoteReadOnly(cacheNote); + } + + Attach.renderNoteAttachNum(selectNoteId, true); + + Note.contentAjaxSeq++; + var seq = Note.contentAjaxSeq; + function setContent(ret) { + Note.contentAjax = null; + if(seq != Note.contentAjaxSeq) { + return; + } + Note.setNoteCache(ret, false); + // 把其它信息也带上 + ret = Note.cache[selectNoteId] + if(hasPerm) { + Note.renderNoteContent(ret); + } else { + Note.renderNoteContentReadOnly(ret); + } + self.hideContentLoading(); + } + + if(cacheNote.Content) { + setContent(cacheNote); + return; + } + + var url = "/note/GetNoteContent"; + var param = {noteId: selectNoteId}; + if(isShare) { + url = "/share/GetShareNoteContent"; + param.sharedUserId = cacheNote.UserId // 谁的笔记 + } + + self.showContentLoading(); + if(Note.contentAjax != null) { + Note.contentAjax.abort(); + } + note.contentAjax = ajaxGet(url, param, setContent); +} + +// 渲染 + +// 更改信息到左侧 +// 定时更改 当前正在编辑的信息到左侧导航 +// 或change select. 之前的note, 已经改变了 +Note.renderChangedNote = function(changedNote) { + if(!changedNote) { + return; + } + + // 找到左侧相应的note + var $leftNoteNav = $(tt('[noteId="?"]', changedNote.NoteId)); + if(changedNote.Title) { + $leftNoteNav.find(".item-title").html(changedNote.Title); + } + if(changedNote.Desc) { + $leftNoteNav.find(".desc").html(changedNote.Desc); + } + if(changedNote.ImgSrc) { + $thumb = $leftNoteNav.find(".item-thumb"); + // 有可能之前没有图片 + if($thumb.length > 0) { + $thumb.find("img").attr("src", changedNote.ImgSrc); + } else { + $leftNoteNav.append(tt('
        ', changedNote.ImgSrc)); + $leftNoteNav.addClass("item-image"); + } + $leftNoteNav.find(".item-desc").removeAttr("style"); + } else if(changedNote.ImgSrc == "") { + $leftNoteNav.find(".item-thumb").remove(); // 以前有, 现在没有了 + $leftNoteNav.removeClass("item-image"); + } +} + +// 清空右侧note信息, 可能是共享的, +// 此时需要清空只读的, 且切换到note edit模式下 +Note.clearNoteInfo = function() { + Note.curNoteId = ""; + Tag.clearTags(); + $("#noteTitle").val(""); + setEditorContent(""); + + // markdown editor + $("#wmd-input").val(""); + $("#wmd-preview").html(""); + + // 只隐藏即可 + $("#noteRead").hide(); +} +// 清除noteList导航 +Note.clearNoteList = function() { + Note.noteItemListO.html(""); // 清空 +} + +// 清空所有, 在转换notebook时使用 +Note.clearAll = function() { + // 当前的笔记清空掉 + Note.curNoteId = ""; + + Note.clearNoteInfo(); + Note.clearNoteList(); +} + +// render到编辑器 +// render note +Note.renderNote = function(note) { + if(!note) { + return; + } + // title + $("#noteTitle").val(note.Title); + + // 当前正在编辑的 + // tags + Tag.renderTags(note.Tags); +} + +// render content +Note.renderNoteContent = function(content) { + setEditorContent(content.Content, content.IsMarkdown, content.Preview); + // 只有在renderNoteContent时才设置curNoteId + Note.curNoteId = content.NoteId; +} + +// 初始化时渲染最初的notes +/** +
        + +*/ + +Note.showEditorMask = function() { + $("#editorMask").css("z-index", 10).show(); + // 要判断是否是垃圾筒 + if(Notebook.curNotebookIsTrashOrAll()) { + $("#editorMaskBtns").hide(); + $("#editorMaskBtnsEmpty").show(); + } else { + $("#editorMaskBtns").show(); + $("#editorMaskBtnsEmpty").hide(); + } +} +Note.hideEditorMask = function() { + $("#editorMask").css("z-index", -10).hide(); +} + +// 这里如果notes过多>100个将会很慢!!, 使用setTimeout来分解 +Note.renderNotesC = 0; +Note.renderNotes = function(notes, forNewNote, isShared) { + var renderNotesC = ++Note.renderNotesC; + + // 手机端不用 + // slimScroll使得手机端滚动不流畅 + if(!LEA.isMobile && !Mobile.isMobile()) { + $("#noteItemList").slimScroll({ scrollTo: '0px', height: "100%", onlyScrollBar: true}); + } + + if(!notes || typeof notes != "object" || notes.length <= 0) { + // 如果没有, 那么是不是应该hide editor? + if(!forNewNote) { + Note.showEditorMask(); + } + return; + } + Note.hideEditorMask(); + // 新建笔记时会先创建一个新笔记, 所以不能清空 + if(forNewNote == undefined) { + forNewNote = false; + } + if(!forNewNote) { + Note.noteItemListO.html(""); // 清空 + } + + // 20个一次 + var len = notes.length; + var c = Math.ceil(len/20); + + Note._renderNotes(notes, forNewNote, isShared, 1); + + // 先设置缓存 + for(var i = 0; i < len; ++i) { + var note = notes[i]; + // 不清空 + // 之前是addNoteCache, 如果是搜索出的, 会把内容都重置了 + Note.setNoteCache(note, false); + + // 如果是共享的笔记本, 缓存也放在Share下 + if(isShared) { + Share.setCache(note); + } + } + + for(var i = 1; i < c; ++i) { + setTimeout( + (function(i) { + // 防止还没渲染完就点击另一个notebook了 + return function() { + if(renderNotesC == Note.renderNotesC) { + Note._renderNotes(notes, forNewNote, isShared, i+1); + } + } + })(i), i*2000); + } +} +Note._renderNotes = function(notes, forNewNote, isShared, tang) { // 第几趟 + var baseClasses = "item-my"; + if(isShared) { + baseClasses = "item-shared"; + } + + var len = notes.length; + for(var i = (tang-1)*20; i < len && i < tang*20; ++i) { + var classes = baseClasses; + if(!forNewNote && i == 0) { + classes += " item-active"; + } + var note = notes[i]; + var tmp; + if(note.ImgSrc) { + tmp = tt(Note.itemTpl, classes, note.NoteId, note.ImgSrc, note.Title, Notebook.getNotebookTitle(note.NotebookId), goNowToDatetime(note.UpdatedTime), note.Desc); + } else { + tmp = tt(Note.itemTplNoImg, classes, note.NoteId, note.Title, Notebook.getNotebookTitle(note.NotebookId), goNowToDatetime(note.UpdatedTime), note.Desc); + } + if(!note.IsBlog) { + tmp = $(tmp); + tmp.find(".item-blog").hide(); + } + Note.noteItemListO.append(tmp); + + /* + // 共享的note也放在Note的cache一份 + if(isShared) { + note.IsShared = true; // 注明是共享的 + } + + // 不清空 + // 之前是addNoteCache, 如果是搜索出的, 会把内容都重置了 + Note.setNoteCache(note, false); + + // 如果是共享的笔记本, 缓存也放在Share下 + if(isShared) { + Share.setCache(note); + } + */ + } +} + +// 新建一个笔记 +// 要切换到当前的notebook下去新建笔记 +// isShare时fromUserId才有用 +// 3.8 add isMarkdown +Note.newNote = function(notebookId, isShare, fromUserId, isMarkdown) { + // 切换编辑器 + switchEditor(isMarkdown); + Note.hideEditorMask(); + + // 防止从共享read only跳到添加 + Note.hideReadOnly(); + + Note.stopInterval(); + // 保存当前的笔记 + Note.curChangedSaveIt(); + + var note = {NoteId: getObjectId(), Title: "", Tags:[], Content:"", NotebookId: notebookId, IsNew: true, FromUserId: fromUserId, IsMarkdown: isMarkdown}; // 是新的 + // 添加到缓存中 + Note.addNoteCache(note); + + // 清空附件数 + Attach.clearNoteAttachNum(); + + // 是否是为共享的notebook添加笔记, 如果是, 则还要记录fromUserId + var newItem = ""; + + var baseClasses = "item-my"; + if(isShare) { + baseClasses = "item-shared"; + } + + var notebook = Notebook.getNotebook(notebookId); + var notebookTitle = notebook ? notebook.Title : ""; + var curDate = getCurDate(); + if(isShare) { + newItem = tt(Note.newItemTpl, baseClasses, fromUserId, note.NoteId, note.Title, notebookTitle, curDate, ""); + } else { + newItem = tt(Note.newItemTpl, baseClasses, "", note.NoteId, note.Title, notebookTitle, curDate, ""); + } + + // notebook是否是Blog + if(!notebook.IsBlog) { + newItem = $(newItem); + newItem.find(".item-blog").hide(); + } + + // 是否在当前notebook下, 不是则切换过去, 并得到该notebook下所有的notes, 追加到后面! + if(!Notebook.isCurNotebook(notebookId)) { + // 先清空所有 + Note.clearAll(); + + // 插入到第一个位置 + Note.noteItemListO.prepend(newItem); + + // 改变为当前的notebookId + // 会得到该notebookId的其它笔记 + if(!isShare) { + Notebook.changeNotebookForNewNote(notebookId); + } else { + Share.changeNotebookForNewNote(notebookId); + } + } else { + // 插入到第一个位置 + Note.noteItemListO.prepend(newItem); + } + + Note.selectTarget($(tt('[noteId="?"]', note.NoteId))); + + $("#noteTitle").focus(); + + Note.renderNote(note); + Note.renderNoteContent(note); + Note.curNoteId = note.NoteId; + + // 更新数量 + Notebook.incrNotebookNumberNotes(notebookId) +} + +// 保存note ctrl + s +Note.saveNote = function(e) { + var num = e.which ? e.which : e.keyCode; + // 保存 + if((e.ctrlKey || e.metaKey) && num == 83 ) { // ctrl + s or command + s + Note.curChangedSaveIt(); + e.preventDefault(); + return false; + } else { + } +}; + +// 删除或移动笔记后, 渲染下一个或上一个 +Note.changeToNext = function(target) { + var $target = $(target); + var next = $target.next(); + if(!next.length) { + var prev = $target.prev(); + if(prev.length) { + next = prev; + } else { + // 就它一个 + Note.showEditorMask(); + return; + } + } + + Note.changeNote(next.attr("noteId")); +} + +// 删除笔记 +// 1. 先隐藏, 成功后再移除DOM +// 2. ajax之 noteId +// Share.deleteSharedNote调用 +Note.deleteNote = function(target, contextmenuItem, isShared) { + // 如果删除的是已选中的, 赶紧设置curNoteId = null + if($(target).hasClass("item-active")) { + // -1 停止定时器 + Note.stopInterval(); + // 不保存 + Note.curNoteId = null; + // 清空信息 + Note.clearNoteInfo(); + } + + noteId = $(target).attr("noteId"); + if(!noteId) { + return; + } + // 1 + $(target).hide(); + + // 2 + var note = Note.cache[noteId]; + var url = "/note/deleteNote" + if(note.IsTrash) { + url = "/note/deleteTrash"; + } else { + // 减少数量 + Notebook.minusNotebookNumberNotes(note.NotebookId); + } + + ajaxGet(url, {noteId: noteId, userId: note.UserId, isShared: isShared}, function(ret) { + if(ret) { + Note.changeToNext(target); + + $(target).remove(); + + // 删除缓存 + if(note) { + Note.clearCacheByNotebookId(note.NotebookId) + delete Note.cache[noteId] + } + + showMsg("删除成功!", 500); + } else { + // 弹出信息 popup 不用点确认的 + $(target).show(); + showMsg("删除失败!", 2000); + } + }); + +} + +// 显示共享信息 +Note.listNoteShareUserInfo = function(target) { + var noteId = $(target).attr("noteId"); + showDialogRemote("share/listNoteShareUserInfo", {noteId: noteId}); +} + +// 共享笔记 +Note.shareNote = function(target) { + var title = $(target).find(".item-title").text(); + showDialog("dialogShareNote", {title: getMsg("shareToFriends") + "-" + title}); + + setTimeout(function() { + $("#friendsEmail").focus(); + }, 500); + + var noteId = $(target).attr("noteId"); + shareNoteOrNotebook(noteId, true); +} + +// 历史记录 +Note.listNoteContentHistories = function() { + // 弹框 + $("#leanoteDialog #modalTitle").html(getMsg("history")); + $content = $("#leanoteDialog .modal-body"); + $content.html(""); + $("#leanoteDialog .modal-footer").html(''); + options = {} + options.show = true; + $("#leanoteDialog").modal(options); + + ajaxGet("noteContentHistory/listHistories", {noteId: Note.curNoteId}, function(re) { + if(!isArray(re)) {$content.html(getMsg("noHistories")); return} + // 组装成一个tab + var str = "

        " + getMsg("historiesNum") + '

        '; + note = Note.cache[Note.curNoteId]; + var s = "div" + if(note.IsMarkdown) { + s = "pre"; + } + for (i in re) { + var content = re[i] + content.Ab = Note.genAbstract(content.Content, 200); + str += tt('', i, (+i+1), s, content.Ab, s, goNowToDatetime(content.UpdatedTime)) + } + str += "
        #??
        ' + getMsg("datetime") + ': ?
        "; + $content.html(str); + $("#historyList .all").click(function() { + $p = $(this).parent().parent(); + var seq = $p.attr("seq"); + var $c = $p.find(".each-content"); + var info = re[seq]; + if(!info.unfold) { // 默认是折叠的 + $(this).text(getMsg("fold")); // 折叠 + $c.html(info.Content); + info.unfold = true; + } else { + $(this).text(getMsg("unfold")); // 展开 + $c.html(info.Ab); + info.unfold = false + } + }); + + // 还原 + $("#historyList .back").click(function() { + $p = $(this).parent().parent(); + var seq = $p.attr("seq"); + if(confirm(getMsg("confirmBackup"))) { + // 保存当前版本 + Note.curChangedSaveIt(); + // 设置之 + note = Note.cache[Note.curNoteId]; + setEditorContent(re[seq].Content, note.IsMarkdown); + // + hideDialog(); + } + }); + + }); +} + +// 长微博 +Note.html2Image = function(target) { + var noteId = $(target).attr("noteId"); + showDialog("html2ImageDialog", {title: "分享到社区", postShow: function() { + ajaxGet("/note/html2Image", {noteId: noteId}, function(ret) { + if (typeof ret == "object" && ret.Ok) { + $("#leanoteDialog .weibo span").html("生成成功, 右键图片保存到本地.") + $("#leanoteDialog .weibo img").attr("src", ret.Id + "?" + ((new Date()).getTime())); + $("#leanoteDialog .btn-share").removeClass("disabled"); + var note = Note.cache[noteId]; + var pic = UrlPrefix + ret.Id; + var title = encodeURI(note.Title + " (" + UserInfo.Username + "分享. 来自leanote.com)"); + var windowParam = 'width=700, height=580, top=180, left=320, toolbar=no, menubar=no, scrollbars=no, location=yes, resizable=no, status=no'; + $("#leanoteDialog .sendWeiboBtn").click(function() { + var url = "http://service.weibo.com/share/share.php?title=" + title; + url += "&pic=" + pic; + window.open(url, '分享到新浪微博', windowParam); + }); + $("#leanoteDialog .sendTxWeiboBtn").click(function() { + var _appkey = '801542571'; + var url = "http://share.v.t.qq.com/index.php?c=share&a=index&appkey=" + _appkey +"&title=" + title +"&url=&pic=" + pic + window.open(url, '分享到腾讯微博', windowParam); + }); + $("#leanoteDialog .sendQQBtn").click(function() { + var url = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + UrlPrefix + '&title=' + title + '&pics=' + pic; + window.open(url, '分享QQ空间', windowParam); + }); + $("#leanoteDialog .sendRRBtn").click(function() { + var url = 'http://widget.renren.com/dialog/share?resourceUrl=' + UrlPrefix + '&srcUrl=' + UrlPrefix + '&title=' + title + '&pic=' + pic; + window.open(url, '分享人人网', windowParam); + }); + } else { + $("#leanoteDialog .weibo").html("对不起, 我们出错了!") + } + }); + }}); +} + +//-------------- +// read only + +Note.showReadOnly = function() { + Note.isReadOnly = true; + $("#noteRead").show(); +} +Note.hideReadOnly = function() { + Note.isReadOnly = false; + $("#noteRead").hide(); +} +// read only +Note.renderNoteReadOnly = function(note) { + Note.showReadOnly(); + $("#noteReadTitle").html(note.Title); + + Tag.renderReadOnlyTags(note.Tags); + + $("#noteReadCreatedTime").html(goNowToDatetime(note.CreatedTime)); + $("#noteReadUpdatedTime").html(goNowToDatetime(note.UpdatedTime)); +} +Note.renderNoteContentReadOnly = function(note) { + if(note.IsMarkdown) { + $("#noteReadContent").html('
        ' + note.Content + "
        "); + } else { + $("#noteReadContent").html(note.Content); + } +} + +//--------------------------- +// 搜索 +// 有点小复杂, 因为速度过快会导致没加载完, 然后就保存上一个 => 致使标题没有 +// 为什么会标题没有? +Note.lastSearch = null; +Note.lastKey = null; // 判断是否与上一个相等, 相等就不查询, 如果是等了很久再按enter? +Note.lastSearchTime = new Date(); +Note.isOver2Seconds = false; +Note.isSameSearch = function(key) { + // 判断时间是否超过了1秒, 超过了就认为是不同的 + var now = new Date(); + var duration = now.getTime() - Note.lastSearchTime.getTime(); + Note.isOver2Seconds = duration > 2000 ? true : false; + if(!Note.lastKey || Note.lastKey != key || duration > 1000) { + Note.lastKey = key; + Note.lastSearchTime = now; + return false; + } + + if(key == Note.lastKey) { + return true; + } + + Note.lastSearchTime = now; + Note.lastKey = key; + return false; +} + +Note.searchNote = function() { + var val = $("#searchNoteInput").val(); + if(!val) { + // 定位到all + Notebook.changeNotebook("0"); + return; + } + // 判断是否与上一个是相同的搜索, 是则不搜索 + if(Note.isSameSearch(val)) { + return; + } + + // 之前有, 还有结束的 + if(Note.lastSearch) { + Note.lastSearch.abort(); + } + + // 步骤与tag的搜索一样 + // 1 + Note.curChangedSaveIt(); + + // 2 先清空所有 + Note.clearAll(); + + // 发送请求之 + // 先取消上一个 + showLoading(); + Note.lastSearch = $.post("/note/searchNote", {key: val}, function(notes) { + hideLoading(); + if(notes) { + // 成功后设为空 + Note.lastSearch = null; + // renderNotes只是note列表加载, 右侧笔记详情还没加载 + // 这个时候, 定位第一个, 保存之前的, + // 如果: 第一次搜索, renderNotes OK, 还没等到changeNote时 + // 第二次搜索来到, Note.curChangedSaveIt(); + // 导致没有标题了 + // 不是这个原因, 下面的Note.changeNote会导致保存 + + // 设空, 防止发生上述情况 + // Note.curNoteId = ""; + + Note.renderNotes(notes); + if(!isEmpty(notes)) { + Note.changeNote(notes[0].NoteId, false/*, true || Note.isOver2Seconds*/); // isShare, needSaveChanged?, 超过2秒就要保存 + } + } else { + // abort的 + } + }); + // Note.lastSearch.abort(); +} + +//---------- +//设为blog/unset +Note.setNote2Blog = function(target) { + var noteId = $(target).attr("noteId"); + var note = Note.cache[noteId]; + var isBlog = true; + if(note.IsBlog != undefined) { + isBlog = !note.IsBlog; + } + // 标志添加/去掉 + if(isBlog) { + $(target).find(".item-blog").show(); + } else { + $(target).find(".item-blog").hide(); + } + ajaxPost("/note/setNote2Blog", {noteId: noteId, isBlog: isBlog}, function(ret) { + if(ret) { + Note.setNoteCache({NoteId: noteId, IsBlog: isBlog}, false); // 不清空NotesByNotebookId缓存 + } + }); +} + +// 设置notebook的blog状态 +// 当修改notebook是否是blog时调用 +Note.setAllNoteBlogStatus = function(notebookId, isBlog) { + if(!notebookId) { + return; + } + var notes = Note.getNotesByNotebookId(notebookId); + if(!isArray(notes)) { + return; + } + var len = notes.length; + if(len == 0) { + for(var i in Note.cache) { + if(Note.cache[i].NotebookId == notebookId) { + Note.cache[i].IsBlog = isBlog; + } + } + } else { + for(var i = 0; i < len; ++i) { + notes[i].IsBlog = isBlog; + } + } +} + +// 移动 +Note.moveNote = function(target, data) { + var noteId = $(target).attr("noteId"); + var note = Note.cache[noteId]; + var notebookId = data.notebookId; + + if(!note.IsTrash && note.NotebookId == notebookId) { + return; + } + + // 修改数量 + Notebook.incrNotebookNumberNotes(notebookId); + if(!note.IsTrash) { + Notebook.minusNotebookNumberNotes(note.NotebookId); + } + + ajaxGet("/note/moveNote", {noteId: noteId, notebookId: notebookId}, function(ret) { + if(ret && ret.NoteId) { + if(note.IsTrash) { + Note.changeToNext(target); + $(target).remove(); + Note.clearCacheByNotebookId(notebookId); + } else { + // 不是trash, 移动, 那么判断是当前是否是all下 + // 不在all下, 就删除之 + // 如果当前是active, 那么clearNoteInfo之 + if(!Notebook.curActiveNotebookIsAll()) { + Note.changeToNext(target); + if($(target).hasClass("item-active")) { + Note.clearNoteInfo(); + } + $(target).remove(); + } else { + // 不移动, 那么要改变其notebook title + $(target).find(".note-notebook").html(Notebook.getNotebookTitle(notebookId)); + } + + // 重新清空cache 之前的和之后的 + Note.clearCacheByNotebookId(note.NotebookId); + Note.clearCacheByNotebookId(notebookId); + } + + // 改变缓存 + Note.setNoteCache(ret) + } + }); +} + +// 复制 +// data是自动传来的, 是contextmenu数据 +Note.copyNote = function(target, data, isShared) { + var noteId = $(target).attr("noteId"); + var note = Note.cache[noteId]; + var notebookId = data.notebookId; + + // trash不能复制, 不能复制给自己 + if(note.IsTrash || note.NotebookId == notebookId) { + return; + } + + var url = "/note/copyNote"; + var data = {noteId: noteId, notebookId: notebookId}; + if(isShared) { + url = "/note/copySharedNote"; + data.fromUserId = note.UserId; + } + + ajaxGet(url, data, function(ret) { + if(ret && ret.NoteId) { + // 重新清空cache 之后的 + Note.clearCacheByNotebookId(notebookId); + // 改变缓存, 添加之 + Note.setNoteCache(ret) + } + }); + + // 增加数量 + Notebook.incrNotebookNumberNotes(notebookId) +} + +// 这里速度不慢, 很快 +Note.getContextNotebooks = function(notebooks) { + var moves = []; + var copys = []; + var copys2 = []; + for(var i in notebooks) { + var notebook = notebooks[i]; + var move = {text: notebook.Title, notebookId: notebook.NotebookId, action: Note.moveNote} + var copy = {text: notebook.Title, notebookId: notebook.NotebookId, action: Note.copyNote} + var copy2 = {text: notebook.Title, notebookId: notebook.NotebookId, action: Share.copySharedNote} + if(!isEmpty(notebook.Subs)) { + var mc = Note.getContextNotebooks(notebook.Subs); + move.items = mc[0]; + copy.items = mc[1]; + copy2.items = mc[2]; + move.type = "group"; + move.width = 150; + copy.type = "group"; + copy.width = 150; + copy2.type = "group"; + copy2.width = 150; + } + moves.push(move); + copys.push(copy); + copys2.push(copy2); + } + return [moves, copys, copys2]; +} +// Notebook调用 +Note.contextmenu = null; +Note.notebooksCopy = []; // share会用到 +Note.initContextmenu = function() { + var self = Note; + if(Note.contextmenu) { + Note.contextmenu.destroy(); + } + // 得到可移动的notebook + var notebooks = Notebook.everNotebooks; + var mc = self.getContextNotebooks(notebooks); + + var notebooksMove = mc[0]; + var notebooksCopy = mc[1]; + self.notebooksCopy = mc[2]; + + //--------------------- + // context menu + //--------------------- + var noteListMenu = { + width: 180, + items: [ + { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Note.listNoteShareUserInfo}, + { type: "splitLine" }, + { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Note.setNote2Blog }, + { text: getMsg("cancelPublic"), alias: 'unset2Blog', faIcon: "fa-undo", action: Note.setNote2Blog }, + //{ type: "splitLine" }, + //{ text: "分享到社区", alias: 'html2Image', icon: "", action: Note.html2Image}, + { type: "splitLine" }, + { text: getMsg("delete"), icon: "", faIcon: "fa-trash-o", action: Note.deleteNote }, + { text: getMsg("move"), alias: "move", faIcon: "fa-arrow-right", + type: "group", + width: 180, + items: notebooksMove + }, + { text: getMsg("copy"), alias: "copy", icon:"", faIcon: "fa-copy", + type: "group", + width: 180, + items: notebooksCopy + } + ], + onShow: applyrule, + onContextMenu: beforeContextMenu, + + parent: "#noteItemList", + children: ".item-my", + } + + function menuAction(target) { + // $('#myModal').modal('show') + showDialog("dialogUpdateNotebook", {title: "修改笔记本", postShow: function() { + }}); + } + function applyrule(menu) { + var noteId = $(this).attr("noteId"); + var note = Note.cache[noteId]; + if(!note) { + return; + } + // 要disable的items + var items = []; + + // 如果是trash, 什么都不能做 + if(note.IsTrash) { + items.push("shareToFriends"); + items.push("shareStatus"); + items.push("unset2Blog"); + items.push("set2Blog"); + items.push("copy"); + } else { + // 是否已公开为blog + if(!note.IsBlog) { + items.push("unset2Blog"); + } else { + items.push("set2Blog"); + } + + // 移动与复制不能是本notebook下 + var notebookTitle = Notebook.getNotebookTitle(note.NotebookId); + items.push("move." + notebookTitle); + items.push("copy." + notebookTitle); + } + + menu.applyrule({ + name: "target..", + disable: true, + items: items + }); + + } + function beforeContextMenu() { + return this.id != "target3"; + } + + // 这里很慢!! + Note.contextmenu = $("#noteItemList .item-my").contextmenu(noteListMenu); +} + +// 附件 +// 笔记的附件需要ajax获取 +// 建一张附件表? attachId, noteId, 其它信息 +// note里有attach_nums字段记录个数 +// [ok] +var Attach = { + loadedNoteAttachs: {}, // noteId => [attch1Info, attach2Info...] // 按笔记 + attachsMap: {}, // attachId => attachInfo + init: function() { + var self = this; + // 显示attachs + $("#showAttach").click(function(){ + self.renderAttachs(Note.curNoteId); + }); + // 防止点击隐藏 + self.attachListO.click(function(e) { + e.stopPropagation(); + }); + // 删除 + self.attachListO.on("click", ".delete-attach", function(e) { + e.stopPropagation(); + var attachId = $(this).closest('li').data("id"); + var t = this; + if(confirm("Are you sure to delete it ?")) { + $(t).button("loading"); + ajaxPost("/attach/deleteAttach", {attachId: attachId}, function(re) { + $(t).button("reset"); + if(reIsOk(re)) { + self.deleteAttach(attachId); + } else { + alert(re.Msg); + } + }); + } + }); + // 下载 + self.attachListO.on("click", ".download-attach", function(e) { + e.stopPropagation(); + var attachId = $(this).closest('li').data("id"); + window.open(UrlPrefix + "/attach/download?attachId=" + attachId); + // location.href = "/attach/download?attachId=" + attachId; + }); + // 下载全部 + self.downloadAllBtnO.click(function() { + window.open(UrlPrefix + "/attach/downloadAll?noteId=" + Note.curNoteId); + // location.href = "/attach/downloadAll?noteId=" + Note.curNoteId; + }); + + // make link + self.attachListO.on("click", ".link-attach", function(e) { + e.stopPropagation(); + var attachId = $(this).closest('li').data("id"); + var attach = self.attachsMap[attachId]; + var src = UrlPrefix + "/attach/download?attachId=" + attachId; + if(LEA.isMarkdownEditor() && MarkdownEditor) { + MarkdownEditor.insertLink(src, attach.Title); + } else { + tinymce.activeEditor.insertContent('' + attach.Title + ''); + } + }); + + // make all link + self.linkAllBtnO.on("click",function(e) { + e.stopPropagation(); + var note = Note.getCurNote(); + if(!note) { + return; + } + var src = UrlPrefix + "/attach/downloadAll?noteId=" + Note.curNoteId + var title = note.Title ? note.Title + ".tar.gz" : "all.tar.gz"; + + if(LEA.isMarkdownEditor() && MarkdownEditor) { + MarkdownEditor.insertLink(src, title); + } else { + tinymce.activeEditor.insertContent('' + title + ''); + } + }); + }, + attachListO: $("#attachList"), + attachNumO: $("#attachNum"), + attachDropdownO: $("#attachDropdown"), + downloadAllBtnO: $("#downloadAllBtn"), + linkAllBtnO: $("#linkAllBtn"), + // 添加笔记时 + clearNoteAttachNum: function() { + var self = this; + self.attachNumO.html("").hide(); + }, + renderNoteAttachNum: function(noteId, needHide) { + var self = this; + var note = Note.getNote(noteId); + if(note.AttachNum) { + self.attachNumO.html("(" + note.AttachNum + ")").show(); + self.downloadAllBtnO.show(); + self.linkAllBtnO.show(); + } else { + self.attachNumO.hide(); + self.downloadAllBtnO.hide(); + self.linkAllBtnO.hide(); + } + + // 隐藏掉 + if(needHide) { + self.attachDropdownO.removeClass("open"); + } + }, + _renderAttachs: function(attachs) { + var self = this; + // foreach 循环之 + /* +
      • +
        leanote官abcefedafadfadfadfadfad方文档.doc
        +
        + + +
        +
      • + */ + var html = ""; + var attachNum = attachs.length; + for(var i = 0; i < attachNum; ++i) { + var each = attachs[i]; + html += '
      • ' + + '
        ' + each.Title + '
        ' + + '
        ' + + ' ' + + ' ' + + ' ' + + '
        ' + + '
      • '; + self.attachsMap[each.AttachId] = each; + } + self.attachListO.html(html); + + // 设置数量 + var note = Note.getCurNote(); + if(note) { + note.AttachNum = attachNum; + self.renderNoteAttachNum(note.NoteId, false); + } + }, + // 渲染noteId的附件 + // 当点击"附件"时加载, + // TODO 判断是否已loaded + renderAttachs: function(noteId) { + var self = this; + if(self.loadedNoteAttachs[noteId]) { + self._renderAttachs(self.loadedNoteAttachs[noteId]); + return; + } + // 显示loading + self.attachListO.html('
      • '); + // ajax获取noteAttachs + ajaxGet("/attach/getAttachs", {noteId: noteId}, function(ret) { + var list = []; + if(ret.Ok) { + list = ret.List; + if(!list) { + list = []; + } + } + // 添加到缓存中 + self.loadedNoteAttachs[noteId] = list; + self._renderAttachs(list); + }); + }, + // 添加附件, attachment_upload上传调用 + addAttach: function(attachInfo) { + var self = this; + if(!self.loadedNoteAttachs[attachInfo.NoteId]) { + self.loadedNoteAttachs[attachInfo.NoteId] = []; + } + self.loadedNoteAttachs[attachInfo.NoteId].push(attachInfo); + self.renderAttachs(attachInfo.NoteId); + }, + // 删除 + deleteAttach: function(attachId) { + var self = this; + var noteId = Note.curNoteId; + var attachs = self.loadedNoteAttachs[noteId]; + for(var i = 0; i < attachs.length; ++i) { + if(attachs[i].AttachId == attachId) { + // 删除之, 并render之 + attachs.splice(i, 1); + break; + } + } + // self.loadedNoteAttachs[noteId] = attachs; + self.renderAttachs(noteId); + }, + + // 下载 + downloadAttach: function(fileId) { + var self = this; + }, + downloadAll: function() { + } +} + +//------------------- 事件 +$(function() { + // 附件初始化 + Attach.init(); + + //----------------- + // for list nav + $("#noteItemList").on("click", ".item", function(event) { + log(event); + event.stopPropagation(); + var noteId = $(this).attr("noteId"); + + // 手机端处理 + Mobile.changeNote(noteId); + + if(!noteId) { + return; + } + // 当前的和所选的是一个, 不改变 + if(Note.curNoteId != noteId) { + Note.changeNote(noteId); + } + }); + + //------------------ + // 新建笔记 + // 1. 直接点击新建 OR + // 2. 点击nav for new note + $("#newNoteBtn, #editorMask .note").click(function() { + var notebookId = $("#curNotebookForNewNote").attr('notebookId'); + Note.newNote(notebookId); + }); + $("#newNoteMarkdownBtn, #editorMask .markdown").click(function() { + var notebookId = $("#curNotebookForNewNote").attr('notebookId'); + Note.newNote(notebookId, false, "", true); + }); + $("#notebookNavForNewNote").on("click", "li div", function() { + var notebookId = $(this).attr("notebookId"); + if($(this).hasClass("new-note-right")) { + Note.newNote(notebookId, false, "", true); + } else { + Note.newNote(notebookId); + } + }); + $("#searchNotebookForAdd").click(function(e) { + e.stopPropagation(); + }); + $("#searchNotebookForAdd").keyup(function() { + var key = $(this).val(); + Notebook.searchNotebookForAddNote(key); + }); + $("#searchNotebookForList").keyup(function() { + var key = $(this).val(); + Notebook.searchNotebookForList(key); + }); + + //--------------------------- + // 搜索, 按enter才搜索 + /* + $("#searchNoteInput").on("keyup", function(e) { + Note.searchNote(); + }); + */ + $("#searchNoteInput").on("keydown", function(e) { + var theEvent = e; // window.event || arguments.callee.caller.arguments[0]; + if(theEvent.keyCode == 13 || theEvent.keyCode == 108) { + theEvent.preventDefault(); + Note.searchNote(); + return false; + } + }); + + //-------------------- + // Note.initContextmenu(); + + //------------ + // 文档历史 + $("#contentHistory").click(function() { + Note.listNoteContentHistories() + }); + + $("#saveBtn").click(function() { + Note.curChangedSaveIt(true); + }); + + // blog + $("#noteItemList").on("click", ".item-blog", function(e) { + e.preventDefault(); + e.stopPropagation(); + // 得到ID + var noteId = $(this).parent().attr('noteId'); + window.open("/blog/view/" + noteId); + }); + + // note setting + $("#noteItemList").on("click", ".item-my .item-setting", function(e) { + e.preventDefault(); + e.stopPropagation(); + var $p = $(this).parent(); + Note.contextmenu.showMenu(e, $p); + }); +}); + +// 定时器启动 +Note.startInterval(); \ No newline at end of file diff --git a/public/js/app/notebook-min.js b/public/js/app/notebook-min.js new file mode 100644 index 0000000..9adb6ec --- /dev/null +++ b/public/js/app/notebook-min.js @@ -0,0 +1 @@ +Notebook.curNotebookId="";Notebook.cache={};Notebook.notebooks=[];Notebook.notebookNavForListNote="";Notebook.notebookNavForNewNote="";Notebook.setCache=function(notebook){var notebookId=notebook.NotebookId;if(!notebookId){return}if(!Notebook.cache[notebookId]){Notebook.cache[notebookId]={}}$.extend(Notebook.cache[notebookId],notebook)};Notebook.getCurNotebookId=function(){return Notebook.curNotebookId};Notebook._updateNotebookNumberNotes=function(notebookId,n){var self=this;var notebook=self.getNotebook(notebookId);if(!notebook){return}notebook.NumberNotes+=n;if(notebook.NumberNotes<0){notebook.NumberNotes=0}$("#numberNotes_"+notebookId).html(notebook.NumberNotes)};Notebook.incrNotebookNumberNotes=function(notebookId){var self=this;self._updateNotebookNumberNotes(notebookId,1)};Notebook.minusNotebookNumberNotes=function(notebookId){var self=this;self._updateNotebookNumberNotes(notebookId,-1)};Notebook.getNotebook=function(notebookId){return Notebook.cache[notebookId]};Notebook.getNotebookTitle=function(notebookId){var notebook=Notebook.cache[notebookId];if(notebook){return notebook.Title}else{return"未知"}};Notebook.getTreeSetting=function(isSearch,isShare){var noSearch=!isSearch;var self=this;function addDiyDom(treeId,treeNode){var spaceWidth=5;var switchObj=$("#"+treeId+" #"+treeNode.tId+"_switch"),icoObj=$("#"+treeId+" #"+treeNode.tId+"_ico");switchObj.remove();icoObj.before(switchObj);if(!isShare){if(!Notebook.isAllNotebookId(treeNode.NotebookId)&&!Notebook.isTrashNotebookId(treeNode.NotebookId)){icoObj.after($(''+(treeNode.NumberNotes||0)+""));icoObj.after($(''))}}else{if(!Share.isDefaultNotebookId(treeNode.NotebookId)){icoObj.after($(''))}}if(treeNode.level>1){var spaceStr="";switchObj.before(spaceStr)}}function beforeDrag(treeId,treeNodes){for(var i=0,l=treeNodes.length;i
        ?
        M
        ',classes,notebook.NotebookId,notebook.Title,notebook.NotebookId);if(!isEmpty(notebook.Subs)){eachForNew+=""}eachForNew+="";navForNewNote+=eachForNew}return navForNewNote};Notebook.everNavForNewNote="";Notebook.everNotebooks=[];Notebook.changeNav=function(){var self=Notebook;var notebooks=Notebook.tree.getNodes();var pureNotebooks=notebooks.slice(1,-1);var html=self.getChangedNotebooks(pureNotebooks);self.everNavForNewNote=html;self.everNotebooks=pureNotebooks;$("#notebookNavForNewNote").html(html);var t1=(new Date).getTime();Note.initContextmenu();Share.initContextmenu(Note.notebooksCopy);var t2=(new Date).getTime();log(t2-t1)};Notebook.renderShareNotebooks=function(sharedUserInfos,shareNotebooks){if(isEmpty(sharedUserInfos)){return}if(!shareNotebooks||typeof shareNotebooks!="object"||shareNotebooks.length<0){return}var $shareNotebooks=$("#shareNotebooks");var user2ShareNotebooks={};for(var i in shareNotebooks){var userNotebooks=shareNotebooks[i];user2ShareNotebooks[userNotebooks.UserId]=userNotebooks}for(var i in sharedUserInfos){var userInfo=sharedUserInfos[i];var userNotebooks=user2ShareNotebooks[userInfo.UserId]||{ShareNotebooks:[]};userNotebooks.ShareNotebooks=[{NotebookId:"-2",Title:"默认共享"}].concat(userNotebooks.ShareNotebooks);var username=userInfo.Username||userInfo.Email;var header=tt('
        ',username,username);var body='
          ';for(var j in userNotebooks.ShareNotebooks){var notebook=userNotebooks.ShareNotebooks[j];body+=tt('
        • ?
        • ',notebook.NotebookId,notebook.Title)}body+="
        ";$shareNotebooks.append(header+body+"
        ")}};Notebook.selectNotebook=function(target){$(".notebook-item").removeClass("curSelectedNode");$(target).addClass("curSelectedNode")};Notebook.changeNotebookNavForNewNote=function(notebookId,title){if(!notebookId){var notebook=Notebook.notebooks[0];notebookId=notebook.NotebookId;title=notebook.Title}if(!title){var notebook=Notebook.cache[0];title=notebook.Title}if(!Notebook.isAllNotebookId(notebookId)&&!Notebook.isTrashNotebookId(notebookId)){$("#curNotebookForNewNote").html(title).attr("notebookId",notebookId)}else if(!$("#curNotebookForNewNote").attr("notebookId")){if(Notebook.notebooks.length>2){var notebook=Notebook.notebooks[1];notebookId=notebook.NotebookId;title=notebook.Title;Notebook.changeNotebookNavForNewNote(notebookId,title)}}};Notebook.toggleToMyNav=function(userId,notebookId){$("#sharedNotebookNavForListNav").hide();$("#myNotebookNavForListNav").show();$("#newMyNote").show();$("#newSharedNote").hide();$("#tagSearch").hide()};Notebook.changeNotebookNav=function(notebookId){Notebook.toggleToMyNav();Notebook.selectNotebook($(tt('#notebookList [notebookId="?"]',notebookId)));var notebook=Notebook.cache[notebookId];if(!notebook){return}$("#curNotebookForListNote").html(notebook.Title);Notebook.changeNotebookNavForNewNote(notebookId,notebook.Title)};Notebook.isAllNotebookId=function(notebookId){return notebookId==Notebook.allNotebookId};Notebook.isTrashNotebookId=function(notebookId){return notebookId==Notebook.trashNotebookId};Notebook.curActiveNotebookIsAll=function(){return Notebook.isAllNotebookId($("#notebookList .active").attr("notebookId"))};Notebook.changeNotebook=function(notebookId){Notebook.changeNotebookNav(notebookId);Notebook.curNotebookId=notebookId;Note.curChangedSaveIt();Note.clearAll();var url="/note/ListNotes/";var param={notebookId:notebookId};if(Notebook.isTrashNotebookId(notebookId)){url="/note/listTrashNotes";param={}}else if(Notebook.isAllNotebookId(notebookId)){param={};cacheNotes=Note.getNotesByNotebookId();if(!isEmpty(cacheNotes)){Note.renderNotesAndFirstOneContent(cacheNotes);return}}else{cacheNotes=Note.getNotesByNotebookId(notebookId);if(!isEmpty(cacheNotes)){Note.renderNotesAndFirstOneContent(cacheNotes);return}}ajaxGet(url,param,Note.renderNotesAndFirstOneContent)};Notebook.isCurNotebook=function(notebookId){return $(tt('#notebookList [notebookId="?"], #shareNotebooks [notebookId="?"]',notebookId,notebookId)).attr("class")=="active"};Notebook.changeNotebookForNewNote=function(notebookId){if(Notebook.isTrashNotebookId(notebookId)||Notebook.isAllNotebookId(notebookId)){return}Notebook.changeNotebookNav(notebookId);Notebook.curNotebookId=notebookId;var url="/note/ListNotes/";var param={notebookId:notebookId};ajaxGet(url,param,function(ret){Note.renderNotes(ret,true)})};Notebook.listNotebookShareUserInfo=function(target){var notebookId=$(target).attr("notebookId");showDialogRemote("share/listNotebookShareUserInfo",{notebookId:notebookId})};Notebook.shareNotebooks=function(target){var title=$(target).text();showDialog("dialogShareNote",{title:"分享笔记本给好友-"+title});setTimeout(function(){$("#friendsEmail").focus()},500);var notebookId=$(target).attr("notebookId");shareNoteOrNotebook(notebookId,false)};Notebook.setNotebook2Blog=function(target){var notebookId=$(target).attr("notebookId");var notebook=Notebook.cache[notebookId];var isBlog=true;if(notebook.IsBlog!=undefined){isBlog=!notebook.IsBlog}if(Notebook.curNotebookId==notebookId){if(isBlog){$("#noteList .item-blog").show()}else{$("#noteList .item-blog").hide()}}else if(Notebook.curNotebookId==Notebook.allNotebookId){$("#noteItemList .item").each(function(){var noteId=$(this).attr("noteId");var note=Note.cache[noteId];if(note.NotebookId==notebookId){if(isBlog)$(this).find(".item-blog").show();else $(this).find(".item-blog").hide()}})}ajaxPost("notebook/setNotebook2Blog",{notebookId:notebookId,isBlog:isBlog},function(ret){if(ret){Note.setAllNoteBlogStatus(notebookId,isBlog);Notebook.setCache({NotebookId:notebookId,IsBlog:isBlog})}})};Notebook.updateNotebookTitle=function(target){var self=Notebook;var notebookId=$(target).attr("notebookId");if(self.tree2){self.tree2.editName(self.tree2.getNodeByTId(notebookId))}else{self.tree.editName(self.tree.getNodeByTId(notebookId))}};Notebook.doUpdateNotebookTitle=function(notebookId,newTitle){var self=Notebook;ajaxPost("/notebook/updateNotebookTitle",{notebookId:notebookId,title:newTitle},function(ret){Notebook.cache[notebookId].Title=newTitle;Notebook.changeNav();if(self.tree2){var notebook=self.tree.getNodeByTId(notebookId);notebook.Title=newTitle;self.tree.updateNode(notebook)}})};Notebook.addNotebookSeq=1;Notebook.addNotebook=function(){var self=Notebook;if($("#myNotebooks").hasClass("closed")){$("#myNotebooks .folderHeader").trigger("click")}self.tree.addNodes(null,{Title:"",NotebookId:getObjectId(),IsNew:true},true,true)};Notebook.doAddNotebook=function(notebookId,title,parentNotebookId){var self=Notebook;ajaxPost("/notebook/addNotebook",{notebookId:notebookId,title:title,parentNotebookId:parentNotebookId},function(ret){if(ret.NotebookId){Notebook.cache[ret.NotebookId]=ret;var notebook=self.tree.getNodeByTId(notebookId);$.extend(notebook,ret);notebook.IsNew=false;Notebook.changeNotebook(notebookId);Notebook.changeNav()}})};Notebook.addChildNotebook=function(target){var self=Notebook;if($("#myNotebooks").hasClass("closed")){$("#myNotebooks .folderHeader").trigger("click")}var notebookId=$(target).attr("notebookId");self.tree.addNodes(self.tree.getNodeByTId(notebookId),{Title:"",NotebookId:getObjectId(),IsNew:true},false,true)};Notebook.deleteNotebook=function(target){var self=Notebook;var notebookId=$(target).attr("notebookId");if(!notebookId){return}ajaxGet("/notebook/deleteNotebook",{notebookId:notebookId},function(ret){if(ret.Ok){self.tree.removeNode(self.tree.getNodeByTId(notebookId));if(self.tree2){self.tree2.removeNode(self.tree2.getNodeByTId(notebookId))}delete Notebook.cache[notebookId];Notebook.changeNav()}else{alert(ret.Msg)}})};$(function(){$("#minNotebookList").on("click","li",function(){var notebookId=$(this).find("a").attr("notebookId");Notebook.changeNotebook(notebookId)});var notebookListMenu={width:180,items:[{text:getMsg("shareToFriends"),alias:"shareToFriends",icon:"",faIcon:"fa-share-square-o",action:Notebook.listNotebookShareUserInfo},{type:"splitLine"},{text:getMsg("publicAsBlog"),alias:"set2Blog",faIcon:"fa-bold",action:Notebook.setNotebook2Blog},{text:getMsg("cancelPublic"),alias:"unset2Blog",faIcon:"fa-undo",action:Notebook.setNotebook2Blog},{type:"splitLine"},{text:getMsg("addChildNotebook"),faIcon:"fa-sitemap",action:Notebook.addChildNotebook},{text:getMsg("rename"),faIcon:"fa-pencil",action:Notebook.updateNotebookTitle},{text:getMsg("delete"),icon:"",alias:"delete",faIcon:"fa-trash-o",action:Notebook.deleteNotebook}],onShow:applyrule,onContextMenu:beforeContextMenu,parent:"#notebookList ",children:"li a"};var notebookListMenu2={width:180,items:[{text:getMsg("shareToFriends"),alias:"shareToFriends",icon:"",faIcon:"fa-share-square-o",action:Notebook.listNotebookShareUserInfo},{type:"splitLine"},{text:getMsg("publicAsBlog"),alias:"set2Blog",faIcon:"fa-bold",action:Notebook.setNotebook2Blog},{text:getMsg("cancelPublic"),alias:"unset2Blog",faIcon:"fa-undo",action:Notebook.setNotebook2Blog},{type:"splitLine"},{text:getMsg("rename"),icon:"",action:Notebook.updateNotebookTitle},{text:getMsg("delete"),icon:"",alias:"delete",faIcon:"fa-trash-o",action:Notebook.deleteNotebook}],onShow:applyrule,onContextMenu:beforeContextMenu,parent:"#notebookListForSearch ",children:"li a"};function applyrule(menu){var notebookId=$(this).attr("notebookId");var notebook=Notebook.cache[notebookId];if(!notebook){return}var items=[];if(!notebook.IsBlog){items.push("unset2Blog")}else{items.push("set2Blog")}if(Note.notebookHasNotes(notebookId)){items.push("delete")}menu.applyrule({name:"target2",disable:true,items:items})}function beforeContextMenu(){var notebookId=$(this).attr("notebookId");return!Notebook.isTrashNotebookId(notebookId)&&!Notebook.isAllNotebookId(notebookId)}Notebook.contextmenu=$("#notebookList li a").contextmenu(notebookListMenu);Notebook.contextmenuSearch=$("#notebookListForSearch li a").contextmenu(notebookListMenu2);$("#addNotebookPlus").click(function(e){e.stopPropagation();Notebook.addNotebook()});$("#notebookList").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();Notebook.contextmenu.showMenu(e,$p)});$("#notebookListForSearch").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();Notebook.contextmenuSearch.showMenu(e,$p)})}); \ No newline at end of file diff --git a/public/js/app/notebook.js b/public/js/app/notebook.js new file mode 100644 index 0000000..d3204b7 --- /dev/null +++ b/public/js/app/notebook.js @@ -0,0 +1,888 @@ +Notebook.curNotebookId = ""; +Notebook.cache = {}; // notebookId => {}; +Notebook.notebooks = []; // 按次序 +//
      • CSS
      • +Notebook.notebookNavForListNote = ""; // html 为了note list上面和新建时的ul +Notebook.notebookNavForNewNote = ""; // html 为了note list上面和新建时的ul + +// 设置缓存 +Notebook.setCache = function(notebook) { + var notebookId = notebook.NotebookId; + if(!notebookId) { + return; + } + if(!Notebook.cache[notebookId]) { + Notebook.cache[notebookId] = {}; + } + $.extend(Notebook.cache[notebookId], notebook); +} + +Notebook.getCurNotebookId = function() { + return Notebook.curNotebookId; +}; + +// 笔记本的笔记数量更新 +Notebook._updateNotebookNumberNotes = function(notebookId, n) { + var self = this; + var notebook = self.getNotebook(notebookId); + if(!notebook) { + return; + } + notebook.NumberNotes += n; + if(notebook.NumberNotes < 0) { + notebook.NumberNotes = 0; + } + $("#numberNotes_" + notebookId).html(notebook.NumberNotes); +}; +// addNote, copyNote, moveNote +Notebook.incrNotebookNumberNotes = function(notebookId) { + var self = this; + self._updateNotebookNumberNotes(notebookId, 1); +}; +// moteNote, deleteNote +Notebook.minusNotebookNumberNotes = function(notebookId) { + var self = this; + self._updateNotebookNumberNotes(notebookId, -1); +}; + +// 得到notebook标题, 给note显示其notebook标题用 +// called by Note +Notebook.getNotebook = function(notebookId) { + return Notebook.cache[notebookId]; +} +// called by Note +Notebook.getNotebookTitle = function(notebookId) { + var notebook = Notebook.cache[notebookId]; + if(notebook) { + return notebook.Title; + } else { + return "未知"; + } +} + +/** + * 我的notebooks + + */ + +Notebook.getTreeSetting = function(isSearch, isShare){ + var noSearch = !isSearch; + + var self = this; + // 添加自定义dom + function addDiyDom(treeId, treeNode) { + var spaceWidth = 5; + var switchObj = $("#" + treeId + " #" + treeNode.tId + "_switch"), + icoObj = $("#" + treeId + " #" + treeNode.tId + "_ico"); + switchObj.remove(); + icoObj.before(switchObj); + if(!isShare) { + if(!Notebook.isAllNotebookId(treeNode.NotebookId) && !Notebook.isTrashNotebookId(treeNode.NotebookId)) { + icoObj.after($('' + (treeNode.NumberNotes || 0) + '')); + icoObj.after($('')); + } + } else { + if(!Share.isDefaultNotebookId(treeNode.NotebookId)) { + icoObj.after($('')); + } + } + if (treeNode.level > 1) { + var spaceStr = ""; + switchObj.before(spaceStr); + } + } + // 拖拽 + function beforeDrag(treeId, treeNodes) { + for (var i=0,l=treeNodes.length; i
        ?
        M
        ', classes, notebook.NotebookId, notebook.Title, notebook.NotebookId); + + if(!isEmpty(notebook.Subs)) { + eachForNew += ""; + } + + eachForNew += ''; + + navForNewNote += eachForNew; + } + return navForNewNote; +} + +Notebook.everNavForNewNote = ""; +Notebook.everNotebooks = []; +Notebook.changeNav = function() { + var self = Notebook; + var notebooks = Notebook.tree.getNodes(); + var pureNotebooks = notebooks.slice(1, -1); // 不含新和垃圾 + var html = self.getChangedNotebooks(pureNotebooks); + + self.everNavForNewNote = html; + self.everNotebooks = pureNotebooks; + + $("#notebookNavForNewNote").html(html); + + // 移动, 复制重新来, 因为nav变了, 移动至-----的notebook导航也变了 + // 这里速度很慢 + var t1 = (new Date()).getTime(); + Note.initContextmenu(); + Share.initContextmenu(Note.notebooksCopy); + var t2 = (new Date()).getTime(); + log(t2-t1); +} + +/** + * 我的共享notebooks +
        + + */ +// TODO 层级 +Notebook.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { + if(isEmpty(sharedUserInfos)) { + return; + } + + if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) { + return; + } + + var $shareNotebooks = $("#shareNotebooks"); + var user2ShareNotebooks = {}; + for(var i in shareNotebooks) { + var userNotebooks = shareNotebooks[i]; + user2ShareNotebooks[userNotebooks.UserId] = userNotebooks; + } + for(var i in sharedUserInfos) { + var userInfo = sharedUserInfos[i]; + var userNotebooks = user2ShareNotebooks[userInfo.UserId] || {ShareNotebooks:[]}; + + userNotebooks.ShareNotebooks = [{NotebookId: "-2", Title: "默认共享"}].concat(userNotebooks.ShareNotebooks) + + var username = userInfo.Username || userInfo.Email; + var header = tt('
        ', username, username); + var body = '
          '; + for(var j in userNotebooks.ShareNotebooks) { + var notebook = userNotebooks.ShareNotebooks[j]; + body += tt('
        • ?
        • ', notebook.NotebookId, notebook.Title) + } + body += "
        "; + + $shareNotebooks.append(header + body + "
        ") + } +} + +// 左侧导航, 选中某个notebook +Notebook.selectNotebook = function(target) { + $(".notebook-item").removeClass("curSelectedNode"); + $(target).addClass("curSelectedNode"); +}; + +// 新建笔记导航 +Notebook.changeNotebookNavForNewNote = function(notebookId, title) { + // 没有notebookId, 则选择第1个notebook + // 第一个是全部笔记 + if(!notebookId) { + var notebook = Notebook.notebooks[0]; + notebookId = notebook.NotebookId; + title = notebook.Title; + } + if(!title) { + var notebook = Notebook.cache[0]; + title = notebook.Title; + } + + if(!Notebook.isAllNotebookId(notebookId) && !Notebook.isTrashNotebookId(notebookId)) { + $("#curNotebookForNewNote").html(title).attr("notebookId", notebookId); + } else if(!$("#curNotebookForNewNote").attr("notebookId")) { + // 但又没有一个笔记, 默认选第一个吧 + // 这里很可能会死循环, 万一用户没有其它笔记呢? + // 服务端肯定要在新建一个用户时给他创建一个默认笔记本的 + if(Notebook.notebooks.length > 2) { + var notebook = Notebook.notebooks[1]; + notebookId = notebook.NotebookId; + title = notebook.Title; + Notebook.changeNotebookNavForNewNote(notebookId, title); + } + } +} + +// 改变导航, 两处 +// 单击左侧, 单击新建下拉时调用 +// 1 选中左侧导航, +// 2 notelist上面 > +// 3 新建笔记 - js > +// 转成我的nav <-> 共享 +Notebook.toggleToMyNav = function(userId, notebookId) { + $("#sharedNotebookNavForListNav").hide(); + $("#myNotebookNavForListNav").show(); + + $("#newMyNote").show(); + $("#newSharedNote").hide(); + + // 搜索tag隐藏 + $("#tagSearch").hide(); +} +Notebook.changeNotebookNav = function(notebookId) { + Notebook.toggleToMyNav(); + + // 1 + Notebook.selectNotebook($(tt('#notebookList [notebookId="?"]', notebookId))); + + var notebook = Notebook.cache[notebookId]; + + if(!notebook) { + return; + } + + // 2 + $("#curNotebookForListNote").html(notebook.Title); + + // 3 + Notebook.changeNotebookNavForNewNote(notebookId, notebook.Title); +} + +Notebook.isAllNotebookId = function(notebookId) { + return notebookId == Notebook.allNotebookId; +} +Notebook.isTrashNotebookId = function(notebookId) { + return notebookId == Notebook.trashNotebookId; +} +// 当前选中的笔记本是否是"所有" +// called by Note +Notebook.curActiveNotebookIsAll = function() { + return Notebook.isAllNotebookId($("#notebookList .active").attr("notebookId")); +} + +// 改变笔记本 +// 0. 改变样式 +// 1. 改变note, 此时需要先保存 +// 2. ajax得到该notebook下的所有note +// 3. 使用Note.RederNotes() +Notebook.changeNotebook = function(notebookId) { + Notebook.changeNotebookNav(notebookId); + + Notebook.curNotebookId = notebookId; + + // 1 + Note.curChangedSaveIt(); + + // 2 先清空所有 + Note.clearAll(); + + var url = "/note/ListNotes/"; + var param = {notebookId: notebookId}; + + // 废纸篓 + if(Notebook.isTrashNotebookId(notebookId)) { + url = "/note/listTrashNotes"; + param = {}; + } else if(Notebook.isAllNotebookId(notebookId)) { + param = {}; + // 得到全部的... + cacheNotes = Note.getNotesByNotebookId(); + if(!isEmpty(cacheNotes)) { // 万一真的是没有呢? + Note.renderNotesAndFirstOneContent(cacheNotes); + return; + } + } else { + cacheNotes = Note.getNotesByNotebookId(notebookId); + if(!isEmpty(cacheNotes)) { // 万一真的是没有呢? + Note.renderNotesAndFirstOneContent(cacheNotes); + return; + } + } + + // 2 得到笔记本 + // 这里可以缓存起来, note按notebookId缓存 + ajaxGet(url, param, Note.renderNotesAndFirstOneContent); +} + +// 是否是当前选中的notebookId +// 还包括共享 +// called by Note +Notebook.isCurNotebook = function(notebookId) { + return $(tt('#notebookList [notebookId="?"], #shareNotebooks [notebookId="?"]', notebookId, notebookId)).attr("class") == "active"; +} + +// 改变nav, 为了新建note +// called by Note +Notebook.changeNotebookForNewNote = function(notebookId) { + // 废纸篓 + if(Notebook.isTrashNotebookId(notebookId) || Notebook.isAllNotebookId(notebookId)) { + return; + } + + Notebook.changeNotebookNav(notebookId); + Notebook.curNotebookId = notebookId; + + var url = "/note/ListNotes/"; + var param = {notebookId: notebookId}; + + // 2 得到笔记本 + // 这里可以缓存起来, note按notebookId缓存 + ajaxGet(url, param, function(ret) { + // note 导航 + Note.renderNotes(ret, true); + }); +}; + +//--------------------------- +// 显示共享信息 +Notebook.listNotebookShareUserInfo = function(target) { + var notebookId = $(target).attr("notebookId"); + showDialogRemote("share/listNotebookShareUserInfo", {notebookId: notebookId}); +} +// 共享笔记本 +Notebook.shareNotebooks= function(target) { + var title = $(target).text(); + showDialog("dialogShareNote", {title: "分享笔记本给好友-" + title}); + setTimeout(function() { + $("#friendsEmail").focus(); + }, 500); + var notebookId = $(target).attr("notebookId"); + + shareNoteOrNotebook(notebookId, false); +} + +//----------------------------- +// 设为blog/unset +Notebook.setNotebook2Blog = function(target) { + var notebookId = $(target).attr("notebookId"); + var notebook = Notebook.cache[notebookId]; + var isBlog = true; + if(notebook.IsBlog != undefined) { + isBlog = !notebook.IsBlog; + } + + // 那么, 如果当前是该notebook下, 重新渲染之 + if(Notebook.curNotebookId == notebookId) { + if(isBlog) { + $("#noteList .item-blog").show(); + } else { + $("#noteList .item-blog").hide(); + } + + // 如果当前在所有笔记本下 + } else if(Notebook.curNotebookId == Notebook.allNotebookId){ + $("#noteItemList .item").each(function(){ + var noteId = $(this).attr("noteId"); + var note = Note.cache[noteId]; + if(note.NotebookId == notebookId) { + if(isBlog) $(this).find(".item-blog").show(); + else $(this).find(".item-blog").hide(); + } + }); + } + ajaxPost("notebook/setNotebook2Blog", {notebookId: notebookId, isBlog: isBlog}, function(ret) { + if(ret) { + // 这里要设置notebook下的note的blog状态 + Note.setAllNoteBlogStatus(notebookId, isBlog); + Notebook.setCache({NotebookId: notebookId, IsBlog: isBlog}); + } + }); +} + +// 添加, 修改完后都要对notebook的列表重新计算 TODO + +// 修改笔记本标题 +Notebook.updateNotebookTitle = function(target) { + var self = Notebook; + var notebookId = $(target).attr("notebookId"); + + if(self.tree2) { + self.tree2.editName(self.tree2.getNodeByTId(notebookId)); + } else { + self.tree.editName(self.tree.getNodeByTId(notebookId)); + } +} +Notebook.doUpdateNotebookTitle = function(notebookId, newTitle) { + var self = Notebook; + ajaxPost("/notebook/updateNotebookTitle", {notebookId: notebookId, title: newTitle}, function(ret) { + // 修改缓存 + Notebook.cache[notebookId].Title = newTitle; + // 改变nav + Notebook.changeNav(); + + // 同步 + if(self.tree2) { + var notebook = self.tree.getNodeByTId(notebookId); + notebook.Title = newTitle; + self.tree.updateNode(notebook); + } + }); +} + +//----------- +// 添加笔记本 +// 1 确保是展开的 +// 2 在所有后面添加
      • +Notebook.addNotebookSeq = 1; // inputId +Notebook.addNotebook = function() { + var self = Notebook; + if($("#myNotebooks").hasClass("closed")) { + $("#myNotebooks .folderHeader").trigger("click"); + } + + // 添加并修改 + self.tree.addNodes(null, {Title: "", NotebookId: getObjectId(), IsNew: true}, true, true); +} + +// rename 调用 +Notebook.doAddNotebook = function(notebookId, title, parentNotebookId) { + var self = Notebook; + ajaxPost("/notebook/addNotebook", {notebookId: notebookId, title: title, parentNotebookId: parentNotebookId}, function(ret) { + if(ret.NotebookId) { + Notebook.cache[ret.NotebookId] = ret; + var notebook = self.tree.getNodeByTId(notebookId); + $.extend(notebook, ret); + notebook.IsNew = false; + + // 选中之 + Notebook.changeNotebook(notebookId); + + // 改变nav + Notebook.changeNav(); + } + }); +} + +//------------- +// 添加子笔记本 +Notebook.addChildNotebook = function(target) { + var self = Notebook; + if($("#myNotebooks").hasClass("closed")) { + $("#myNotebooks .folderHeader").trigger("click"); + } + + var notebookId = $(target).attr("notebookId"); + + // 添加并修改 + self.tree.addNodes(self.tree.getNodeByTId(notebookId), {Title: "", NotebookId: getObjectId(), IsNew: true}, false, true); +} + +//------------- +// 删除 +Notebook.deleteNotebook = function(target) { + var self = Notebook; + + var notebookId = $(target).attr("notebookId"); + if(!notebookId) { + return; + } + + ajaxGet("/notebook/deleteNotebook", {notebookId: notebookId}, function(ret) { + if(ret.Ok) { + /* + $(target).parent().remove(); + */ + self.tree.removeNode(self.tree.getNodeByTId(notebookId)); + if(self.tree2) { + self.tree2.removeNode(self.tree2.getNodeByTId(notebookId)); + } + delete Notebook.cache[notebookId]; + + // 改变nav + Notebook.changeNav(); + } else { + alert(ret.Msg); + } + }); +} + +$(function() { + //------------------- + // 点击notebook + /* + $("#myNotebooks").on("click", "ul.folderBody li a", function() { + var notebookId = $(this).attr("notebookId"); + Notebook.changeNotebook(notebookId); + }); + */ + // min + $("#minNotebookList").on("click", "li", function() { + var notebookId = $(this).find("a").attr("notebookId"); + Notebook.changeNotebook(notebookId); + }); + + // 修改笔记本标题, blur后修改标题之 + /* + enterBlur("#notebookList", "input#editNotebookTitle"); + $("#notebookList").on("blur", "input#editNotebookTitle", Notebook.doUpdateNotebookTitle); + */ + + //------------------- + // 右键菜单 + var notebookListMenu = { + width: 180, + items: [ + { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Notebook.listNotebookShareUserInfo}, + { type: "splitLine" }, + { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Notebook.setNotebook2Blog }, + { text: getMsg("cancelPublic"), alias: 'unset2Blog',faIcon: "fa-undo", action: Notebook.setNotebook2Blog }, // Unset + { type: "splitLine" }, + { text: getMsg("addChildNotebook"), faIcon: "fa-sitemap", action: Notebook.addChildNotebook }, + { text: getMsg("rename"), faIcon: "fa-pencil", action: Notebook.updateNotebookTitle }, + { text: getMsg("delete"), icon: "", alias: 'delete', faIcon: "fa-trash-o", action: Notebook.deleteNotebook } + ], + onShow: applyrule, + onContextMenu: beforeContextMenu, + parent: "#notebookList ", + children: "li a" + } + + // for search + var notebookListMenu2 = { + width: 180, + items: [ + { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Notebook.listNotebookShareUserInfo}, + { type: "splitLine" }, + { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Notebook.setNotebook2Blog }, + { text: getMsg("cancelPublic"), alias: 'unset2Blog',faIcon: "fa-undo", action: Notebook.setNotebook2Blog }, // Unset + { type: "splitLine" }, + { text: getMsg("rename"), icon: "", action: Notebook.updateNotebookTitle }, + { text: getMsg("delete"), icon: "", alias: 'delete', faIcon: "fa-trash-o", action: Notebook.deleteNotebook } + ], + onShow: applyrule, + onContextMenu: beforeContextMenu, + parent: "#notebookListForSearch ", + children: "li a" + } + + function applyrule(menu) { + var notebookId = $(this).attr("notebookId"); + var notebook = Notebook.cache[notebookId]; + if(!notebook) { + return; + } + // disabled的items + var items = []; + // 是否已公开为blog + if(!notebook.IsBlog) { + items.push("unset2Blog"); + } else { + items.push("set2Blog"); + } + // 是否还有笔记 + if(Note.notebookHasNotes(notebookId)) { + items.push("delete"); + } + menu.applyrule({ + name: "target2", + disable: true, + items: items + }); + } + // 哪个不能 + function beforeContextMenu() { + var notebookId = $(this).attr("notebookId"); + return !Notebook.isTrashNotebookId(notebookId) && !Notebook.isAllNotebookId(notebookId); + } + + Notebook.contextmenu = $("#notebookList li a").contextmenu(notebookListMenu); + + Notebook.contextmenuSearch = $("#notebookListForSearch li a").contextmenu(notebookListMenu2); + + // 添加笔记本 + $("#addNotebookPlus").click(function(e) { + e.stopPropagation(); + Notebook.addNotebook(); + }); + + // notebook setting + $("#notebookList").on("click", ".notebook-setting", function(e) { + e.preventDefault(); + e.stopPropagation(); + var $p = $(this).parent(); + Notebook.contextmenu.showMenu(e, $p); + }); + $("#notebookListForSearch").on("click", ".notebook-setting", function(e) { + e.preventDefault(); + e.stopPropagation(); + var $p = $(this).parent(); + Notebook.contextmenuSearch.showMenu(e, $p); + }); +}); \ No newline at end of file diff --git a/public/js/app/page-min.js b/public/js/app/page-min.js new file mode 100644 index 0000000..c9b445d --- /dev/null +++ b/public/js/app/page-min.js @@ -0,0 +1 @@ +function editorMode(){this.writingHash="#writing";this.normalHash="#normal";this.isWritingMode=location.hash==this.writingHash;this.toggleA=null}editorMode.prototype.toggleAText=function(isWriting){var self=this;setTimeout(function(){toggleA=$("#toggleEditorMode a");if(isWriting){toggleA.attr("href",self.normalHash).text(getMsg("normalMode"))}else{toggleA.attr("href",self.writingHash).text(getMsg("writingMode"))}},0)};editorMode.prototype.isWriting=function(hash){return hash==this.writingHash};editorMode.prototype.init=function(){this.changeMode(this.isWritingMode);var self=this;$("#toggleEditorMode").click(function(){saveBookmark();var $a=$(this).find("a");var isWriting=self.isWriting($a.attr("href"));self.changeMode(isWriting);restoreBookmark()})};editorMode.prototype.changeMode=function(isWritingMode){this.toggleAText(isWritingMode);if(isWritingMode){this.writtingMode()}else{this.normalMode()}$("#moreBtn i").removeClass("fa-angle-up").addClass("fa-angle-down")};editorMode.prototype.resizeEditor=function(){setTimeout(function(){resizeEditor()},10);setTimeout(function(){resizeEditor()},20);setTimeout(function(){resizeEditor()},500)};editorMode.prototype.normalMode=function(){var $c=$("#editorContent_ifr").contents();$c.contents().find("#writtingMode").remove();$c.contents().find('link[href$="editor-writting-mode.css"]').remove();$("#noteItemListWrap, #notesAndSort").show();$("#noteList").unbind("mouseenter").unbind("mouseleave");var theme=UserInfo.Theme||"default";theme+=".css";$("#themeLink").attr("href","/css/theme/"+theme);$("#mceToolbar").css("height","30px");this.resizeEditor();$("#noteList").width(UserInfo.NoteListWidth);$("#note").css("left",UserInfo.NoteListWidth)};editorMode.prototype.writtingMode=function(){$("#themeLink").attr("href","/css/theme/writting-overwrite.css");setTimeout(function(){var $c=$("#editorContent_ifr").contents();$c.contents().find("head").append('')},0);$("#noteItemListWrap, #notesAndSort").fadeOut();$("#noteList").hover(function(){$("#noteItemListWrap, #notesAndSort").fadeIn()},function(){$("#noteItemListWrap, #notesAndSort").fadeOut()});$("#mceToolbar").css("height","40px");this.resizeEditor();$("#noteList").width(250);$("#note").css("left",0)};editorMode.prototype.getWritingCss=function(){if(this.isWritingMode){return["css/editor/editor-writting-mode.css"]}return[]};var em=new editorMode;var Resize={lineMove:false,mdLineMove:false,target:null,leftNotebook:$("#leftNotebook"),notebookSplitter:$("#notebookSplitter"),noteList:$("#noteList"),noteAndEditor:$("#noteAndEditor"),noteSplitter:$("#noteSplitter"),note:$("#note"),body:$("body"),leftColumn:$("#left-column"),rightColumn:$("#right-column"),mdSplitter:$("#mdSplitter"),init:function(){var self=this;self.initEvent()},initEvent:function(){var self=this;$(".noteSplit").bind("mousedown",function(event){event.preventDefault();self.lineMove=true;$(this).css("background-color","#ccc");self.target=$(this).attr("id");$("#noteMask").css("z-index",99999)});self.mdSplitter.bind("mousedown",function(event){event.preventDefault();self.mdLineMove=true;$(this).css("background-color","#ccc")});self.body.bind("mousemove",function(event){if(self.lineMove){event.preventDefault();self.resize3Columns(event)}else if(self.mdLineMove){event.preventDefault();self.resizeMdColumns(event)}});self.body.bind("mouseup",function(event){self.stopResize();$("#noteMask").css("z-index",-1)})},stopResize:function(){var self=this;if(self.lineMove||self.mdLineMove){ajaxGet("/user/updateColumnWidth",{mdEditorWidth:UserInfo.MdEditorWidth,notebookWidth:UserInfo.NotebookWidth,noteListWidth:UserInfo.NoteListWidth},function(){})}self.lineMove=false;self.mdLineMove=false;$(".noteSplit").css("background","none");self.mdSplitter.css("background","none")},set3ColumnsWidth:function(notebookWidth,noteListWidth){var self=this;if(notebookWidth<150||noteListWidth<100){return}var noteWidth=self.body.width()-notebookWidth-noteListWidth;if(noteWidth<400){return}self.leftNotebook.width(notebookWidth);self.notebookSplitter.css("left",notebookWidth);self.noteAndEditor.css("left",notebookWidth);self.noteList.width(noteListWidth);self.noteSplitter.css("left",noteListWidth);self.note.css("left",noteListWidth);UserInfo.NotebookWidth=notebookWidth;UserInfo.NoteListWidth=noteListWidth},resize3Columns:function(event,isFromeIfr){var self=this;if(isFromeIfr){event.clientX+=self.body.width()-self.note.width()}var notebookWidth,noteListWidth;if(self.lineMove){if(self.target=="notebookSplitter"){notebookWidth=event.clientX;noteListWidth=self.noteList.width();self.set3ColumnsWidth(notebookWidth,noteListWidth)}else{notebookWidth=self.leftNotebook.width();noteListWidth=event.clientX-notebookWidth;self.set3ColumnsWidth(notebookWidth,noteListWidth)}resizeEditor()}},resizeMdColumns:function(event){var self=this;if(self.mdLineMove){var mdEditorWidth=event.clientX-self.leftNotebook.width()-self.noteList.width();self.setMdColumnWidth(mdEditorWidth)}},setMdColumnWidth:function(mdEditorWidth){var self=this;if(mdEditorWidth>100){UserInfo.MdEditorWidth=mdEditorWidth;self.leftColumn.width(mdEditorWidth);self.rightColumn.css("left",mdEditorWidth);self.mdSplitter.css("left",mdEditorWidth)}}};Mobile={noteO:$("#note"),bodyO:$("body"),setMenuO:$("#setMenu"),hashChange:function(){var self=Mobile;var hash=location.hash;if(hash.indexOf("noteId")!=-1){self.toEditor(false);var noteId=hash.substr(8);Note.changeNote(noteId,false,false)}else{self.toNormal(false)}},init:function(){var self=this;self.isMobile();$(window).on("hashchange",self.hashChange);self.hashChange()},isMobile:function(){var u=navigator.userAgent;LEA.isMobile=false;LEA.isMobile=/Mobile|Android|iPhone/i.test(u);if(!LEA.isMobile&&$(document).width()<=700){LEA.isMobile=true}return LEA.isMobile},changeNote:function(noteId){var self=this;if(!LEA.isMobile){return true}self.toEditor(true,noteId);return false},toEditor:function(changeHash,noteId){var self=this;self.bodyO.addClass("full-editor");self.noteO.addClass("editor-show");if(changeHash){if(!noteId){noteId=Note.curNoteId}location.hash="noteId="+noteId}},toNormal:function(changeHash){var self=this;self.bodyO.removeClass("full-editor");self.noteO.removeClass("editor-show");if(changeHash){location.hash="notebookAndNote"}},switchPage:function(){var self=this;if(!LEA.isMobile){return true}if(self.bodyO.hasClass("full-editor")){self.toNormal(true)}else{self.toEditor(true)}return false}};function initSlimScroll(){if(Mobile.isMobile()){return}$("#notebook").slimScroll({height:"100%"});$("#noteItemList").slimScroll({height:"100%"});$("#wmd-input").slimScroll({height:"100%"});$("#wmd-input").css("width","100%");$("#wmd-panel-preview").slimScroll({height:"100%"});$("#wmd-panel-preview").css("width","100%")}function initEditor(){var mceToobarEverHeight=0;$("#moreBtn").click(function(){saveBookmark();var height=$("#mceToolbar").height();if(height<$("#popularToolbar").height()){$("#mceToolbar").height($("#popularToolbar").height());$(this).find("i").removeClass("fa-angle-down").addClass("fa-angle-up");mceToobarEverHeight=height}else{$("#mceToolbar").height(mceToobarEverHeight);$(this).find("i").removeClass("fa-angle-up").addClass("fa-angle-down")}resizeEditor();restoreBookmark()});tinymce.init({setup:function(ed){ed.on("keydown",Note.saveNote);ed.on("keydown",function(e){var num=e.which?e.which:e.keyCode;if(num==9){if(!e.shiftKey){var node=ed.selection.getNode();if(node.nodeName=="PRE"){ed.execCommand("mceInsertRawHTML",false," ")}else{ed.execCommand("mceInsertRawHTML",false,"    ")}}else{}e.preventDefault();e.stopPropagation();return false}});ed.on("click",function(e){$("body").trigger("click")});ed.on("click",function(){log(ed.selection.getNode())})},convert_urls:true,relative_urls:false,remove_script_host:false,selector:"#editorContent",content_css:["css/bootstrap.css","css/editor/editor.css"].concat(em.getWritingCss()),skin:"custom",language:LEA.locale,plugins:["autolink link leaui_image lists charmap hr","paste","searchreplace leanote_nav leanote_code tabfocus","table directionality textcolor codemirror"],toolbar1:"formatselect | forecolor backcolor | bold italic underline strikethrough | leaui_image | leanote_code | bullist numlist | alignleft aligncenter alignright alignjustify",toolbar2:"outdent indent blockquote | link unlink | table | hr removeformat | subscript superscript |searchreplace | code | pastetext pasteCopyImage | fontselect fontsizeselect",menubar:false,toolbar_items_size:"small",statusbar:false,url_converter:false,font_formats:"Arial=arial,helvetica,sans-serif;"+"Arial Black=arial black,avant garde;"+"Times New Roman=times new roman,times;"+"Courier New=courier new,courier;"+"Tahoma=tahoma,arial,helvetica,sans-serif;"+"Verdana=verdana,geneva;"+"宋体=SimSun;"+"新宋体=NSimSun;"+"黑体=SimHei;"+"微软雅黑=Microsoft YaHei",block_formats:"Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p",codemirror:{indentOnInit:true,path:"CodeMirror",config:{lineNumbers:true},jsFiles:[]},paste_data_images:true});window.onbeforeunload=function(e){Note.curChangedSaveIt()};$("body").on("keydown",Note.saveNote)}var random=1;function scrollTo(self,tagName,text){var iframe=$("#editorContent_ifr").contents();var target=iframe.find(tagName+":contains("+text+")");random++;var navs=$('#leanoteNavContent [data-a="'+tagName+"-"+encodeURI(text)+'"]');var len=navs.size();for(var i=0;i=i+1){target=target.eq(i);var top=target.offset().top;var nowTop=iframe.scrollTop();var d=200;for(var i=0;i'); + }, 0); + + $("#noteItemListWrap, #notesAndSort").fadeOut(); + $("#noteList").hover(function() { + $("#noteItemListWrap, #notesAndSort").fadeIn(); + }, function() { + $("#noteItemListWrap, #notesAndSort").fadeOut(); + }); + + // 点击扩展会使html的height生成, 切换后会覆盖css文件的 + $("#mceToolbar").css("height", "40px"); + + //$("#pageInner").addClass("animated fadeInUp"); + + this.resizeEditor(); + + $("#noteList").width(250); + $("#note").css("left", 0); +} + +editorMode.prototype.getWritingCss = function() { + if(this.isWritingMode) { + return ["css/editor/editor-writting-mode.css"]; + } + return []; +} +var em = new editorMode(); + +//---------------- +// 拖拉改变变宽度 +var Resize = { + lineMove: false, + mdLineMove: false, + target: null, + + leftNotebook: $("#leftNotebook"), + notebookSplitter: $("#notebookSplitter"), + noteList: $("#noteList"), + noteAndEditor: $("#noteAndEditor"), + noteSplitter: $("#noteSplitter"), + note: $("#note"), + body: $("body"), + leftColumn: $("#left-column"), + rightColumn: $("#right-column"), + mdSplitter: $("#mdSplitter"), + + init: function() { + var self = this; + self.initEvent(); + }, + + initEvent: function() { + var self = this; + + // 鼠标点下 + $(".noteSplit").bind("mousedown", function(event) { + event.preventDefault(); // 防止选择文本 + self.lineMove = true; + $(this).css("background-color", "#ccc"); + self.target = $(this).attr("id"); + // 防止iframe捕获不了事件 + $("#noteMask").css("z-index", 99999); // .css("background-color", // "#ccc"); + }); + + // 鼠标点下 + self.mdSplitter.bind("mousedown", function(event) { + event.preventDefault(); // 防止选择文本 + self.mdLineMove = true; + $(this).css("background-color", "#ccc"); + }); + + // 鼠标移动时 + self.body.bind("mousemove", function(event) { + if(self.lineMove) { // 如果没有这个if会导致不能选择文本 + event.preventDefault(); + self.resize3Columns(event); + } else if(self.mdLineMove) { + event.preventDefault(); + self.resizeMdColumns(event); + } + }); + + // 鼠标放开, 结束 + self.body.bind("mouseup", function(event) { + self.stopResize(); + // 取消遮罩 + $("#noteMask").css("z-index", -1); + }); + }, + // 停止, 保存数据 + stopResize: function() { + var self = this; + if(self.lineMove || self.mdLineMove) { + // ajax保存 + ajaxGet("/user/updateColumnWidth", {mdEditorWidth: UserInfo.MdEditorWidth, notebookWidth: UserInfo.NotebookWidth, noteListWidth: UserInfo.NoteListWidth}, function() { + }); + } + self.lineMove = false; + self.mdLineMove = false; + $(".noteSplit").css("background", "none"); + self.mdSplitter.css("background", "none"); + }, + + // 最终调用该方法 + set3ColumnsWidth: function(notebookWidth, noteListWidth) { + var self = this; + if(notebookWidth < 150 || noteListWidth < 100) { + return; + } + var noteWidth = self.body.width() - notebookWidth - noteListWidth; + if(noteWidth < 400) { + return; + } + + self.leftNotebook.width(notebookWidth); + self.notebookSplitter.css("left", notebookWidth); + + self.noteAndEditor.css("left", notebookWidth); + self.noteList.width(noteListWidth); + self.noteSplitter.css("left", noteListWidth); + self.note.css("left", noteListWidth); + + UserInfo.NotebookWidth = notebookWidth; + UserInfo.NoteListWidth = noteListWidth; + }, + resize3Columns: function(event, isFromeIfr) { + var self = this; + if (isFromeIfr) { + event.clientX += self.body.width() - self.note.width(); + } + + var notebookWidth, noteListWidth; + if(self.lineMove) { + if (self.target == "notebookSplitter") { + notebookWidth = event.clientX; + noteListWidth = self.noteList.width(); + self.set3ColumnsWidth(notebookWidth, noteListWidth); + } else { + notebookWidth = self.leftNotebook.width(); + noteListWidth = event.clientX - notebookWidth; + self.set3ColumnsWidth(notebookWidth, noteListWidth); + } + + resizeEditor(); + } + }, + + // mdeditor + resizeMdColumns: function(event) { + var self = this; + if (self.mdLineMove) { + var mdEditorWidth = event.clientX - self.leftNotebook.width() - self.noteList.width(); + self.setMdColumnWidth(mdEditorWidth); + } + }, + // 设置宽度 + setMdColumnWidth: function(mdEditorWidth) { + var self = this; + if(mdEditorWidth > 100) { + UserInfo.MdEditorWidth = mdEditorWidth; + self.leftColumn.width(mdEditorWidth); + self.rightColumn.css("left", mdEditorWidth); + self.mdSplitter.css("left", mdEditorWidth); + } + } +} + +//-------------------------- +// 手机端访问之 +Mobile = { + // 点击之笔记 + // 切换到编辑器模式 + noteO: $("#note"), + bodyO: $("body"), + setMenuO: $("#setMenu"), + hashChange: function() { + var self = Mobile; + var hash = location.hash; + // noteId + if(hash.indexOf("noteId") != -1) { + self.toEditor(false); + var noteId = hash.substr(8); + Note.changeNote(noteId, false, false); + } else { + // 笔记本和笔记列表 + self.toNormal(false); + } + }, + init: function() { + var self = this; + self.isMobile(); + $(window).on("hashchange", self.hashChange); + self.hashChange(); + /* + $("#noteItemList").on("tap", ".item", function(event) { + $(this).click(); + }); + $(document).on("swipeleft",function(e){ + e.stopPropagation(); + e.preventDefault(); + self.toEditor(); + }); + $(document).on("swiperight",function(e){ + e.stopPropagation(); + e.preventDefault(); + self.toNormal(); + }); + */ + }, + isMobile: function() { + var u = navigator.userAgent; + LEA.isMobile = false; + LEA.isMobile = /Mobile|Android|iPhone/i.test(u); + if(!LEA.isMobile && $(document).width() <= 700){ + LEA.isMobile = true + } + return LEA.isMobile; + }, + changeNote: function(noteId) { + var self = this; + if(!LEA.isMobile) {return true;} + self.toEditor(true, noteId); + return false; + }, + + toEditor: function(changeHash, noteId) { + var self = this; + self.bodyO.addClass("full-editor"); + self.noteO.addClass("editor-show"); + if(changeHash) { + if(!noteId) { + noteId = Note.curNoteId; + } + location.hash = "noteId=" + noteId; + } + }, + toNormal: function(changeHash) { + var self = this; + self.bodyO.removeClass("full-editor"); + self.noteO.removeClass("editor-show"); + + if(changeHash) { + location.hash = "notebookAndNote"; + } + }, + switchPage: function() { + var self = this; + if(!LEA.isMobile) {return true;} + if(self.bodyO.hasClass("full-editor")) { + self.toNormal(true); + } else { + self.toEditor(true); + } + return false; + } +} + + +function initSlimScroll() { + if(Mobile.isMobile()) { + return; + } + $("#notebook").slimScroll({ + height: "100%", // $("#leftNotebook").height()+"px" + }); + $("#noteItemList").slimScroll({ + height: "100%", // ($("#leftNotebook").height()-42)+"px" + }); + $("#wmd-input").slimScroll({ + height: "100%", // $("#wmd-input").height()+"px" + }); + $("#wmd-input").css("width", "100%"); + + $("#wmd-panel-preview").slimScroll({ + height: "100%", // $("#wmd-panel-preview").height()+"px" + }); + + $("#wmd-panel-preview").css("width", "100%"); +} + +//----------- +// 初始化编辑器 +function initEditor() { + // editor + // toolbar 下拉扩展, 也要resizeEditor + var mceToobarEverHeight = 0; + $("#moreBtn").click(function() { + saveBookmark(); + + var height = $("#mceToolbar").height(); + + // 现在是折叠的 + if (height < $("#popularToolbar").height()) { + $("#mceToolbar").height($("#popularToolbar").height()); + $(this).find("i").removeClass("fa-angle-down").addClass("fa-angle-up"); + mceToobarEverHeight = height; + } else { + $("#mceToolbar").height(mceToobarEverHeight); + $(this).find("i").removeClass("fa-angle-up").addClass("fa-angle-down"); + } + + resizeEditor(); + + restoreBookmark(); + }); + + // 初始化编辑器 + tinymce.init({ + setup: function(ed) { + ed.on('keydown', Note.saveNote); + // indent outdent + ed.on('keydown', function(e) { + var num = e.which ? e.which : e.keyCode; + if (num == 9) { // tab pressed + + if(!e.shiftKey) { +// ed.execCommand('Indent'); + // TODO 如果当前在li, ul, ol下不执行!! + // 如果在pre下就加tab + var node = ed.selection.getNode(); + if(node.nodeName == "PRE") { + ed.execCommand('mceInsertRawHTML', false, '\x09'); // inserts tab + } else { + ed.execCommand('mceInsertRawHTML', false, "    "); // inserts 空格 + } + } else { + // delete 4 个空格 +// ed.execCommand('Outdent'); + } + + e.preventDefault(); + e.stopPropagation(); + return false; + } + }); + + // 为了把下拉菜单关闭 + ed.on("click", function(e) { + $("body").trigger("click"); + }); + + // 鼠标移上时 + ed.on("click", function() { + log(ed.selection.getNode()) + }); + }, + + // fix TinyMCE Removes site base url + // http://stackoverflow.com/questions/3360084/tinymce-removes-site-base-urls + convert_urls:true, + relative_urls:false, + remove_script_host:false, + + selector : "#editorContent", + // height: 100,//这个应该是文档的高度, 而其上层的高度是$("#content").height(), + // parentHeight: $("#content").height(), + content_css : ["css/bootstrap.css", "css/editor/editor.css"].concat(em.getWritingCss()), + skin : "custom", + language: LEA.locale, // 语言 + plugins : [ + "autolink link leaui_image lists charmap hr", "paste", + "searchreplace leanote_nav leanote_code tabfocus", + "table directionality textcolor codemirror" ], // nonbreaking + + toolbar1 : "formatselect | forecolor backcolor | bold italic underline strikethrough | leaui_image | leanote_code | bullist numlist | alignleft aligncenter alignright alignjustify", + toolbar2 : "outdent indent blockquote | link unlink | table | hr removeformat | subscript superscript |searchreplace | code | pastetext pasteCopyImage | fontselect fontsizeselect", + + // 使用tab键: http://www.tinymce.com/wiki.php/Plugin3x:nonbreaking + // http://stackoverflow.com/questions/13543220/tiny-mce-how-to-allow-people-to-indent + // nonbreaking_force_tab : true, + + menubar : false, + toolbar_items_size : 'small', + statusbar : false, + url_converter: false, + font_formats : "Arial=arial,helvetica,sans-serif;" + + "Arial Black=arial black,avant garde;" + + "Times New Roman=times new roman,times;" + + "Courier New=courier new,courier;" + + "Tahoma=tahoma,arial,helvetica,sans-serif;" + + "Verdana=verdana,geneva;" + "宋体=SimSun;" + + "新宋体=NSimSun;" + "黑体=SimHei;" + + "微软雅黑=Microsoft YaHei", + block_formats : "Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p", + codemirror: { + indentOnInit: true, // Whether or not to indent code on init. + path: 'CodeMirror', // Path to CodeMirror distribution + config: { // CodeMirror config object + //mode: 'application/x-httpd-php', + lineNumbers: true + }, + jsFiles: [ // Additional JS files to load + // 'mode/clike/clike.js', + //'mode/php/php.js' + ] + }, + // This option specifies whether data:url images (inline images) should be removed or not from the pasted contents. + // Setting this to "true" will allow the pasted images, and setting this to "false" will disallow pasted images. + // For example, Firefox enables you to paste images directly into any contentEditable field. This is normally not something people want, so this option is "false" by default. + paste_data_images: true + }); + + // 刷新时保存 参考autosave插件 + window.onbeforeunload = function(e) { + Note.curChangedSaveIt(); + } + + // 全局ctrl + s + $("body").on('keydown', Note.saveNote); +} + +//----------------------- +// 导航 +var random = 1; +function scrollTo(self, tagName, text) { + var iframe = $("#editorContent_ifr").contents(); + var target = iframe.find(tagName + ":contains(" + text + ")"); + random++; + + // 找到是第几个 + // 在nav是第几个 + var navs = $('#leanoteNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]'); +// alert('#leanoteNavContent [data-a="' + tagName + '-' + encodeURI(text) + '"]') + var len = navs.size(); + for(var i = 0; i < len; ++i) { + if(navs[i] == self) { + break; + } + } + + if (target.size() >= i+1) { + target = target.eq(i); + // 之前插入, 防止多行定位不准 + var top = target.offset().top; + var nowTop = iframe.scrollTop(); + + // iframe.scrollTop(top); + // $(iframe).animate({scrollTop: top}, 300); // 有问题 + + var d = 200; // 时间间隔 + for(var i = 0; i < d; i++) { + setTimeout( + (function(top) { + return function() { + iframe.scrollTop(top); + } + })(nowTop + 1.0*i*(top-nowTop)/d), i); + } + // 最后必然执行 + setTimeout(function() { + iframe.scrollTop(top); + }, d+5); + return; + } +} + +//-------------- +// 调用之 +$(function() { + // 窗口缩放时 + $(window).resize(function() { + Mobile.isMobile(); + resizeEditor(); + }); + + // 初始化编辑器 + initEditor(); + + // 左侧, folder 展开与关闭 + $(".folderHeader").click(function() { + var body = $(this).next(); + var p = $(this).parent(); + if (!body.is(":hidden")) { + $(".folderNote").removeClass("opened").addClass("closed"); +// body.hide(); + p.removeClass("opened").addClass("closed"); + $(this).find(".fa-angle-down").removeClass("fa-angle-down").addClass("fa-angle-right"); + } else { + $(".folderNote").removeClass("opened").addClass("closed"); +// body.show(); + p.removeClass("closed").addClass("opened"); + $(this).find(".fa-angle-right").removeClass("fa-angle-right").addClass("fa-angle-down"); + } + }); + + // 导航隐藏与显示 + $("#leanoteNav h1").on("click", function(e) { + if (!$("#leanoteNav").hasClass("unfolder")) { + $("#leanoteNav").addClass("unfolder"); + } else { + $("#leanoteNav").removeClass("unfolder"); + } + }); + + // 打开设置 + function openSetInfoDialog(whichTab) { + showDialogRemote("/user/account", {tab: whichTab}); + } + // 帐号设置 + $("#setInfo").click(function() { + openSetInfoDialog(0); + }); + // 邮箱验证 + $("#wrongEmail").click(function() { + openSetInfoDialog(1); + }); + + $("#setAvatarMenu").click(function() { + showDialog2("#avatarDialog", {title: "头像设置", postShow: function() { + }}); + }); + $("#setTheme").click(function() { + showDialog2("#setThemeDialog", {title: "主题设置", postShow: function() { + if (!UserInfo.Theme) { + UserInfo.Theme = "default"; + } + $("#themeForm input[value='" + UserInfo.Theme + "']").attr("checked", true); + }}); + }); + + //--------- + // 主题 + $("#themeForm").on("click", "input", function(e) { + var val = $(this).val(); + $("#themeLink").attr("href", "/css/theme/" + val + ".css"); + + ajaxPost("/user/updateTheme", {theme: val}, function(re) { + if(reIsOk(re)) { + UserInfo.Theme = val + } + }); + }); + + //------------- + // 邮箱验证 + if(!UserInfo.Verified) { +// $("#leanoteMsg").hide(); +// $("#verifyMsg").show(); + } + + // 禁止双击选中文字 + $("#notebook, #newMyNote, #myProfile, #topNav, #notesAndSort", "#leanoteNavTrigger").bind("selectstart", function(e) { + e.preventDefault(); + return false; + }); + + // 左侧隐藏或展示 + function updateLeftIsMin(is) { + ajaxGet("/user/updateLeftIsMin", {leftIsMin: is}) + } + function minLeft(save) { + $("#leftNotebook").width(30); + $("#notebook").hide(); + // 左侧 + $("#noteAndEditor").css("left", 30) + $("#notebookSplitter").hide(); + +// $("#leftSwitcher").removeClass("fa-angle-left").addClass("fa-angle-right"); + + // logo + $("#logo").hide(); + $("#leftSwitcher").hide(); + $("#leftSwitcher2").show(); + $("#leftNotebook .slimScrollDiv").hide(); + + if(save) { + updateLeftIsMin(true); + } + } + + function maxLeft(save) { + $("#noteAndEditor").css("left", UserInfo.NotebookWidth); + $("#leftNotebook").width(UserInfo.NotebookWidth); + $("#notebook").show(); + $("#notebookSplitter").show(); + +// $("#leftSwitcher").removeClass("fa-angle-right").addClass("fa-angle-left"); + + $("#leftSwitcher2").hide(); + $("#logo").show(); + $("#leftSwitcher").show(); + $("#leftNotebook .slimScrollDiv").show(); + + if(save) { + updateLeftIsMin(false); + } + } + + $("#leftSwitcher2").click(function() { + maxLeft(true); + }); + $("#leftSwitcher").click(function() { + if(Mobile.switchPage()) { + minLeft(true); + } + }); + + // 得到最大dropdown高度 + // 废弃 + function getMaxDropdownHeight(obj) { + var offset = $(obj).offset(); + var maxHeight = $(document).height()-offset.top; + maxHeight -= 70; + if(maxHeight < 0) { + maxHeight = 0; + } + + var preHeight = $(obj).find("ul").height(); + return preHeight < maxHeight ? preHeight : maxHeight; + } + + // mini版 + // 点击展开 + $("#notebookMin div.minContainer").click(function() { + var target = $(this).attr("target"); + maxLeft(true); + if(target == "#notebookList") { + if($("#myNotebooks").hasClass("closed")) { + $("#myNotebooks .folderHeader").trigger("click"); + } + } else if(target == "#tagNav") { + if($("#myTag").hasClass("closed")) { + $("#myTag .folderHeader").trigger("click"); + } + } else { + if($("#myShareNotebooks").hasClass("closed")) { + $("#myShareNotebooks .folderHeader").trigger("click"); + } + } + }); + + //------------------------ + // 界面设置, 左侧是否是隐藏的 + UserInfo.NotebookWidth = UserInfo.NotebookWidth || $("#notebook").width(); + UserInfo.NoteListWidth = UserInfo.NoteListWidth || $("#noteList").width(); + + Resize.init(); + Resize.set3ColumnsWidth(UserInfo.NotebookWidth, UserInfo.NoteListWidth); + Resize.setMdColumnWidth(UserInfo.MdEditorWidth); + + if (UserInfo.LeftIsMin) { + minLeft(false); + } + + // end + // 开始时显示loading...... + // 隐藏mask + $("#mainMask").html(""); + $("#mainMask").hide(100); + + // 4/25 防止dropdown太高 + // dropdown + $('.dropdown').on('shown.bs.dropdown', function () { + var $ul = $(this).find("ul"); + // $ul.css("max-height", getMaxDropdownHeight(this)); + }); + + //-------- + // 编辑器帮助 + $("#tipsBtn").click(function() { + showDialog2("#tipsDialog"); + }); + + //-------- + // 建议 + $("#yourSuggestions").click(function() { + showDialog2("#suggestionsDialog"); + }); + $("#suggestionBtn").click(function(e) { + e.preventDefault(); + var suggestion = $.trim($("#suggestionTextarea").val()); + if(!suggestion) { + $("#suggestionMsg").html("请输入您的建议, 谢谢!").show().addClass("alert-warning").removeClass("alert-success"); + $("#suggestionTextarea").focus(); + return; + } + $("#suggestionBtn").html("正在处理...").addClass("disabled"); + $("#suggestionMsg").html("正在处理..."); + $.post("/suggestion", {suggestion: suggestion}, function(ret) { + $("#suggestionBtn").html("提交").removeClass("disabled"); + if(ret.Ok) { + $("#suggestionMsg").html("谢谢反馈, 我们会第一时间处理, 祝您愉快!").addClass("alert-success").removeClass("alert-warning").show(); + } else { + $("#suggestionMsg").html("出错了").show().addClass("alert-warning").removeClass("alert-success"); + } + }); + }); + + // 编辑器模式 + em.init(); + + // 手机端? + Mobile.init(); +}); + diff --git a/public/js/app/share-min.js b/public/js/app/share-min.js new file mode 100644 index 0000000..f959a81 --- /dev/null +++ b/public/js/app/share-min.js @@ -0,0 +1 @@ +Share.defaultNotebookId="share0";Share.defaultNotebookTitle=getMsg("defaulthhare");Share.sharedUserInfos={};Share.userNavs={};Share.notebookCache={};Share.cache={};Share.dialogIsNote=true;Share.setCache=function(note){if(!note||!note.NoteId){return}Share.cache[note.NoteId]=note};Share.getNotebooksForNew=function(userId,notebooks){var self=this;var navForNewNote="";var len=notebooks.length;for(var i=0;i
        ?
        M
        ',classes,userId,notebook.NotebookId,notebook.Title);if(subs){eachForNew+=""}eachForNew+=""}navForNewNote+=eachForNew}return navForNewNote};Share.trees={};Share.renderShareNotebooks=function(sharedUserInfos,shareNotebooks){var self=Share;if(isEmpty(sharedUserInfos)){return}if(!shareNotebooks||typeof shareNotebooks!="object"||shareNotebooks.length<0){shareNotebooks={}}var $shareNotebooks=$("#shareNotebooks");for(var i in sharedUserInfos){var userInfo=sharedUserInfos[i];var userNotebooksPre=shareNotebooks[userInfo.UserId]||[];userNotebooks=[{NotebookId:self.defaultNotebookId,Title:Share.defaultNotebookTitle}].concat(userNotebooksPre);self.notebookCache[self.defaultNotebookId]=userNotebooks[0];var username=userInfo.Username||userInfo.Email;userInfo.Username=username;Share.sharedUserInfos[userInfo.UserId]=userInfo;var userId=userInfo.UserId;var header=tt('
      • ?
        ',userInfo.UserId,username);var friendId="friendContainer_"+userId;var body='
          ';$shareNotebooks.append(header+body+"
        • ");self.trees[userId]=$.fn.zTree.init($("#"+friendId),Notebook.getTreeSetting(true,true),userNotebooks);self.userNavs[userId]={forNew:self.getNotebooksForNew(userId,userNotebooksPre)};log(self.userNavs)}$(".friend-notebooks").hover(function(){if(!$(this).hasClass("showIcon")){$(this).addClass("showIcon")}},function(){$(this).removeClass("showIcon")});$(".friend-header i").click(function(){var $this=$(this);var $tree=$(this).parent().next();if($tree.is(":hidden")){$tree.slideDown("fast");$this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-down")}else{$tree.slideUp("fast");$this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-right")}});var shareNotebookMenu={width:180,items:[{text:getMsg("deleteSharedNotebook"),icon:"",faIcon:"fa-trash-o",action:Share.deleteShareNotebook}],onShow:applyrule,onContextMenu:beforeContextMenu,parent:"#shareNotebooks",children:".notebook-item"};function applyrule(menu){return}function beforeContextMenu(){var notebookId=$(this).attr("notebookId");return!Share.isDefaultNotebookId(notebookId)}var menuNotebooks=$("#shareNotebooks").contextmenu(shareNotebookMenu);var shareUserMenu={width:180,items:[{text:getMsg("deleteAllShared"),icon:"",faIcon:"fa-trash-o",action:Share.deleteUserShareNoteAndNotebook}],parent:"#shareNotebooks",children:".friend-header"};var menuUser=$("#shareNotebooks").contextmenu(shareUserMenu);$(".friend-header").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();menuUser.showMenu(e,$p)});$("#shareNotebooks .notebook-item").on("click",".notebook-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();menuNotebooks.showMenu(e,$p)})};Share.isDefaultNotebookId=function(notebookId){return Share.defaultNotebookId==notebookId};Share.toggleToSharedNav=function(userId,notebookId){var self=this;$("#curNotebookForListNote").html(Share.notebookCache[notebookId].Title+"("+Share.sharedUserInfos[userId].Username+")");var forNew=Share.userNavs[userId].forNew;if(forNew){$("#notebookNavForNewSharedNote").html(forNew);var curNotebookId="";var curNotebookTitle="";if(Share.notebookCache[notebookId].Perm){curNotebookId=notebookId;curNotebookTitle=Share.notebookCache[notebookId].Title}else{var $f=$("#notebookNavForNewSharedNote li").eq(0);curNotebookId=$f.attr("notebookId");curNotebookTitle=$f.find(".new-note-left").text()}$("#curNotebookForNewSharedNote").html(curNotebookTitle+"("+Share.sharedUserInfos[userId].Username+")");$("#curNotebookForNewSharedNote").attr("notebookId",curNotebookId);$("#curNotebookForNewSharedNote").attr("userId",userId);$("#newSharedNote").show();$("#newMyNote").hide()}else{$("#newMyNote").show();$("#newSharedNote").hide()}$("#tagSearch").hide()};Share.changeNotebook=function(userId,notebookId){Notebook.selectNotebook($(tt('#friendContainer_? a[notebookId="?"]',userId,notebookId)));Share.toggleToSharedNav(userId,notebookId);Note.curChangedSaveIt();Note.clearAll();var url="/share/ListShareNotes/";var param={userId:userId};if(!Share.isDefaultNotebookId(notebookId)){param.notebookId=notebookId}ajaxGet(url,param,function(ret){if(param.notebookId){}Note.renderNotes(ret,false,true);if(!isEmpty(ret)){Note.changeNote(ret[0].NoteId,true)}else{}})};Share.hasUpdatePerm=function(notebookId){var note=Share.cache[notebookId];if(!note||!note.Perm){return false}return true};Share.deleteShareNotebook=function(target){if(confirm("Are you sure to delete it?")){var notebookId=$(target).attr("notebookId");var fromUserId=$(target).closest(".friend-notebooks").attr("fromUserId");ajaxGet("/share/DeleteShareNotebookBySharedUser",{notebookId:notebookId,fromUserId:fromUserId},function(ret){if(ret){$(target).parent().remove()}})}};Share.deleteShareNote=function(target){var noteId=$(target).attr("noteId");var fromUserId=$(target).attr("fromUserId");ajaxGet("/share/DeleteShareNoteBySharedUser",{noteId:noteId,fromUserId:fromUserId},function(ret){if(ret){$(target).remove()}})};Share.deleteUserShareNoteAndNotebook=function(target){if(confirm("Are you sure to delete all shared notebooks and notes?")){var fromUserId=$(target).attr("fromUserId");ajaxGet("/share/deleteUserShareNoteAndNotebook",{fromUserId:fromUserId},function(ret){if(ret){$(target).parent().remove()}})}};Share.changeNotebookForNewNote=function(notebookId){Notebook.selectNotebook($(tt('#shareNotebooks [notebookId="?"]',notebookId)));var userId=Share.notebookCache[notebookId].UserId;Share.toggleToSharedNav(userId,notebookId);var url="/share/ListShareNotes/";var param={userId:userId,notebookId:notebookId};ajaxGet(url,param,function(ret){Note.renderNotes(ret,true,true)})};Share.deleteSharedNote=function(target,contextmenuItem){Note.deleteNote(target,contextmenuItem,true)};Share.copySharedNote=function(target,contextmenuItem){Note.copyNote(target,contextmenuItem,true)};Share.contextmenu=null;Share.initContextmenu=function(notebooksCopy){if(Share.contextmenu){Share.contextmenu.destroy()}var noteListMenu={width:180,items:[{text:getMsg("copyToMyNotebook"),alias:"copy",faIcon:"fa-copy",type:"group",width:180,items:notebooksCopy},{type:"splitLine"},{text:getMsg("delete"),alias:"delete",icon:"",faIcon:"fa-trash-o",action:Share.deleteSharedNote}],onShow:applyrule,parent:"#noteItemList",children:".item-shared"};function applyrule(menu){var noteId=$(this).attr("noteId");var note=Share.cache[noteId];if(!note){return}var items=[];if(!(note.Perm&¬e.CreatedUserId==UserInfo.UserId)){items.push("delete")}menu.applyrule({name:"target...",disable:true,items:items})}Share.contextmenu=$("#noteItemList .item-shared").contextmenu(noteListMenu)};$(function(){$("#noteItemList").on("click",".item-shared .item-setting",function(e){e.preventDefault();e.stopPropagation();var $p=$(this).parent();Share.contextmenu.showMenu(e,$p)});$("#newSharedNoteBtn").click(function(){var notebookId=$("#curNotebookForNewSharedNote").attr("notebookId");var userId=$("#curNotebookForNewSharedNote").attr("userId");Note.newNote(notebookId,true,userId)});$("#newShareNoteMarkdownBtn").click(function(){var notebookId=$("#curNotebookForNewSharedNote").attr("notebookId");var userId=$("#curNotebookForNewSharedNote").attr("userId");Note.newNote(notebookId,true,userId,true)});$("#notebookNavForNewSharedNote").on("click","li div",function(){var notebookId=$(this).parent().attr("notebookId");var userId=$(this).parent().attr("userId");if($(this).text()=="M"){Note.newNote(notebookId,true,userId,true)}else{Note.newNote(notebookId,true,userId)}});$("#leanoteDialogRemote").on("click",".change-perm",function(){var self=this;var perm=$(this).attr("perm");var noteOrNotebookId=$(this).attr("noteOrNotebookId");var toUserId=$(this).attr("toUserId");var toHtml=getMsg("writable");var toPerm="1";if(perm=="1"){toHtml=getMsg("readOnly");toPerm="0"}var url="/share/UpdateShareNotebookPerm";var param={perm:toPerm,toUserId:toUserId};if(Share.dialogIsNote){url="/share/UpdateShareNotePerm";param.noteId=noteOrNotebookId}else{param.notebookId=noteOrNotebookId}ajaxGet(url,param,function(ret){if(ret){$(self).html(toHtml);$(self).attr("perm",toPerm)}})});$("#leanoteDialogRemote").on("click",".delete-share",function(){var self=this;var noteOrNotebookId=$(this).attr("noteOrNotebookId");var toUserId=$(this).attr("toUserId");var url="/share/DeleteShareNotebook";var param={toUserId:toUserId};if(Share.dialogIsNote){url="/share/DeleteShareNote";param.noteId=noteOrNotebookId}else{param.notebookId=noteOrNotebookId}ajaxGet(url,param,function(ret){if(ret){$(self).parent().parent().remove()}})});var seq=1;$("#leanoteDialogRemote").on("click","#addShareNotebookBtn",function(){seq++;var tpl='#';tpl+='";tpl+=' ";tpl+='";tpl+=' ";tpl+="";$("#shareNotebookTable tbody").prepend(tpl);$("#tr"+seq+" #friendsEmail").focus()});$("#registerEmailBtn").click(function(){var content=$("#emailContent").val();var toEmail=$("#toEmail").val();if(!content){showAlert("#registerEmailMsg",getMsg("emailBodyRequired"),"danger");return}post("/user/sendRegisterEmail",{content:content,toEmail:toEmail},function(ret){showAlert("#registerEmailMsg",getMsg("sendSuccess"),"success");hideDialog2("#sendRegisterEmailDialog",1e3)},this)})});function addShareNoteOrNotebook(trSeq){var trId="#tr"+trSeq;var id=Share.dialogNoteOrNotebookId;var emails=isEmailFromInput(trId+" #friendsEmail","#shareMsg",getMsg("inputFriendEmail"));if(!emails){return}var shareNotePerm=$(trId+' input[name="perm'+trSeq+'"]:checked').val()||0;var perm=shareNotePerm;var url="share/addShareNote";var data={noteId:id,emails:[emails],perm:shareNotePerm};if(!Share.dialogIsNote){url="share/addShareNotebook";data={notebookId:id,emails:[emails],perm:shareNotePerm}}hideAlert("#shareMsg");post(url,data,function(ret){var ret=ret[emails];if(ret){if(ret.Ok){var tpl=tt("?","#");tpl+=tt("?",emails);tpl+=tt('?',id,perm,ret.Id,!perm||perm=="0"?getMsg("readOnly"):getMsg("writable"));tpl+=tt(''+getMsg("delete")+"",id,ret.Id);$(trId).html(tpl)}else{var shareUrl=UrlPrefix+"/register?from="+UserInfo.Username;showAlert("#shareMsg",getMsg("friendNotExits",[getMsg("app"),shareUrl])+' '+getMsg("clickToCopy")+'
          '+getMsg("sendInviteEmailToYourFriend")+', "+getMsg("send"),"warning");$("#copyDiv").text(shareUrl);initCopy("shareCopy",function(args){if(args.text){showMsg2("#copyStatus",getMsg("copySuccess"),1e3)}else{showMsg2("#copyStatus",getMsg("copyFailed"),1e3)}})}}},trId+" .btn-success")}function sendRegisterEmail(email){showDialog2("#sendRegisterEmailDialog",{postShow:function(){$("#emailContent").val(getMsg("inviteEmailBody",[UserInfo.Username,getMsg("app")]));setTimeout(function(){$("#emailContent").focus()},500);$("#toEmail").val(email)}})}function deleteShareNoteOrNotebook(trSeq){$("#tr"+trSeq).remove()} \ No newline at end of file diff --git a/public/js/app/share.js b/public/js/app/share.js new file mode 100644 index 0000000..c0aaf3f --- /dev/null +++ b/public/js/app/share.js @@ -0,0 +1,583 @@ +//------------------------------------ +// 共享, notbeook, note +//------------------------------------ + +// 默认共享notebook id +Share.defaultNotebookId = "share0"; +Share.defaultNotebookTitle = getMsg("defaulthhare"); +Share.sharedUserInfos = {}; // userId => {} + +// 在render时就创建, 以后复用之 +Share.userNavs = {}; // userId => {"forList":html, "forNew":html} + +// 缓存都不要, 统一放在Note.cache中 +// 放在这里, 只是为了debug, 分离 +Share.notebookCache = {}; // notebooks 的cache +Share.cache = {}; // note的cache + +// 分享的弹出框是note的 +Share.dialogIsNote = true; + +// 设置缓存 note +Share.setCache = function(note) { + if(!note || !note.NoteId) { + return; + } + Share.cache[note.NoteId] = note; +} + +/** + * 我的共享notebooks +
          + + */ +// TODO 层级 +// shareNotebooks = {userId => {}} +Share.getNotebooksForNew = function(userId, notebooks) { + var self = this; + var navForNewNote = ""; + + var len = notebooks.length; + for(var i = 0; i < len; ++i) { + var notebook = notebooks[i]; + notebook.IsShared = true; + notebook.UserId = userId; + self.notebookCache[notebook.NotebookId] = notebook; + // notebook的cache也缓存一份, 为了显示标题 + Notebook.cache[notebook.NotebookId] = notebook; + + var classes = ""; + var subs = false; + if(!isEmpty(notebook.Subs)) { + log(11); + log(notebook.Subs); + var subs = self.getNotebooksForNew(userId, notebook.Subs); + if(subs) { + classes = "dropdown-submenu"; + } + } + + var eachForNew = ""; + if(notebook.Perm) { + var eachForNew = tt(''; + } + + navForNewNote += eachForNew; + } + return navForNewNote; +} +Share.trees = {}; +Share.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) { + var self = Share; + if(isEmpty(sharedUserInfos)) { + return; + } + + if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) { + shareNotebooks = {}; + } + + var $shareNotebooks = $("#shareNotebooks"); + + // render每一个用户的share给我的笔记本, 之前先建一个默认共享 + for(var i in sharedUserInfos) { + var userInfo = sharedUserInfos[i]; + var userNotebooksPre = shareNotebooks[userInfo.UserId] || []; + + userNotebooks = [{NotebookId: self.defaultNotebookId, Title: Share.defaultNotebookTitle}].concat(userNotebooksPre) + + self.notebookCache[self.defaultNotebookId] = userNotebooks[0]; + + var username = userInfo.Username || userInfo.Email; + userInfo.Username = username; + Share.sharedUserInfos[userInfo.UserId] = userInfo; + var userId = userInfo.UserId; + var header = tt('
        • ?
          ', userInfo.UserId, username); + var friendId = "friendContainer_" + userId; + var body = '
            '; + $shareNotebooks.append(header + body + "
          • ") + + self.trees[userId] = $.fn.zTree.init($("#" + friendId), Notebook.getTreeSetting(true, true), userNotebooks); + + self.userNavs[userId] = {"forNew": self.getNotebooksForNew(userId, userNotebooksPre)}; + log(self.userNavs); + } + + $(".friend-notebooks").hover(function () { + if (!$(this).hasClass("showIcon")) { + $(this).addClass("showIcon"); + } + }, function() { + $(this).removeClass("showIcon"); + }); + + $(".friend-header i").click(function() { + var $this = $(this); + var $tree = $(this).parent().next(); + if($tree.is(":hidden")) { + $tree.slideDown("fast"); + $this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-down"); + } else { + $tree.slideUp("fast"); + $this.removeClass("fa-angle-right fa-angle-down").addClass("fa-angle-right"); + } + }); + + //----------------------------- + // contextmenu shareNotebooks + // 删除共享笔记本 + var shareNotebookMenu = { + width: 180, + items: [ + { text: getMsg("deleteSharedNotebook"), icon: "", faIcon: "fa-trash-o", action: Share.deleteShareNotebook } + ], + onShow: applyrule, + onContextMenu: beforeContextMenu, + + parent: "#shareNotebooks", + children: ".notebook-item", + }; + function applyrule(menu) { + return; + } + // 默认共享不能删除 + function beforeContextMenu() { + var notebookId = $(this).attr("notebookId"); + return !Share.isDefaultNotebookId(notebookId); + } + + var menuNotebooks = $("#shareNotebooks").contextmenu(shareNotebookMenu); + + //--------------------------- + // contextmenu shareNotebooks + // 删除某用户所有的 + var shareUserMenu = { + width: 180, + items: [ + { text: getMsg("deleteAllShared"), icon: "", faIcon: "fa-trash-o", action: Share.deleteUserShareNoteAndNotebook } + ], + parent: "#shareNotebooks", + children: ".friend-header", + }; + + var menuUser = $("#shareNotebooks").contextmenu(shareUserMenu); + + $(".friend-header").on("click", ".notebook-setting", function(e) { + e.preventDefault(); + e.stopPropagation(); + var $p = $(this).parent(); + menuUser.showMenu(e, $p); + }); + $("#shareNotebooks .notebook-item").on("click", ".notebook-setting", function(e) { + e.preventDefault(); + e.stopPropagation(); + var $p = $(this).parent(); + menuNotebooks.showMenu(e, $p); + }); +}; + +Share.isDefaultNotebookId = function(notebookId) { + return Share.defaultNotebookId == notebookId; +} + +// 转成共享的nav +// for list和for new +// 如果forNew没有, 那么还是保持我的nav +Share.toggleToSharedNav = function(userId, notebookId) { + var self = this; + // for list + $("#curNotebookForListNote").html(Share.notebookCache[notebookId].Title + '(' + Share.sharedUserInfos[userId].Username + ")"); + + // for new + // 如果该用户下有新建的note, 那么列出, 如果没有, 则列出我的笔记 + var forNew = Share.userNavs[userId].forNew; + if(forNew) { + $("#notebookNavForNewSharedNote").html(forNew); + // 新建之, 可能当前选择的没有权限新建. 此时需要得到第一个 + var curNotebookId = ""; + var curNotebookTitle = ""; + if(Share.notebookCache[notebookId].Perm) { + curNotebookId = notebookId; + curNotebookTitle = Share.notebookCache[notebookId].Title; + } else { + // 得到第一个 + var $f = $("#notebookNavForNewSharedNote li").eq(0); + curNotebookId = $f.attr("notebookId"); + curNotebookTitle = $f.find(".new-note-left").text(); + } + + $("#curNotebookForNewSharedNote").html(curNotebookTitle + '(' + Share.sharedUserInfos[userId].Username + ')'); + $("#curNotebookForNewSharedNote").attr("notebookId", curNotebookId); + $("#curNotebookForNewSharedNote").attr("userId", userId); + + $("#newSharedNote").show(); + $("#newMyNote").hide(); + + } else { + // 展示出我的笔记 + $("#newMyNote").show(); + $("#newSharedNote").hide(); + } + + // 隐藏tag + $("#tagSearch").hide(); +} + +//改变笔记本 +//0. 改变样式 +//1. 改变note, 此时需要先保存 +//2. ajax得到该notebook下的所有note +//3. 使用Note.RederNotes() +Share.changeNotebook = function(userId, notebookId) { + // 选中 + Notebook.selectNotebook($(tt('#friendContainer_? a[notebookId="?"]', userId, notebookId))); + + // 改变nav!!!! TODO + Share.toggleToSharedNav(userId, notebookId); + + // 1 + Note.curChangedSaveIt(); + + // 2 先清空所有 + Note.clearAll(); + + var url = "/share/ListShareNotes/"; + var param = {userId: userId}; + if(!Share.isDefaultNotebookId(notebookId)) { + param.notebookId = notebookId; + } + + // 2 得到笔记本 + // 这里可以缓存起来, note按notebookId缓存 + ajaxGet(url, param, function(ret) { + // note 导航 + // + // 如果是特定笔记本下的notes, 那么传过来的没有权限信息, 此时权限由notebookId决定 + if(param.notebookId) { + + } + Note.renderNotes(ret, false, true); + // 渲染第一个 + // 这里, 有点小复杂, 还要判断权限... + if(!isEmpty(ret)) { + // 定位 + Note.changeNote(ret[0].NoteId, true); + } else { + } + }); +} + +// 是否有更新权限 +// called by Note +Share.hasUpdatePerm = function(notebookId) { + var note = Share.cache[notebookId]; + if(!note || !note.Perm) { + return false; + } + return true; +} + +//--------------------------- +// 我删除别人共享给我的笔记本 +Share.deleteShareNotebook = function(target) { + if(confirm("Are you sure to delete it?")) { + var notebookId = $(target).attr("notebookId"); + var fromUserId = $(target).closest(".friend-notebooks").attr("fromUserId"); // 谁共享给了我 from + ajaxGet("/share/DeleteShareNotebookBySharedUser", {notebookId: notebookId, fromUserId: fromUserId}, function(ret) { + if(ret) { + $(target).parent().remove(); + } + }); + } +} +Share.deleteShareNote = function(target) { + var noteId = $(target).attr("noteId"); + var fromUserId = $(target).attr("fromUserId"); // 谁共享给了我 from + ajaxGet("/share/DeleteShareNoteBySharedUser", {noteId: noteId, fromUserId: fromUserId}, function(ret) { + if(ret) { + $(target).remove(); + } + }); +} +Share.deleteUserShareNoteAndNotebook = function(target) { + if(confirm("Are you sure to delete all shared notebooks and notes?")) { + var fromUserId = $(target).attr("fromUserId"); // 谁共享给了我 from + ajaxGet("/share/deleteUserShareNoteAndNotebook", {fromUserId: fromUserId}, function(ret) { + if(ret) { + $(target).parent().remove(); + } + }); + } +} + +// 新建shared note +Share.changeNotebookForNewNote = function(notebookId) { + // 改变nav for list, for new + Notebook.selectNotebook($(tt('#shareNotebooks [notebookId="?"]', notebookId))); + var userId = Share.notebookCache[notebookId].UserId; + Share.toggleToSharedNav(userId, notebookId); + + // 得到笔记本 + var url = "/share/ListShareNotes/"; + var param = {userId: userId, notebookId: notebookId}; + + // 2 得到笔记本 + // 这里可以缓存起来, note按notebookId缓存 + ajaxGet(url, param, function(ret) { + // note 导航 + Note.renderNotes(ret, true, true); + }); +} + +// 删除笔记, 我有权限, 且是我创建的笔记 +Share.deleteSharedNote = function(target, contextmenuItem) { + Note.deleteNote(target, contextmenuItem, true); +} +Share.copySharedNote = function(target, contextmenuItem) { + Note.copyNote(target, contextmenuItem, true); +} + +Share.contextmenu = null; +Share.initContextmenu = function(notebooksCopy) { + if(Share.contextmenu) { + Share.contextmenu.destroy(); + } + + //--------------------- + // context menu + //--------------------- + var noteListMenu = { + width: 180, + items: [ + { text: getMsg("copyToMyNotebook"), alias: "copy", faIcon: "fa-copy", + type: "group", + width: 180, + items: notebooksCopy + }, + { type: "splitLine" }, + { text: getMsg("delete"), alias: "delete", icon: "", faIcon: "fa-trash-o", action: Share.deleteSharedNote } + ], + onShow: applyrule, + parent: "#noteItemList", + children: ".item-shared", + } + function applyrule(menu) { + var noteId = $(this).attr("noteId"); + var note = Share.cache[noteId]; + if(!note) { + return; + } + var items = []; + if(!(note.Perm && note.CreatedUserId == UserInfo.UserId)) { + items.push("delete"); + } + // 不是自己的创建的不能删除 + menu.applyrule({ + name: "target...", + disable: true, + items: items + }); + + } + + Share.contextmenu = $("#noteItemList .item-shared").contextmenu(noteListMenu); +} + +$(function() { + // note setting + $("#noteItemList").on("click", ".item-shared .item-setting", function(e) { + e.preventDefault(); + e.stopPropagation(); + // 得到ID + var $p = $(this).parent(); + Share.contextmenu.showMenu(e, $p); + }); + + + + //--------------------------- + // 新建笔记 + // 1. 直接点击新建 OR + // 2. 点击nav for new note + $("#newSharedNoteBtn").click(function() { + var notebookId = $("#curNotebookForNewSharedNote").attr('notebookId'); + var userId = $("#curNotebookForNewSharedNote").attr('userId'); + Note.newNote(notebookId, true, userId); + }); + $("#newShareNoteMarkdownBtn").click(function() { + var notebookId = $("#curNotebookForNewSharedNote").attr('notebookId'); + var userId = $("#curNotebookForNewSharedNote").attr('userId'); + Note.newNote(notebookId, true, userId, true); + }); + $("#notebookNavForNewSharedNote").on("click", "li div", function() { + var notebookId = $(this).parent().attr("notebookId"); + var userId = $(this).parent().attr("userId"); + + if($(this).text() == "M") { + Note.newNote(notebookId, true, userId, true); + } else { + Note.newNote(notebookId, true, userId); + } + }); + + //------------------ + // 添加共享 + $("#leanoteDialogRemote").on("click", ".change-perm", function() { + var self = this; + var perm = $(this).attr("perm"); + var noteOrNotebookId = $(this).attr("noteOrNotebookId"); + var toUserId = $(this).attr("toUserId"); + var toHtml = getMsg("writable"); + var toPerm = "1"; + if(perm == "1") { + toHtml = getMsg("readOnly"); + toPerm = "0"; + } + var url = "/share/UpdateShareNotebookPerm"; + var param = {perm: toPerm, toUserId: toUserId}; + if(Share.dialogIsNote) { + url = "/share/UpdateShareNotePerm"; + param.noteId = noteOrNotebookId; + } else { + param.notebookId = noteOrNotebookId; + } + ajaxGet(url, param, function(ret) { + if(ret) { + $(self).html(toHtml); + $(self).attr("perm", toPerm); + } + }); + }); + + $("#leanoteDialogRemote").on("click", ".delete-share", function() { + var self = this; + var noteOrNotebookId = $(this).attr("noteOrNotebookId"); + var toUserId = $(this).attr("toUserId"); + + var url = "/share/DeleteShareNotebook"; + var param = {toUserId: toUserId}; + if(Share.dialogIsNote) { + url = "/share/DeleteShareNote"; + param.noteId = noteOrNotebookId; + } else { + param.notebookId = noteOrNotebookId; + } + + ajaxGet(url, param, function(ret) { + if(ret) { + $(self).parent().parent().remove(); + } + }); + }); + + // 添加共享 + var seq = 1; + $("#leanoteDialogRemote").on("click", "#addShareNotebookBtn", function() { + seq++; + var tpl = '#'; + tpl += ''; + tpl += ' '; + tpl += ''; + tpl += ' '; + tpl += ""; + $("#shareNotebookTable tbody").prepend(tpl); + + $("#tr" + seq + " #friendsEmail").focus(); + }); + + //------------------- + // 发送邀请邮件 + $("#registerEmailBtn").click(function() { + var content = $("#emailContent").val(); + var toEmail = $("#toEmail").val(); + if(!content) { + showAlert("#registerEmailMsg", getMsg("emailBodyRequired"), "danger"); + return; + } + post("/user/sendRegisterEmail", {content: content, toEmail: toEmail}, function(ret) { + showAlert("#registerEmailMsg", getMsg("sendSuccess"), "success"); + hideDialog2("#sendRegisterEmailDialog", 1000); + }, this); + }); +}); + +// trSeq 1,2,3... +function addShareNoteOrNotebook(trSeq) { + var trId = "#tr" + trSeq; + var id = Share.dialogNoteOrNotebookId; + + var emails = isEmailFromInput(trId + " #friendsEmail", "#shareMsg", getMsg("inputFriendEmail")); + if(!emails) { + return; + } + var shareNotePerm = $(trId + ' input[name="perm' + trSeq + '"]:checked').val() || 0; + var perm = shareNotePerm; + // emails = emails.split(";"); + var url = "share/addShareNote"; + var data = {noteId: id, emails: [emails], perm: shareNotePerm}; + if(!Share.dialogIsNote) { + url = "share/addShareNotebook"; + data = {notebookId: id, emails: [emails], perm: shareNotePerm}; + } + hideAlert("#shareMsg"); + post(url, data, function(ret) { + var ret = ret[emails]; + if(ret) { + // 成功 + // 成功了则去掉输入框 + if(ret.Ok) { + var tpl = tt('?', '#'); + tpl += tt('?', emails); + tpl += tt('?', id, perm, ret.Id, !perm || perm == '0' ? getMsg("readOnly") : getMsg("writable")); + tpl += tt('' + getMsg("delete") +'', id, ret.Id); + $(trId).html(tpl); + } else { + var shareUrl = UrlPrefix + '/register?from=' + UserInfo.Username; + showAlert("#shareMsg", getMsg('friendNotExits', [getMsg("app"), shareUrl]) + ' ' + getMsg("clickToCopy") + '
            ' + getMsg("sendInviteEmailToYourFriend") + ', ' + getMsg("send"), "warning"); + $("#copyDiv").text(shareUrl); + initCopy("shareCopy", function(args) { + if(args.text) { + showMsg2("#copyStatus", getMsg("copySuccess"), 1000); + } else { + showMsg2("#copyStatus", getMsg("copyFailed"), 1000); + } + }); + } + } + }, trId + " .btn-success"); +} + +// 发送邀请邮件 +function sendRegisterEmail(email) { + showDialog2("#sendRegisterEmailDialog", {postShow: function() { + $("#emailContent").val(getMsg("inviteEmailBody", [UserInfo.Username, getMsg("app")])); + setTimeout(function() { + $("#emailContent").focus(); + }, 500); + $("#toEmail").val(email); + }}); +} + +function deleteShareNoteOrNotebook(trSeq) { + $("#tr" + trSeq).remove(); +} diff --git a/public/js/app/tag-min.js b/public/js/app/tag-min.js new file mode 100644 index 0000000..0b50a63 --- /dev/null +++ b/public/js/app/tag-min.js @@ -0,0 +1 @@ +Tag.classes={"蓝色":"label label-blue","红色":"label label-red","绿色":"label label-green","黄色":"label label-yellow",blue:"label label-blue",red:"label label-red",green:"label label-green",yellow:"label label-yellow"};Tag.mapCn2En={"蓝色":"blue","红色":"red","绿色":"green","黄色":"yellow"};Tag.mapEn2Cn={blue:"蓝色",red:"红色",green:"绿色",yellow:"黄色"};Tag.t=$("#tags");Tag.getTags=function(){var tags=[];Tag.t.children().each(function(){var text=$(this).text();text=text.substring(0,text.length-1);text=Tag.mapCn2En[text]||text;tags.push(text)});return tags};Tag.clearTags=function(){Tag.t.html("")};Tag.renderTags=function(tags){Tag.t.html("");if(isEmpty(tags)){return}for(var i=0;i?',classes,text);$("#noteReadTags").append(tag)}};Tag.appendTag=function(tag){var isColor=false;var classes,text;if(typeof tag=="object"){classes=tag.classes;text=tag.text;if(!text){return}}else{tag=$.trim(tag);text=tag;if(!text){return}var classes=Tag.classes[text];if(classes){isColor=true}else{classes="label label-default"}}if(LEA.locale=="zh"){text=Tag.mapEn2Cn[text]||text}tag=tt('?X',classes,text);$("#tags").children().each(function(){if(isColor){var tagHtml=$("
            ").append($(this).clone()).html();if(tagHtml==tag){$(this).remove()}}else if(text+"X"==$(this).text()){$(this).remove()}});$("#tags").append(tag);hideTagList();if(!isColor){reRenderTags()}};function reRenderTags(){var defautClasses=["label label-default","label label-info"];var i=0;$("#tags").children().each(function(){var thisClasses=$(this).attr("class");if(thisClasses=="label label-default"||thisClasses=="label label-info"){$(this).removeClass(thisClasses).addClass(defautClasses[i%2]);i++}})}Tag.renderTagNav=function(tags){tags=tags||[];for(var i in tags){var tag=tags[i];if(tag=="red"||tag=="blue"||tag=="yellow"||tag=="green"){continue}var text=Tag.mapEn2Cn[tag]||tag;var classes=Tag.classes[tag]||"label label-default";$("#tagNav").append(tt('
          • ?
          • ',text,classes,text))}};$(function(){$("#addTagTrigger").click(function(){$(this).hide();$("#addTagInput").show().focus().val("")});$("#addTagInput").click(function(event){showTagList(event)});$("#addTagInput").blur(function(){var val=$(this).val();if(val){Tag.appendTag(val,true)}return;$("#addTagTrigger").show();$("#addTagInput").hide()});$("#addTagInput").keydown(function(e){if(e.keyCode==13){hideTagList();if($("#addTagInput").val()){$(this).trigger("blur");$("#addTagTrigger").trigger("click")}else{$(this).trigger("blur")}}});$("#tagColor li").click(function(event){var a;if($(this).attr("role")){a=$(this).find("span")}else{a=$(this)}Tag.appendTag({classes:a.attr("class"),text:a.text()})});$("#tags").on("click","i",function(){$(this).parent().remove();reRenderTags()});function searchTag(){var tag=$.trim($(this).data("tag"));Note.curChangedSaveIt();Note.clearAll();$("#tagSearch").html($(this).html()).show();showLoading();ajaxGet("/note/searchNoteByTags",{tags:[tag]},function(notes){hideLoading();if(notes){Note.renderNotes(notes);if(!isEmpty(notes)){Note.changeNote(notes[0].NoteId)}}})}$("#myTag .folderBody").on("click","li",searchTag);$("#minTagNav").on("click","li",searchTag)}); \ No newline at end of file diff --git a/public/js/app/tag.js b/public/js/app/tag.js new file mode 100644 index 0000000..0a8c27f --- /dev/null +++ b/public/js/app/tag.js @@ -0,0 +1,300 @@ +// Tag + +// 蓝色, 红色怎么存到数据库中? 直接存蓝色 + +Tag.classes = { + "蓝色": "label label-blue", + "红色": "label label-red", + "绿色": "label label-green", + "黄色": "label label-yellow", + "blue": "label label-blue", + "red": "label label-red", + "green": "label label-green", + "yellow": "label label-yellow" +} + +// 数据库中统一存En +Tag.mapCn2En = { + "蓝色": "blue", + "红色": "red", + "绿色": "green", + "黄色": "yellow", +} +Tag.mapEn2Cn = { + "blue": "蓝色", + "red": "红色", + "green": "绿色", + "yellow": "黄色", +} + +Tag.t = $("#tags"); + +// called by Note +Tag.getTags = function() { + var tags = []; + Tag.t.children().each(function(){ + var text = $(this).text(); + text = text.substring(0, text.length - 1); // 把X去掉 + text = Tag.mapCn2En[text] || text; + tags.push(text); + }); + // 需要去重吗? 正常情况下不会重复 + return tags; +} + +// called by Note +Tag.clearTags = function() { + Tag.t.html(""); +} + +// 设置tags +// called by Note +Tag.renderTags = function(tags) { + Tag.t.html(""); + if(isEmpty(tags)) { + return; + } + // TODO 重构, 这样不高效 + for(var i = 0; i < tags.length; ++i) { + var tag = tags[i]; + Tag.appendTag(tag); + } +} + +// tag最初状态 +function revertTagStatus() { + $("#addTagTrigger").show(); + $("#addTagInput").hide(); + // hideTagList(); +} + +function hideTagList(event) { + $("#tagDropdown").removeClass("open"); + if (event) { + event.stopPropagation() + } +} +function showTagList(event) { + $("#tagDropdown").addClass("open"); + if (event) { + event.stopPropagation() + } +} + +// 只读模式下显示tags +// called by Note +Tag.renderReadOnlyTags = function(tags) { + // 先清空 + $("#noteReadTags").html(""); + if(isEmpty(tags)) { + $("#noteReadTags").html(getMsg("noTag")); + } + + var i = true; + function getNextDefaultClasses() { + if (i) { + return "label label-default"; + i = false + } else { + i = true; + return "label label-info"; + } + } + + for(var i in tags) { + var text = tags[i]; + text = Tag.mapEn2Cn[text] || text; + var classes = Tag.classes[text]; + if(!classes) { + classes = getNextDefaultClasses(); + } + tag = tt('?', classes, text); + + $("#noteReadTags").append(tag); + } +} + +// 添加tag +// tag = {classes:"label label-red", text:"红色"} +// tag = life +Tag.appendTag = function(tag) { + var isColor = false; + var classes, text; + + if (typeof tag == "object") { + classes = tag.classes; + text = tag.text; + if(!text) { + return; + } + } else { + tag = $.trim(tag); + text = tag; + if(!text) { + return; + } + var classes = Tag.classes[text]; + if(classes) { + isColor = true; + } else { + classes = "label label-default"; + } + } + + if(LEA.locale == "zh") { + text = Tag.mapEn2Cn[text] || text; + } + tag = tt('?X', classes, text); + + // 避免重复 + $("#tags").children().each(function() { + if (isColor) { + var tagHtml = $("
            ").append($(this).clone()).html(); + if (tagHtml == tag) { + $(this).remove(); + } + } else if (text + "X" == $(this).text()) { + $(this).remove(); + } + }); + + $("#tags").append(tag); + + hideTagList(); + + if (!isColor) { + reRenderTags(); + } +} + +// 为了颜色间隔, add, delete时调用 +function reRenderTags() { + var defautClasses = [ "label label-default", "label label-info" ]; + var i = 0; + $("#tags").children().each( + function() { + var thisClasses = $(this).attr("class"); + if (thisClasses == "label label-default" + || thisClasses == "label label-info") { + $(this).removeClass(thisClasses).addClass( + defautClasses[i % 2]); + i++; + } + }); +} + +//----------- +// 左侧nav en -> cn +Tag.renderTagNav = function(tags) { + tags = tags || []; + for(var i in tags) { + var tag = tags[i]; + if(tag == "red" || tag == "blue" || tag == "yellow" || tag == "green") { + continue; + } + var text = Tag.mapEn2Cn[tag] || tag; + var classes = Tag.classes[tag] || "label label-default"; + $("#tagNav").append(tt('
          • ?
          • ', text, classes, text)); + } +} + + +// 事件 +$(function() { + // tag + $("#addTagTrigger").click(function() { + $(this).hide(); + $("#addTagInput").show().focus().val(""); + }); + + $("#addTagInput").click(function(event) { + showTagList(event); + }); + + $("#addTagInput").blur(function() { + var val = $(this).val(); + if(val) { + Tag.appendTag(val, true); + } + return; + // 下面不能有, 有就有问题 + $("#addTagTrigger").show(); + $("#addTagInput").hide(); + // revertTagStatus(); + }); + $('#addTagInput').keydown(function(e) { + if (e.keyCode == 13) { + hideTagList(); + // 如果有值, 再生成, 没值直接隐藏 + if ($("#addTagInput").val()) { + $(this).trigger("blur"); + $("#addTagTrigger").trigger("click"); + } else { + $(this).trigger("blur"); + } + } + }); + // 点击下拉时也会触发input的blur事件 + $("#tagColor li").click(function(event) { + var a; + if($(this).attr("role")) { + a = $(this).find("span"); + } else { + a = $(this); + } + Tag.appendTag({ + classes : a.attr("class"), + text : a.text() + }); + }); + // 这是个问题, 为什么? 捕获不了事件?, input的blur造成 + /* + $(".label").click(function(event) { + var a = $(this); + Tag.appendTag({ + classes : a.attr("class"), + text : a.text() + }); + // event.stopPropagation(); + }); + */ + + $("#tags").on("click", "i", function() { + $(this).parent().remove(); + reRenderTags(); + }); + + //------------- + // nav 标签搜索 + function searchTag() { + var tag = $.trim($(this).data("tag")); + // tag = Tag.mapCn2En[tag] || tag; + + // 学习changeNotebook + + // 1 + Note.curChangedSaveIt(); + + // 2 先清空所有 + // 也会把curNoteId清空 + Note.clearAll(); + + $("#tagSearch").html($(this).html()).show(); + showLoading(); + ajaxGet("/note/searchNoteByTags", {tags: [tag]}, function(notes) { + hideLoading(); + if(notes) { + // 和note搜索一样 + // 设空, 防止发生上述情况 + // Note.curNoteId = ""; + + Note.renderNotes(notes); + if(!isEmpty(notes)) { + Note.changeNote(notes[0].NoteId); + } + } + }); + } + $("#myTag .folderBody").on("click", "li", searchTag); + $("#minTagNav").on("click", "li", searchTag); +}); \ No newline at end of file From 954c4e5e95539c40e5686ffc6a3e6c0b9280e890 Mon Sep 17 00:00:00 2001 From: life Date: Sun, 9 Nov 2014 22:26:38 +0800 Subject: [PATCH 06/12] for setBlog --- app/controllers/NoteController.go | 28 +++++++++++++++++++++++---- app/controllers/NotebookController.go | 8 ++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/app/controllers/NoteController.go b/app/controllers/NoteController.go index 33e6dad..df21997 100644 --- a/app/controllers/NoteController.go +++ b/app/controllers/NoteController.go @@ -7,6 +7,7 @@ import ( . "github.com/leanote/leanote/app/lea" "github.com/leanote/leanote/app/info" "os/exec" + "time" // "github.com/leanote/leanote/app/types" // "io/ioutil" // "fmt" @@ -52,8 +53,8 @@ func (c Note) Index() revel.Result { } // 当然, 还需要得到第一个notes的content //... - c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username + c.RenderArgs["userInfo"] = userInfo c.RenderArgs["userInfoJson"] = c.Json(userInfo) c.RenderArgs["notebooks"] = c.Json(notebooks) @@ -123,7 +124,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result { // 新添加note if noteOrContent.IsNew { userId := c.GetObjectUserId(); - myUserId := userId +// myUserId := userId // 为共享新建? if noteOrContent.FromUserId != "" { userId = bson.ObjectIdHex(noteOrContent.FromUserId) @@ -145,7 +146,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result { Content: noteOrContent.Content, Abstract: noteOrContent.Abstract}; - note = noteService.AddNoteAndContent(note, noteContent, myUserId) + note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId()) return c.RenderJson(note) } @@ -352,4 +353,23 @@ func (c Note) Html2Image(noteId string) revel.Result { } */ -} \ No newline at end of file +} + +// 设置/取消Blog; 置顶 +func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result { + noteUpdate := bson.M{} + if isTop { + isBlog = true + } + if !isBlog { + isTop = false + } + noteUpdate["IsBlog"] = isBlog + noteUpdate["IsTop"] = isTop + if isBlog { + noteUpdate["PublicTime"] = time.Now() + } + re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(), + noteId, noteUpdate) + return c.RenderJson(re) +} diff --git a/app/controllers/NotebookController.go b/app/controllers/NotebookController.go index d09d95a..b77adcd 100644 --- a/app/controllers/NotebookController.go +++ b/app/controllers/NotebookController.go @@ -68,4 +68,12 @@ func (c Notebook) DragNotebooks(data string) revel.Result { json.Unmarshal([]byte(data), &info) return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings)) +} + +// 设置notebook <-> blog +func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result { + noteUpdate := bson.M{"IsBlog": isBlog} + re := notebookService.UpdateNotebook(c.GetUserId(), + notebookId, noteUpdate) + return c.RenderJson(re) } \ No newline at end of file From 6555384e5ca5d18cfa0fa1b25c9a94aa20c97aa3 Mon Sep 17 00:00:00 2001 From: life Date: Mon, 10 Nov 2014 16:26:04 +0800 Subject: [PATCH 07/12] siteurl, adminUsername config in configService --- app/controllers/BaseController.go | 6 +- app/controllers/BlogController.go | 6 +- app/controllers/FileController.go | 4 +- app/controllers/NoteController.go | 5 +- .../admin/AdminUpgradeController.go | 10 ++- app/controllers/admin/init.go | 5 +- app/controllers/init.go | 84 ++++++++++--------- app/controllers/member/init.go | 4 +- app/service/BlogService.go | 4 +- app/service/ConfigService.go | 47 +++++++---- app/service/EmailService.go | 20 ++--- app/service/ThemeService.go | 2 +- app/service/UserService.go | 5 +- app/service/init.go | 8 +- messages/msg.en | 2 + messages/msg.zh | 4 +- 16 files changed, 118 insertions(+), 98 deletions(-) diff --git a/app/controllers/BaseController.go b/app/controllers/BaseController.go index 8ed0de9..fcef661 100644 --- a/app/controllers/BaseController.go +++ b/app/controllers/BaseController.go @@ -183,7 +183,7 @@ func (c BaseController) SetLocale() string { lang = "en"; } c.RenderArgs["locale"] = lang; - c.RenderArgs["siteUrl"] = siteUrl; + c.RenderArgs["siteUrl"] = configService.GetSiteUrl(); c.RenderArgs["blogUrl"] = configService.GetBlogUrl() c.RenderArgs["leaUrl"] = configService.GetLeaUrl() @@ -196,7 +196,7 @@ func (c BaseController) SetLocale() string { func (c BaseController) SetUserInfo() { userInfo := c.GetUserInfo() c.RenderArgs["userInfo"] = userInfo - if(userInfo.Username == adminUsername) { + if(userInfo.Username == configService.GetAdminUsername()) { c.RenderArgs["isAdmin"] = true } } @@ -242,4 +242,4 @@ func (c BaseController) RenderRe(re info.Re) revel.Result { } } return c.RenderJson(re) -} \ No newline at end of file +} diff --git a/app/controllers/BlogController.go b/app/controllers/BlogController.go index c1cf46c..d01d043 100644 --- a/app/controllers/BlogController.go +++ b/app/controllers/BlogController.go @@ -104,6 +104,7 @@ func (c Blog) setPreviewUrl() { themeId := c.Session["themeId"] theme := themeService.GetTheme(userId, themeId) + siteUrl := configService.GetSiteUrl() blogUrl := siteUrl + "/preview" // blog.leanote.com userIdOrEmail := userId @@ -137,6 +138,7 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0]) // staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com // life.leanote.com, lealife.com + siteUrl := configService.GetSiteUrl() if userBlog.Domain != "" && configService.AllowCustomDomain() { // ok indexUrl = configService.GetUserUrl(userBlog.Domain) @@ -496,7 +498,7 @@ func (c Blog) Archive(userIdOrEmail string, cateId string) (re revel.Result) { // 用户id为空, 转至博客平台 if userIdOrEmail == "" { - userIdOrEmail = leanoteUserId + userIdOrEmail = configService.GetAdminUsername() } var userInfo info.User if userId != "" { @@ -594,7 +596,7 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) { // 用户id为空, 转至博客平台 if userIdOrEmail == "" { - userIdOrEmail = leanoteUserId + userIdOrEmail = configService.GetAdminUsername() } var userInfo info.User if userId != "" { diff --git a/app/controllers/FileController.go b/app/controllers/FileController.go index b95e0d3..7e4a4b7 100644 --- a/app/controllers/FileController.go +++ b/app/controllers/FileController.go @@ -316,7 +316,7 @@ func (c File) UploadImage(renderHtml string) revel.Result { re := c.uploadImage("", ""); - c.RenderArgs["fileUrlPath"] = siteUrl + re.Id + c.RenderArgs["fileUrlPath"] = configService.GetSiteUrl() + re.Id c.RenderArgs["resultCode"] = re.Code c.RenderArgs["resultMsg"] = re.Msg @@ -327,4 +327,4 @@ func (c File) UploadImage(renderHtml string) revel.Result { func (c File) UploadImageJson(from, noteId string) revel.Result { re := c.uploadImage(from, ""); return c.RenderJson(re) -} \ No newline at end of file +} diff --git a/app/controllers/NoteController.go b/app/controllers/NoteController.go index df21997..80e8b17 100644 --- a/app/controllers/NoteController.go +++ b/app/controllers/NoteController.go @@ -53,7 +53,8 @@ func (c Note) Index() revel.Result { } // 当然, 还需要得到第一个notes的content //... - c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username + Log(configService.GetAdminUsername()) + c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username c.RenderArgs["userInfo"] = userInfo c.RenderArgs["userInfoJson"] = c.Json(userInfo) @@ -299,7 +300,7 @@ func (c Note) Html2Image(noteId string) revel.Result { appKey, _ := revel.Config.String("app.secret") cookieDomain, _ := revel.Config.String("cookie.domain") // 生成之 - url := siteUrl + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey; + url := configService.GetSiteUrl() + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey; // /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js binPath := configService.GetGlobalStringConfig("toImageBinPath") if binPath == "" { diff --git a/app/controllers/admin/AdminUpgradeController.go b/app/controllers/admin/AdminUpgradeController.go index c8dc206..8580acf 100644 --- a/app/controllers/admin/AdminUpgradeController.go +++ b/app/controllers/admin/AdminUpgradeController.go @@ -3,7 +3,7 @@ package admin import ( "github.com/revel/revel" // "encoding/json" -// . "github.com/leanote/leanote/app/lea" + "github.com/leanote/leanote/app/info" // "io/ioutil" ) @@ -15,4 +15,10 @@ type AdminUpgrade struct { func (c AdminUpgrade) UpgradeBlog() revel.Result { upgradeService.UpgradeBlog() return nil; -} \ No newline at end of file +} + +func (c AdminUpgrade) UpgradeBetaToSelfBlog() revel.Result { + re := info.NewRe() + re.Ok, re.Msg = upgradeService.UpgradeBetaToSelfBlog(c.GetUserId()) + return c.RenderJson(re) +} diff --git a/app/controllers/admin/init.go b/app/controllers/admin/init.go index c151864..bcd964c 100644 --- a/app/controllers/admin/init.go +++ b/app/controllers/admin/init.go @@ -28,7 +28,6 @@ var configService *service.ConfigService var emailService *service.EmailService var upgradeService *service.UpgradeService -var adminUsername = "admin" // 拦截器 // 不需要拦截的url // Index 除了Note之外都不需要 @@ -83,7 +82,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result { // 验证是否已登录 // 必须是管理员 - if username, ok := c.Session["Username"]; ok && username == adminUsername { + if username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() { return nil // 已登录 } @@ -129,4 +128,4 @@ func init() { revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminEmail{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUpgrade{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminData{}) -} \ No newline at end of file +} diff --git a/app/controllers/init.go b/app/controllers/init.go index 2af847f..11c1761 100644 --- a/app/controllers/init.go +++ b/app/controllers/init.go @@ -20,9 +20,9 @@ var blogService *service.BlogService var tagService *service.TagService var pwdService *service.PwdService var tokenService *service.TokenService -var suggestionService *service.SuggestionService -var albumService *service.AlbumService -var noteImageService *service.NoteImageService +var suggestionService *service.SuggestionService +var albumService *service.AlbumService +var noteImageService *service.NoteImageService var fileService *service.FileService var attachService *service.AttachService var configService *service.ConfigService @@ -32,43 +32,45 @@ var themeService *service.ThemeService var pageSize = 1000 var defaultSortField = "UpdatedTime" -var leanoteUserId = "admin" // 不能更改 -var adminUsername = "admin" -var siteUrl = "http://leanote.com" // 拦截器 // 不需要拦截的url // Index 除了Note之外都不需要 -var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true, - "Login": true, - "DoLogin": true, - "Logout": true, - "Register": true, - "DoRegister": true, - "FindPasswword": true, - "DoFindPassword": true, - "FindPassword2": true, - "FindPasswordUpdate": true, - "Suggestion": true, - }, +var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true, + "Login": true, + "DoLogin": true, + "Logout": true, + "Register": true, + "DoRegister": true, + "FindPasswword": true, + "DoFindPassword": true, + "FindPassword2": true, + "FindPasswordUpdate": true, + "Suggestion": true, +}, "Note": map[string]bool{"ToImage": true}, "Blog": map[string]bool{"Index": true, - "View": true, - "AboutMe": true, - "Cate": true, - "Search": true, + "View": true, + "AboutMe": true, + "Cate": true, + "ListCateLatest": true, + "Search": true, "GetLikeAndComments": true, - "IncReadNum": true, - "ListComments": true, - }, + "IncReadNum": true, + "ListComments": true, + "Single": true, + "Archive": true, + "Tags": true, + }, // 用户的激活与修改邮箱都不需要登录, 通过链接地址 "User": map[string]bool{"UpdateEmail": true, - "ActiveEmail":true, - }, - "Oauth": map[string]bool{"GithubCallback": true}, - "File": map[string]bool{"OutputImage": true, "OutputFile": true}, + "ActiveEmail": true, + }, + "Oauth": map[string]bool{"GithubCallback": true}, + "File": map[string]bool{"OutputImage": true, "OutputFile": true}, "Attach": map[string]bool{"Download": true, "DownloadAll": true}, } + func needValidate(controller, method string) bool { // 在里面 if v, ok := commonUrl[controller]; ok { @@ -79,31 +81,31 @@ func needValidate(controller, method string) bool { return true } else { // controller不在这里的, 肯定要验证 - return true; + return true } } func AuthInterceptor(c *revel.Controller) revel.Result { // 全部变成首字大写 var controller = strings.Title(c.Name) var method = strings.Title(c.MethodName) - + // 是否需要验证? if !needValidate(controller, method) { return nil } - + // 验证是否已登录 if userId, ok := c.Session["UserId"]; ok && userId != "" { return nil // 已登录 } - + // 没有登录, 判断是否是ajax操作 if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" { re := info.NewRe() re.Msg = "NOTLOGIN" return c.RenderJson(re) } - + return c.Redirect("/login") } @@ -121,7 +123,7 @@ func InitService() { tokenService = service.TokenS noteImageService = service.NoteImageS fileService = service.FileS - albumService= service.AlbumS + albumService = service.AlbumS attachService = service.AttachS pwdService = service.PwdS suggestionService = service.SuggestionS @@ -132,6 +134,11 @@ func InitService() { themeService = service.ThemeS } +// 初始化博客模板 +// 博客模板不由revel的 +func initBlogTemplate() { +} + func init() { // interceptor // revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验 @@ -141,12 +148,11 @@ func init() { revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{}) +// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{}) - + revel.OnAppStart(func() { - siteUrl, _ = revel.Config.String("site.url") - // 博客初始化模板 blog.Init() }) -} \ No newline at end of file +} diff --git a/app/controllers/member/init.go b/app/controllers/member/init.go index a86b6f1..2737265 100644 --- a/app/controllers/member/init.go +++ b/app/controllers/member/init.go @@ -29,7 +29,6 @@ var emailService *service.EmailService var upgradeService *service.UpgradeService var themeService *service.ThemeService -var adminUsername = "admin" // 拦截器 // 不需要拦截的url // Index 除了Note之外都不需要 @@ -128,6 +127,5 @@ func init() { revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{}) revel.OnAppStart(func() { - adminUsername, _ = revel.Config.String("adminUsername") }) -} \ No newline at end of file +} diff --git a/app/service/BlogService.go b/app/service/BlogService.go index a396d0b..4d8677c 100644 --- a/app/service/BlogService.go +++ b/app/service/BlogService.go @@ -429,7 +429,7 @@ func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) { // Logo路径问题, 有些有http: 有些没有 if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") { userBlog.Logo = strings.Trim(userBlog.Logo, "/") - userBlog.Logo = siteUrl + "/" + userBlog.Logo + userBlog.Logo = configService.GetSiteUrl() + "/" + userBlog.Logo } if userBlog.SortField == "" { @@ -691,7 +691,7 @@ func (this *BlogService) DeleteComment(noteId, commentId, userId string) bool { return false } - if userId == adminUserId || note.UserId.Hex() == userId || comment.UserId.Hex() == userId { + if userId == configService.GetAdminUserId() || note.UserId.Hex() == userId || comment.UserId.Hex() == userId { if db.Delete(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}) { // 评论-1 db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": -1}}) diff --git a/app/service/ConfigService.go b/app/service/ConfigService.go index fd79093..a24cc7e 100644 --- a/app/service/ConfigService.go +++ b/app/service/ConfigService.go @@ -17,6 +17,9 @@ import ( // 配置服务 // 只是全局的, 用户的配置没有 type ConfigService struct { + adminUserId string + siteUrl string + adminUsername string // 全局的 GlobalAllConfigs map[string]interface{} GlobalStringConfigs map[string]string @@ -24,9 +27,6 @@ type ConfigService struct { GlobalMapConfigs map[string]map[string]string GlobalArrMapConfigs map[string][]map[string]string } - -var adminUserId = "" - // appStart时 将全局的配置从数据库中得到作为全局 func (this *ConfigService) InitGlobalConfigs() bool { this.GlobalAllConfigs = map[string]interface{}{} @@ -35,16 +35,17 @@ func (this *ConfigService) InitGlobalConfigs() bool { this.GlobalMapConfigs = map[string]map[string]string{} this.GlobalArrMapConfigs = map[string][]map[string]string{} - adminUsername, _ := revel.Config.String("adminUsername") - if adminUsername == "" { - adminUsername = "admin" + this.adminUsername, _ = revel.Config.String("adminUsername") + if this.adminUsername == "" { + this.adminUsername = "admin" } + this.siteUrl, _ = revel.Config.String("site.url") - userInfo := userService.GetUserInfoByAny(adminUsername) + userInfo := userService.GetUserInfoByAny(this.adminUsername) if userInfo.UserId == "" { return false } - adminUserId = userInfo.UserId.Hex() + this.adminUserId = userInfo.UserId.Hex() configs := []info.Config{} db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs) @@ -68,6 +69,16 @@ func (this *ConfigService) InitGlobalConfigs() bool { return true } +func (this *ConfigService) GetSiteUrl() string { + return this.siteUrl; +} +func (this *ConfigService) GetAdminUsername() string { + return this.adminUsername +} +func (this *ConfigService) GetAdminUserId() string { + return this.adminUserId +} + // 通用方法 func (this *ConfigService) updateGlobalConfig(userId, key string, value interface{}, isArr, isMap, isArrMap bool) bool { // 判断是否存在 @@ -183,7 +194,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string, if registerSharedUserId == "" { ok = true msg = "share userId is blank, So it share nothing to register" - this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", "") + this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "") return } else { user := userService.GetUserInfo(registerSharedUserId) @@ -192,7 +203,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string, msg = "no such user: " + registerSharedUserId return } else { - this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", registerSharedUserId) + this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId) } } @@ -219,7 +230,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string, } } } - this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotebooks", notebooks) + this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks) notes := []map[string]string{} // 共享笔记 @@ -244,7 +255,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string, } } } - this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotes", notes) + this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes) // 复制 noteIds := []string{} @@ -265,7 +276,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string, } } } - this.UpdateGlobalArrayConfig(adminUserId, "registerCopyNoteIds", noteIds) + this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds) ok = true return @@ -277,7 +288,7 @@ func (this *ConfigService) AddBackup(path, remark string) bool { n := time.Now().Unix() nstr := fmt.Sprintf("%v", n) backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark}) - return this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups) + return this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups) } func (this *ConfigService) getBackupDirname() string { @@ -349,7 +360,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) { port, _ := revel.Config.String("db.port") username, _ := revel.Config.String("db.username") password, _ := revel.Config.String("db.password") - // mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p kk + // mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port if username != "" { binPath += " -u " + username + " -p " + password @@ -398,7 +409,7 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) { // 删除之 backups = append(backups[0:i], backups[i+1:]...) - ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups) + ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups) return ok, "" } @@ -416,7 +427,7 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool, } backup["remark"] = remark; - ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups) + ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups) return ok, "" } @@ -451,7 +462,7 @@ func init() { port = ""; } - siteUrl, _ = revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com + siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com if strings.HasPrefix(siteUrl, "http://") { defaultDomain = siteUrl[len("http://"):] } else if strings.HasPrefix(siteUrl, "https://") { diff --git a/app/service/EmailService.go b/app/service/EmailService.go index 09c7045..ad71306 100644 --- a/app/service/EmailService.go +++ b/app/service/EmailService.go @@ -82,9 +82,9 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri return false } - tokenUrl := siteUrl + "/user/activeEmail?token=" + token + tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token // {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username} - token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))), + token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))), "user": map[string]interface{}{ "userId": userInfo.UserId.Hex(), "email": userInfo.Email, @@ -122,9 +122,9 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail"); // 发送邮件 - tokenUrl := siteUrl + "/user/updateEmail?token=" + token + tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token // {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username} - token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))), + token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))), "newEmail": email, "user": map[string]interface{}{ "userId": userInfo.UserId.Hex(), @@ -148,9 +148,9 @@ func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg st tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword"); // 发送邮件 - tokenUrl := siteUrl + "/findPassword/" + token + tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token // {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username} - token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, + token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))} ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value) @@ -167,8 +167,8 @@ func (this *EmailService) SendInviteEmail(userInfo info.User, email, content str subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject"); tpl := configService.GetGlobalStringConfig("emailTemplateInvite"); - token2Value := map[string]interface{}{"siteUrl": siteUrl, - "registerUrl": siteUrl + "/register?from=" + userInfo.Username, + token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), + "registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username, "content": content, "user": map[string]interface{}{ "username": userInfo.Username, @@ -225,7 +225,7 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm // {blog.id} {blog.title} {blog.url} // {commentUser.userId} {commentUser.username} {commentUser.email} // {commentedUser.userId} {commentedUser.username} {commentedUser.email} - token2Value := map[string]interface{}{"siteUrl": siteUrl, "blogUrl": configService.GetBlogUrl(), + token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(), "blog": map[string]string{ "id": note.NoteId.Hex(), "title": note.Title, @@ -316,7 +316,7 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in var tpl *template.Template - values["siteUrl"] = siteUrl; + values["siteUrl"] = configService.GetSiteUrl(); // subject if subject != "" { diff --git a/app/service/ThemeService.go b/app/service/ThemeService.go index 1f717e9..e5b18fb 100644 --- a/app/service/ThemeService.go +++ b/app/service/ThemeService.go @@ -362,7 +362,7 @@ func (this *ThemeService) DeleteTheme(userId, themeId string) (ok bool) { func (this *ThemeService) PublicTheme(userId, themeId string) (ok bool) { // 是否是管理员? userInfo := userService.GetUserInfo(userId) - if userInfo.Username == adminUsername { + if userInfo.Username == configService.GetAdminUsername() { theme := this.GetThemeById(themeId) return db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(themeId)}, "IsDefault", !theme.IsDefault) } diff --git a/app/service/UserService.go b/app/service/UserService.go index 8b0ac4d..5a3461c 100644 --- a/app/service/UserService.go +++ b/app/service/UserService.go @@ -75,7 +75,7 @@ func (this *UserService) setUserLogo(user *info.User) { } if user.Logo != "" && !strings.HasPrefix(user.Logo, "http") { user.Logo = strings.Trim(user.Logo, "/") - user.Logo = siteUrl + "/" + user.Logo + user.Logo = configService.GetSiteUrl() + "/" + user.Logo } } @@ -256,8 +256,7 @@ func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) { // 管理员重置密码 func (this *UserService) ResetPwd(adminUserId, userId, pwd string) (ok bool, msg string) { - adminInfo := this.GetUserInfoByAny(adminUsername) - if adminInfo.UserId.Hex() != adminUserId { + if configService.GetAdminUserId() != adminUserId { return } ok = db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd)) diff --git a/app/service/init.go b/app/service/init.go index e386a7c..2c7cb7e 100644 --- a/app/service/init.go +++ b/app/service/init.go @@ -1,7 +1,6 @@ package service import ( - "github.com/revel/revel" ) // init service, for share service bettween services @@ -30,9 +29,6 @@ var UpgradeS *UpgradeService var SessionS, sessionService *SessionService var ThemeS, themeService *ThemeService -var siteUrl string -var adminUsername = "admin" - // onAppStart调用 func InitService() { NotebookS = &NotebookService{} @@ -74,6 +70,4 @@ func InitService() { emailService = EmailS sessionService = SessionS themeService = ThemeS - - siteUrl, _ = revel.Config.String("site.url") -} \ No newline at end of file +} diff --git a/messages/msg.en b/messages/msg.en index 6b3f71c..f81e974 100644 --- a/messages/msg.en +++ b/messages/msg.en @@ -242,6 +242,8 @@ latest=Latest # 用户中心 memberCenter=Member Center +userNotExists=该成员沿未注册 +hasUsers=已存在该成员 # error notFound=This page cann't found. diff --git a/messages/msg.zh b/messages/msg.zh index 0971dab..e22b669 100644 --- a/messages/msg.zh +++ b/messages/msg.zh @@ -268,6 +268,8 @@ latest=最新 # 用户中心 memberCenter=用户中心 +userNotExists=该成员沿未注册 +hasUsers=已存在该成员 # 必须要加这个, 奇怪 -[CN] \ No newline at end of file +[CN] From d979a0c3e237762690f848339aead18fc6696e7e Mon Sep 17 00:00:00 2001 From: life Date: Mon, 10 Nov 2014 23:56:15 +0800 Subject: [PATCH 08/12] blog, tags, archives --- app/controllers/BlogController.go | 64 +++++++------ app/controllers/NoteController.go | 17 +--- app/controllers/NotebookController.go | 4 +- app/controllers/PreviewController.go | 4 +- app/db/Mgo.go | 6 +- app/info/BlogCustom.go | 36 +++---- app/info/TagInfo.go | 25 ++++- app/service/BlogService.go | 129 +++++++++++++++++++------- app/service/ConfigService.go | 1 - app/service/NoteService.go | 21 +++++ app/service/NotebookService.go | 51 +++++----- 11 files changed, 233 insertions(+), 125 deletions(-) diff --git a/app/controllers/BlogController.go b/app/controllers/BlogController.go index d01d043..d0a84f4 100644 --- a/app/controllers/BlogController.go +++ b/app/controllers/BlogController.go @@ -8,18 +8,20 @@ import ( . "github.com/leanote/leanote/app/lea" "github.com/leanote/leanote/app/lea/blog" "gopkg.in/mgo.v2/bson" + "fmt" // "github.com/leanote/leanote/app/types" // "io/ioutil" // "math" // "os" // "path" -// "fmt" ) type Blog struct { BaseController } +//----------------------------- +// 前台 /* 公共 // 分类 [ok] @@ -114,7 +116,7 @@ func (c Blog) setPreviewUrl() { postUrl = blogUrl + "/post" // /xxxxx searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId - archiveUrl = blogUrl + "/archive/" + userIdOrEmail // blog.leanote.com/archive/userId + archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId c.RenderArgs["indexUrl"] = indexUrl @@ -123,8 +125,10 @@ func (c Blog) setPreviewUrl() { c.RenderArgs["searchUrl"] = searchUrl c.RenderArgs["singleUrl"] = singleUrl // 单页 c.RenderArgs["archiveUrl"] = archiveUrl + c.RenderArgs["archivesUrl"] = archiveUrl // 别名 c.RenderArgs["tagsUrl"] = tagsUrl c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail + c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"] // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的 c.RenderArgs["themeBaseUrl"] = "/" + theme.Path @@ -146,7 +150,7 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { postUrl = indexUrl + "/post" // /xxxxx searchUrl = indexUrl + "/search" // /xxxxx singleUrl = indexUrl + "/single" - archiveUrl = indexUrl + "/archive" + archiveUrl = indexUrl + "/archives" tagsUrl = indexUrl + "/tags" tagPostsUrl = indexUrl + "/tag" } else if userBlog.SubDomain != "" { @@ -155,7 +159,7 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { postUrl = indexUrl + "/post" // /xxxxx searchUrl = indexUrl + "/search" // /xxxxx singleUrl = indexUrl + "/single" - archiveUrl = indexUrl + "/archive" + archiveUrl = indexUrl + "/archives" tagsUrl = indexUrl + "/tags" tagPostsUrl = indexUrl + "/tag" } else { @@ -174,7 +178,7 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { postUrl = blogUrl + "/post" // /xxxxx searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId - archiveUrl = blogUrl + "/archive/" + userIdOrEmail // blog.leanote.com/archive/userId + archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId tagsUrl = blogUrl + "/tags/" + userIdOrEmail tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/userId } @@ -189,8 +193,10 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { c.RenderArgs["searchUrl"] = searchUrl c.RenderArgs["singleUrl"] = singleUrl // 单页 c.RenderArgs["archiveUrl"] = archiveUrl + c.RenderArgs["archivesUrl"] = archiveUrl // 别名 c.RenderArgs["tagsUrl"] = tagsUrl c.RenderArgs["tagPostsUrl"] = tagPostsUrl + c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"] // 别名 // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的 c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath @@ -323,6 +329,7 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us _, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc) c.RenderArgs["recentPosts"] = c.fixBlogs(recentBlogs) c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"] + c.RenderArgs["tags"] = blogService.GetBlogTags(userId) // 语言, url地址 c.SetLocale() @@ -355,26 +362,26 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us } // 修复博客, index, cate用到 -func (c Blog) fixBlog(blog info.BlogItem) map[string]interface{} { - blog2 := map[string]interface{}{ - "NoteId": blog.NoteId.Hex(), - "Title": blog.Title, - "CreatedTime": blog.CreatedTime, - "UpdatedTime": blog.UpdatedTime, - "PublicTime": blog.PublicTime, - "Desc": blog.Desc, - "Abstract": blog.Abstract, - "Content": blog.Content, - "Tags": blog.Tags, - "CommentNum": blog.CommentNum, - "ReadNum": blog.ReadNum, - "LikeNum": blog.LikeNum, - "IsMarkdown": blog.IsMarkdown, +func (c Blog) fixBlog(blog info.BlogItem) info.Post { + blog2 := info.Post{ + NoteId: blog.NoteId.Hex(), + Title: blog.Title, + CreatedTime: blog.CreatedTime, + UpdatedTime: blog.UpdatedTime, + PublicTime: blog.PublicTime, + Desc: blog.Desc, + Abstract: blog.Abstract, + Content: blog.Content, + Tags: blog.Tags, + CommentNum: blog.CommentNum, + ReadNum: blog.ReadNum, + LikeNum: blog.LikeNum, + IsMarkdown: blog.IsMarkdown, } return blog2 } -func (c Blog) fixBlogs(blogs []info.BlogItem) []map[string]interface{} { - blogs2 := make([]map[string]interface{}, len(blogs)) +func (c Blog) fixBlogs(blogs []info.BlogItem) []info.Post { + blogs2 := make([]info.Post, len(blogs)) for i, blog := range blogs { blogs2[i] = c.fixBlog(blog) } @@ -430,7 +437,7 @@ func (c Blog) Tags(userIdOrEmail string) (re revel.Result) { } c.RenderArgs["curIsTags"] = true - tags := blogService.ListBlogsTag(userId) + tags := blogService.GetBlogTags(userId) c.RenderArgs["tags"] = tags return c.render("tags.html", userBlog.ThemePath) } @@ -482,12 +489,13 @@ func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) { } // 归档 -func (c Blog) Archive(userIdOrEmail string, cateId string) (re revel.Result) { +func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re revel.Result) { notebookId := cateId // 自定义域名 hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { + fmt.Println(err) re = c.e404(userBlog.ThemePath); } }() @@ -513,7 +521,7 @@ func (c Blog) Archive(userIdOrEmail string, cateId string) (re revel.Result) { return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 } - arcs := blogService.ListBlogsArchive(userId, notebookId, "PublicTime", false) + arcs := blogService.ListBlogsArchive(userId, notebookId, year, month, "PublicTime", false) c.RenderArgs["archives"] = arcs c.RenderArgs["curIsArchive"] = true @@ -522,6 +530,9 @@ func (c Blog) Archive(userIdOrEmail string, cateId string) (re revel.Result) { c.RenderArgs["curCateTitle"] = notebook.Title c.RenderArgs["curCateId"] = notebookId } + c.RenderArgs["curYear"] = year + c.RenderArgs["curMonth"] = month + return c.render("archive.html", userBlog.ThemePath) } @@ -621,8 +632,7 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) { c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"] c.RenderArgs["curIsIndex"] = true - - Log("----") + return c.render("index.html", userBlog.ThemePath) } diff --git a/app/controllers/NoteController.go b/app/controllers/NoteController.go index 80e8b17..d0c7bcb 100644 --- a/app/controllers/NoteController.go +++ b/app/controllers/NoteController.go @@ -7,7 +7,7 @@ import ( . "github.com/leanote/leanote/app/lea" "github.com/leanote/leanote/app/info" "os/exec" - "time" +// "time" // "github.com/leanote/leanote/app/types" // "io/ioutil" // "fmt" @@ -358,19 +358,6 @@ func (c Note) Html2Image(noteId string) revel.Result { // 设置/取消Blog; 置顶 func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result { - noteUpdate := bson.M{} - if isTop { - isBlog = true - } - if !isBlog { - isTop = false - } - noteUpdate["IsBlog"] = isBlog - noteUpdate["IsTop"] = isTop - if isBlog { - noteUpdate["PublicTime"] = time.Now() - } - re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(), - noteId, noteUpdate) + re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop) return c.RenderJson(re) } diff --git a/app/controllers/NotebookController.go b/app/controllers/NotebookController.go index b77adcd..db1d7d9 100644 --- a/app/controllers/NotebookController.go +++ b/app/controllers/NotebookController.go @@ -72,8 +72,6 @@ func (c Notebook) DragNotebooks(data string) revel.Result { // 设置notebook <-> blog func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result { - noteUpdate := bson.M{"IsBlog": isBlog} - re := notebookService.UpdateNotebook(c.GetUserId(), - notebookId, noteUpdate) + re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog) return c.RenderJson(re) } \ No newline at end of file diff --git a/app/controllers/PreviewController.go b/app/controllers/PreviewController.go index e3eda7f..c049f56 100644 --- a/app/controllers/PreviewController.go +++ b/app/controllers/PreviewController.go @@ -64,11 +64,11 @@ func (c Preview) Tags(userIdOrEmail string) revel.Result { // } // return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) } -func (c Preview) Archive(userIdOrEmail string, notebookId string) revel.Result { +func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result { if !c.getPreviewThemeAbsolutePath("") { return c.E404() } - return c.Blog.Archive(c.GetUserId(), notebookId) + return c.Blog.Archives(c.GetUserId(), notebookId, year, month) // return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) } func (c Preview) Cate(notebookId string) revel.Result { diff --git a/app/db/Mgo.go b/app/db/Mgo.go index 40beb0d..37b0bdb 100644 --- a/app/db/Mgo.go +++ b/app/db/Mgo.go @@ -27,7 +27,8 @@ var Groups *mgo.Collection var GroupUsers *mgo.Collection var Tags *mgo.Collection -var TagNotes *mgo.Collection +//var TagNotes *mgo.Collection +var TagCounts *mgo.Collection var UserBlogs *mgo.Collection @@ -110,7 +111,8 @@ func Init() { // tag Tags = Session.DB(dbname).C("tags") - TagNotes = Session.DB(dbname).C("tag_notes") +// TagNotes = Session.DB(dbname).C("tag_notes") + TagCounts = Session.DB(dbname).C("tag_count") // blog UserBlogs = Session.DB(dbname).C("user_blogs") diff --git a/app/info/BlogCustom.go b/app/info/BlogCustom.go index 4e6cab5..0da02b8 100644 --- a/app/info/BlogCustom.go +++ b/app/info/BlogCustom.go @@ -1,7 +1,7 @@ package info import ( -// "time" + "time" ) // 仅仅为了博客的主题 @@ -22,24 +22,26 @@ type BlogInfoCustom struct { type Post struct { NoteId string + Title string + CreatedTime time.Time + UpdatedTime time.Time + PublicTime time.Time + Desc string + Abstract string + Content string + Tags []string + CommentNum int + ReadNum int + LikeNum int + IsMarkdown bool } // 归档 +type ArchiveMonth struct { + Month int + Posts []*Post +} type Archive struct { Year int - Posts []map[string]interface{} + MonthAchives []ArchiveMonth + Posts []*Post } - -type TagsCounts []TagCount -type TagCount struct { - Tag string - Count int -} -func (this TagsCounts) Len() int { - return len(this) -} -func (this TagsCounts) Less(i, j int) bool { - return this[i].Count > this[j].Count -} -func (this TagsCounts) Swap(i, j int) { - this[i], this[j] = this[j], this[i] -} \ No newline at end of file diff --git a/app/info/TagInfo.go b/app/info/TagInfo.go index b8ab389..722bd5f 100644 --- a/app/info/TagInfo.go +++ b/app/info/TagInfo.go @@ -5,15 +5,38 @@ import ( ) // 这里主要是为了统计每个tag的note数目 +// 暂时没用 +/* type TagNote struct { TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 UserId bson.ObjectId `bson:"UserId"` Tag string `Title` // 标题 NoteNum int `NoteNum` // note数目 } +*/ // 每个用户一条记录, 存储用户的所有tags type Tag struct { UserId bson.ObjectId `bson:"_id"` Tags []string `Tags` -} \ No newline at end of file +} + +type TagCount struct { + TagCountId bson.ObjectId `bson:"_id,omitempty"` + UserId bson.ObjectId `UserId` // 谁的 + Tag string `Tag` + IsBlog bool `IsBlog` // 是否是博客的tag统计 + Count int `Count` // 统计数量 +} +/* +type TagsCounts []TagCount +func (this TagsCounts) Len() int { + return len(this) +} +func (this TagsCounts) Less(i, j int) bool { + return this[i].Count > this[j].Count +} +func (this TagsCounts) Swap(i, j int) { + this[i], this[j] = this[j], this[i] +} +*/ \ No newline at end of file diff --git a/app/service/BlogService.go b/app/service/BlogService.go index 4d8677c..33a2105 100644 --- a/app/service/BlogService.go +++ b/app/service/BlogService.go @@ -7,7 +7,7 @@ import ( // "github.com/leanote/leanote/app/lea/netutil" "gopkg.in/mgo.v2/bson" // "time" - "sort" +// "sort" "strings" "time" "strconv" @@ -111,13 +111,25 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int {Tag:xxx, Count: 32} ] */ -func (this *BlogService) ListBlogsTag(userId string) (info.TagsCounts) { +func (this *BlogService) GetBlogTags(userId string) ([]info.TagCount) { + // 得到所有博客 + tagCounts := []info.TagCount{} + query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true} + db.TagCounts.Find(query).Sort("-Count").All(&tagCounts) + return tagCounts +} +// 重新计算博客的标签 +// 在设置设置/取消为博客时调用 +func (this *BlogService) ReCountBlogTags(userId string) (bool) { // 得到所有博客 notes := []info.Note{} - query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": false, "IsBlog": true} + userIdO := bson.ObjectIdHex(userId) + query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true} db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es) + + db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true}); if(notes == nil || len(notes) == 0) { - return nil + return true } // 统计所有的Tags和数目 tagsCount := map[string]int{} @@ -131,16 +143,12 @@ func (this *BlogService) ListBlogsTag(userId string) (info.TagsCounts) { } } } - // 排序, 从大到小 - var tagsCounts info.TagsCounts - tagsCounts = make(info.TagsCounts, len(tagsCount)) - i := 0 + // 一个个插入 for tag, count := range tagsCount { - tagsCounts[i] = info.TagCount{tag, count} - i++ + db.Insert(db.TagCounts, + info.TagCount{UserId: userIdO, IsBlog: true, Tag: tag, Count: count}) } - sort.Sort(&tagsCounts) - return tagsCounts + return true } // 归档博客 /* @@ -155,8 +163,42 @@ Year: 2014 Posts: [] } */ -func (this *BlogService) ListBlogsArchive(userId, notebookId string, sortField string, isAsc bool) ([]info.Archive) { - _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true); +func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) ([]info.Archive) { +// _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true); + q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false} + if notebookId != "" { + q["NotebookId"] = bson.ObjectIdHex(notebookId) + } + if year > 0 { + now := time.Now() + nextYear := year + nextMonth := month + if month == 0 { + month = 1 + nextYear = year + 1 + nextMonth = month + } else if month >= 12 { + month = 12 + nextYear = year + 1 + nextMonth = 1 + } else { // month 在1-12之间 + nextMonth = month + 1 + } + leftT := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, now.Location()) + rightT := time.Date(nextYear, time.Month(nextMonth), 1, 0, 0, 0, 0, now.Location()) + if sortField == "CreatedTime" || sortField == "UpdatedTime" { + q[sortField] = bson.M{"$gte": leftT, "$lt": rightT} + } else { + q["PublicTime"] = bson.M{"$gte": leftT, "$lt": rightT} + } + } + + sorter := sortField + if !isAsc { + sorter = "-" + sortField + } + notes := []info.Note{} + db.Notes.Find(q).Sort(sorter).All(¬es) if(notes == nil || len(notes) == 0) { return nil @@ -164,50 +206,71 @@ func (this *BlogService) ListBlogsArchive(userId, notebookId string, sortField s arcs := []info.Archive{} // 按年汇总 - arcsMap := map[int]*info.Archive{} + arcsMap := map[int]info.Archive{} + // 按月汇总 + arcsMonth := []info.ArchiveMonth{} var t time.Time - var arc *info.Archive + var arc info.Archive everYear := 0 for _, note := range notes { if sortField == "PublicTime" { t = note.PublicTime - } else if sortField == "CreatedTime"{ + } else if sortField == "CreatedTime" { t = note.CreatedTime } else { t = note.UpdatedTime } year := t.Year() + month := int(t.Month()) if everYear == 0 { everYear = year } if everYear != year { - arcs = append(arcs, *arcsMap[everYear]) + yearArc := arcsMap[everYear] + yearArc.MonthAchives = arcsMonth + arcs = append(arcs, yearArc) everYear = year + + // 新的一年 + arcsMonth = []info.ArchiveMonth{} } if arcT, ok := arcsMap[year]; ok { arc = arcT } else { - arc = &info.Archive{Year: year, Posts: []map[string]interface{}{}} + arc = info.Archive{Year: year, Posts: []*info.Post{}} } - arc.Posts = append(arc.Posts, map[string]interface{}{ - "NoteId": note.NoteId.Hex(), - "Title": note.Title, - "CreatedTime": note.CreatedTime, - "UpdatedTime": note.UpdatedTime, - "PublicTime": note.PublicTime, - "Desc": note.Desc, - "Tags": note.Tags, - "CommentNum": note.CommentNum, - "ReadNum": note.ReadNum, - "LikeNum": note.LikeNum, - "IsMarkdown": note.IsMarkdown, - }); + p := &info.Post{ + NoteId: note.NoteId.Hex(), + Title: note.Title, + CreatedTime: note.CreatedTime, + UpdatedTime: note.UpdatedTime, + PublicTime: note.PublicTime, + Desc: note.Desc, + Tags: note.Tags, + CommentNum: note.CommentNum, + ReadNum: note.ReadNum, + LikeNum: note.LikeNum, + IsMarkdown: note.IsMarkdown, + } + arc.Posts = append(arc.Posts, p); arcsMap[year] = arc + + // month + lm := len(arcsMonth) + if(lm == 0 || arcsMonth[lm-1].Month != month) { + arcsMonth = append(arcsMonth, info.ArchiveMonth{month, []*info.Post{p}}) + } else { + arcsMonth[lm-1].Posts = append(arcsMonth[lm-1].Posts, p) + } } // 最后一个 - arcs = append(arcs, *arcsMap[everYear]) + if everYear > 0 { + yearArc := arcsMap[everYear] + yearArc.MonthAchives = arcsMonth + arcs = append(arcs, yearArc) + } return arcs } diff --git a/app/service/ConfigService.go b/app/service/ConfigService.go index a24cc7e..5d1c4e6 100644 --- a/app/service/ConfigService.go +++ b/app/service/ConfigService.go @@ -472,7 +472,6 @@ func init() { }) } - func (this *ConfigService) GetSchema() string { return schema; } diff --git a/app/service/NoteService.go b/app/service/NoteService.go index a4accd3..9ca994c 100644 --- a/app/service/NoteService.go +++ b/app/service/NoteService.go @@ -294,6 +294,27 @@ func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags) } +func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool { + noteUpdate := bson.M{} + if isTop { + isBlog = true + } + if !isBlog { + isTop = false + } + noteUpdate["IsBlog"] = isBlog + noteUpdate["IsTop"] = isTop + if isBlog { + noteUpdate["PublicTime"] = time.Now() + } + ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate) + // 重新计算tags + go (func() { + blogService.ReCountBlogTags(userId) + })() + return ok +} + // 移动note // trash, 正常的都可以用 // 1. 要检查下notebookId是否是自己的 diff --git a/app/service/NotebookService.go b/app/service/NotebookService.go index a1a3774..a64b16e 100644 --- a/app/service/NotebookService.go +++ b/app/service/NotebookService.go @@ -170,34 +170,37 @@ func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title strin // 更新notebook func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool { needUpdate["UpdatedTime"] = time.Now(); - - // 如果有IsBlog之类的, 需要特殊处理 - if isBlog, ok := needUpdate["IsBlog"]; ok { - // 设为blog/取消, 把它下面所有的note都设为isBlog - if is, ok2 := isBlog.(bool); ok2 { - q := bson.M{"UserId": bson.ObjectIdHex(userId), + return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate) +} + +// ToBlog or Not +func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) { + q := bson.M{"UserId": bson.ObjectIdHex(userId), "NotebookId": bson.ObjectIdHex(notebookId)} - data := bson.M{"IsBlog": is} - if is { - data["PublicTime"] = time.Now() - } - db.UpdateByQMap(db.Notes, q, data) - - // noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId - // 先查该notebook下所有notes, 得到id - notes := []info.Note{} - db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es) - if len(notes) > 0 { - noteIds := make([]bson.ObjectId, len(notes)) - for i, each := range notes { - noteIds[i] = each.NoteId - } - db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog}) - } + data := bson.M{"IsBlog": isBlog} + if isBlog { + data["PublicTime"] = time.Now() + } + db.UpdateByQMap(db.Notes, q, data) + + // noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId + // 先查该notebook下所有notes, 得到id + notes := []info.Note{} + db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es) + if len(notes) > 0 { + noteIds := make([]bson.ObjectId, len(notes)) + for i, each := range notes { + noteIds[i] = each.NoteId } + db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog}) } - return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate) + // 重新计算tags + go (func() { + blogService.ReCountBlogTags(userId) + })() + + return true } // 查看是否有子notebook From 1f45666ec426838dd276ab98658bf4d65adc4cda Mon Sep 17 00:00:00 2001 From: life Date: Wed, 12 Nov 2014 17:32:03 +0800 Subject: [PATCH 09/12] beta2 ok --- app/controllers/BlogController.go | 409 ++++------- app/controllers/IndexController.go | 4 + app/controllers/PreviewController.go | 12 +- app/controllers/ShareController.go | 48 +- app/controllers/admin/AdminBlogController.go | 4 +- app/controllers/admin/AdminController.go | 1 + .../admin/AdminSettingController.go | 9 + .../admin/AdminUpgradeController.go | 6 +- .../member/MemberBlogController.go | 95 ++- .../member/MemberGroupController.go | 58 ++ app/controllers/member/init.go | 2 + app/info/BlogCustom.go | 2 + app/info/BlogInfo.go | 18 +- app/info/GroupInfo.go | 25 + app/info/NoteInfo.go | 14 +- app/info/NotebookInfo.go | 1 + app/info/ShareNotebookNoteInfo.go | 8 +- app/info/UserInfo.go | 4 +- app/info/common.go | 5 +- app/init.go | 7 +- app/service/AuthService.go | 5 +- app/service/BlogService.go | 657 ++++++++++++------ app/service/ConfigService.go | 9 + app/service/GroupService.go | 130 ++++ app/service/NoteImageService.go | 7 +- app/service/NoteService.go | 30 +- app/service/NotebookService.go | 12 + app/service/ShareService.go | 355 +++++++--- app/service/ThemeService.go | 30 + app/service/UpgradeService.go | 62 +- app/service/UserService.go | 26 +- app/service/init.go | 77 ++ app/views/admin/nav.html | 39 +- app/views/admin/setting/home_page.html | 49 ++ .../{openRegister.html => open_register.html} | 0 app/views/admin/upgrade/beta2.html | 47 ++ app/views/member/blog/cate.html | 18 +- app/views/member/blog/comment.html | 3 +- app/views/member/blog/list.html | 169 +++++ app/views/member/blog/page.html | 33 + app/views/member/blog/single.html | 18 +- app/views/member/blog/update_abstract.html | 127 ++++ app/views/member/group/index.html | 220 ++++++ app/views/member/nav.html | 22 +- app/views/note/note-dev.html | 2 +- .../share/note_notebook_share_user_infos.html | 126 +++- conf/routes-default | 21 +- messages/msg.en | 1 + messages/msg.zh | 1 + .../leanote_install_data/albums.bson | Bin 599 -> 0 bytes .../leanote_install_data/attachs.bson | Bin 16100 -> 0 bytes .../attachs.metadata.json | 1 - .../leanote_install_data/blog_comments.bson | Bin 15724 -> 0 bytes .../leanote_install_data/blog_likes.bson | Bin 1079 -> 0 bytes .../leanote_install_data/blog_singles.bson | Bin 0 -> 538 bytes ...tadata.json => blog_singles.metadata.json} | 2 +- .../leanote_install_data/configs.bson | Bin 21865 -> 0 bytes .../leanote_install_data/email_logs.bson | Bin 209 -> 0 bytes .../email_logs.metadata.json | 1 - .../leanote_install_data/files.bson | Bin 584 -> 0 bytes .../leanote_install_data/files.metadata.json | 1 - .../leanote_install_data/find_pwds.bson | Bin 348 -> 0 bytes .../find_pwds.metadata.json | 1 - .../leanote_install_data/group_users.bson | Bin 0 -> 84 bytes ...etadata.json => group_users.metadata.json} | 2 +- .../leanote_install_data/groups.bson | Bin 0 -> 102 bytes ...igs.metadata.json => groups.metadata.json} | 2 +- .../leanote_install_data/has_share_notes.bson | Bin 219 -> 0 bytes .../has_share_notes.metadata.json | 1 - .../leanote.ShareNotes.bson | 0 .../leanote.ShareNotes.metadata.json | 1 - .../leanote.has_share_notes.bson | 0 .../leanote.has_share_notes.metadata.json | 1 - .../note_content_histories.bson | Bin 11537 -> 0 bytes .../note_content_histories.metadata.json | 1 - .../leanote_install_data/note_contents.bson | Bin 6572 -> 0 bytes .../note_contents.metadata.json | 1 - .../leanote_install_data/note_images.bson | Bin 3339 -> 0 bytes .../note_images.metadata.json | 1 - .../leanote_install_data/notebooks.bson | Bin 1147 -> 0 bytes .../notebooks.metadata.json | 1 - .../leanote_install_data/notes.bson | Bin 1786 -> 0 bytes .../leanote_install_data/notes.metadata.json | 1 - .../leanote_install_data/reports.bson | Bin 915 -> 0 bytes .../reports.metadata.json | 1 - .../leanote_install_data/sessions.bson | Bin 2100 -> 0 bytes .../sessions.metadata.json | 1 - .../leanote_install_data/share_notebooks.bson | Bin 384 -> 0 bytes .../share_notebooks.metadata.json | 1 - .../leanote_install_data/share_notes.bson | Bin 345 -> 0 bytes .../share_notes.metadata.json | 1 - .../leanote_install_data/suggestions.bson | Bin 4219 -> 0 bytes .../suggestions.metadata.json | 1 - .../leanote_install_data/system.indexes.bson | Bin 2779 -> 0 bytes .../system.users.metadata.json | 1 - mongodb_backup/leanote_install_data/tags.bson | Bin 62 -> 0 bytes .../leanote_install_data/tags.metadata.json | 1 - .../leanote_install_data/themes.bson | Bin 0 -> 1587 bytes ...ums.metadata.json => themes.metadata.json} | 2 +- .../leanote_install_data/tokens.bson | Bin 872 -> 0 bytes .../leanote_install_data/tokens.metadata.json | 1 - .../leanote_install_data/user_blogs.bson | Bin 631 -> 0 bytes .../user_blogs.metadata.json | 1 - .../leanote_install_data/users.bson | Bin 569 -> 0 bytes .../leanote_install_data/users.metadata.json | 1 - public/blog/js/ck/common-min.js | 1 - public/blog/js/common.js | 6 +- public/blog/themes/README.html | 1 + public/blog/themes/default/header.html | 10 +- public/blog/themes/elegant/archive.html | 12 +- public/blog/themes/elegant/header.html | 4 +- public/blog/themes/elegant/index.html | 4 +- public/blog/themes/elegant/post.html | 4 +- public/blog/themes/elegant/search.html | 4 +- public/blog/themes/elegant/tag_posts.html | 4 +- public/blog/themes/nav_fixed/header.html | 10 +- public/member/css/member.css | 6 + public/member/css/member.less | 8 +- public/tinymce/plugins/leaui_image/plugin.js | 6 +- 119 files changed, 2463 insertions(+), 675 deletions(-) create mode 100644 app/controllers/member/MemberGroupController.go create mode 100644 app/info/GroupInfo.go create mode 100644 app/service/GroupService.go create mode 100644 app/views/admin/setting/home_page.html rename app/views/admin/setting/{openRegister.html => open_register.html} (100%) create mode 100644 app/views/admin/upgrade/beta2.html create mode 100644 app/views/member/blog/list.html create mode 100644 app/views/member/blog/page.html create mode 100644 app/views/member/blog/update_abstract.html create mode 100644 app/views/member/group/index.html delete mode 100644 mongodb_backup/leanote_install_data/albums.bson delete mode 100644 mongodb_backup/leanote_install_data/attachs.bson delete mode 100644 mongodb_backup/leanote_install_data/attachs.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/blog_comments.bson delete mode 100644 mongodb_backup/leanote_install_data/blog_likes.bson create mode 100644 mongodb_backup/leanote_install_data/blog_singles.bson rename mongodb_backup/leanote_install_data/{blog_likes.metadata.json => blog_singles.metadata.json} (59%) delete mode 100644 mongodb_backup/leanote_install_data/configs.bson delete mode 100644 mongodb_backup/leanote_install_data/email_logs.bson delete mode 100644 mongodb_backup/leanote_install_data/email_logs.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/files.bson delete mode 100644 mongodb_backup/leanote_install_data/files.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/find_pwds.bson delete mode 100644 mongodb_backup/leanote_install_data/find_pwds.metadata.json create mode 100644 mongodb_backup/leanote_install_data/group_users.bson rename mongodb_backup/leanote_install_data/{blog_comments.metadata.json => group_users.metadata.json} (59%) create mode 100644 mongodb_backup/leanote_install_data/groups.bson rename mongodb_backup/leanote_install_data/{configs.metadata.json => groups.metadata.json} (62%) delete mode 100644 mongodb_backup/leanote_install_data/has_share_notes.bson delete mode 100644 mongodb_backup/leanote_install_data/has_share_notes.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/leanote.ShareNotes.bson delete mode 100644 mongodb_backup/leanote_install_data/leanote.ShareNotes.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/leanote.has_share_notes.bson delete mode 100644 mongodb_backup/leanote_install_data/leanote.has_share_notes.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/note_content_histories.bson delete mode 100644 mongodb_backup/leanote_install_data/note_content_histories.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/note_contents.bson delete mode 100644 mongodb_backup/leanote_install_data/note_contents.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/note_images.bson delete mode 100644 mongodb_backup/leanote_install_data/note_images.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/notebooks.bson delete mode 100644 mongodb_backup/leanote_install_data/notebooks.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/notes.bson delete mode 100644 mongodb_backup/leanote_install_data/notes.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/reports.bson delete mode 100644 mongodb_backup/leanote_install_data/reports.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/sessions.bson delete mode 100644 mongodb_backup/leanote_install_data/sessions.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/share_notebooks.bson delete mode 100644 mongodb_backup/leanote_install_data/share_notebooks.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/share_notes.bson delete mode 100644 mongodb_backup/leanote_install_data/share_notes.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/suggestions.bson delete mode 100644 mongodb_backup/leanote_install_data/suggestions.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/system.indexes.bson delete mode 100644 mongodb_backup/leanote_install_data/system.users.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/tags.bson delete mode 100644 mongodb_backup/leanote_install_data/tags.metadata.json create mode 100644 mongodb_backup/leanote_install_data/themes.bson rename mongodb_backup/leanote_install_data/{albums.metadata.json => themes.metadata.json} (62%) delete mode 100644 mongodb_backup/leanote_install_data/tokens.bson delete mode 100644 mongodb_backup/leanote_install_data/tokens.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/user_blogs.bson delete mode 100644 mongodb_backup/leanote_install_data/user_blogs.metadata.json delete mode 100644 mongodb_backup/leanote_install_data/users.bson delete mode 100644 mongodb_backup/leanote_install_data/users.metadata.json delete mode 100644 public/blog/js/ck/common-min.js create mode 100644 public/blog/themes/README.html diff --git a/app/controllers/BlogController.go b/app/controllers/BlogController.go index d0a84f4..172b9d8 100644 --- a/app/controllers/BlogController.go +++ b/app/controllers/BlogController.go @@ -4,11 +4,11 @@ import ( "github.com/revel/revel" "strings" // "encoding/json" + "fmt" "github.com/leanote/leanote/app/info" . "github.com/leanote/leanote/app/lea" "github.com/leanote/leanote/app/lea/blog" "gopkg.in/mgo.v2/bson" - "fmt" // "github.com/leanote/leanote/app/types" // "io/ioutil" // "math" @@ -47,26 +47,25 @@ $.bootstrapCssUrl $.bootstrapJsUrl */ - func (c Blog) render(templateName string, themePath string) revel.Result { isPreview := false - if c.RenderArgs["isPreview"] != nil { + if c.RenderArgs["isPreview"] != nil { themePath2 := c.RenderArgs["themePath"] if themePath2 == nil { - return c.E404(); + return c.E404() } isPreview = true themePath = themePath2.(string) c.setPreviewUrl() } - return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath + "/" + themePath, isPreview) + return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview) } // 404 func (c Blog) e404(themePath string) revel.Result { // 不知道是谁的404, 则用系统的404 if themePath == "" { - return c.E404(); + return c.E404() } return c.render("404.html", themePath) } @@ -101,24 +100,24 @@ func (c Blog) domain() (ok bool, userBlog info.UserBlog) { // 渲染模板之 func (c Blog) setPreviewUrl() { var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl string - + userId := c.GetUserId() themeId := c.Session["themeId"] theme := themeService.GetTheme(userId, themeId) - + siteUrl := configService.GetSiteUrl() blogUrl := siteUrl + "/preview" // blog.leanote.com userIdOrEmail := userId indexUrl = blogUrl + "/" + userIdOrEmail - cateUrl = blogUrl + "/cate" // /notebookId - - postUrl = blogUrl + "/post" // /xxxxx - searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId - singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId + cateUrl = blogUrl + "/cate" // /notebookId + + postUrl = blogUrl + "/post" // /xxxxx + searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId + singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId - tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId - + tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId + c.RenderArgs["indexUrl"] = indexUrl c.RenderArgs["cateUrl"] = cateUrl c.RenderArgs["postUrl"] = postUrl @@ -127,7 +126,7 @@ func (c Blog) setPreviewUrl() { c.RenderArgs["archiveUrl"] = archiveUrl c.RenderArgs["archivesUrl"] = archiveUrl // 别名 c.RenderArgs["tagsUrl"] = tagsUrl - c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail + c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"] // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的 @@ -137,89 +136,55 @@ func (c Blog) setPreviewUrl() { // 各种地址设置 func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) { // 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com - var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl, staticUrl string host := c.Request.Request.Host - staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0]) + var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0]) // staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com // life.leanote.com, lealife.com siteUrl := configService.GetSiteUrl() - if userBlog.Domain != "" && configService.AllowCustomDomain() { - // ok - indexUrl = configService.GetUserUrl(userBlog.Domain) - cateUrl = indexUrl + "/cate" // /xxxxx - postUrl = indexUrl + "/post" // /xxxxx - searchUrl = indexUrl + "/search" // /xxxxx - singleUrl = indexUrl + "/single" - archiveUrl = indexUrl + "/archives" - tagsUrl = indexUrl + "/tags" - tagPostsUrl = indexUrl + "/tag" - } else if userBlog.SubDomain != "" { - indexUrl = configService.GetUserSubUrl(userBlog.SubDomain) - cateUrl = indexUrl + "/cate" // /xxxxx - postUrl = indexUrl + "/post" // /xxxxx - searchUrl = indexUrl + "/search" // /xxxxx - singleUrl = indexUrl + "/single" - archiveUrl = indexUrl + "/archives" - tagsUrl = indexUrl + "/tags" - tagPostsUrl = indexUrl + "/tag" - } else { - // ok - blogUrl := configService.GetBlogUrl() // blog.leanote.com - userIdOrEmail := "" - if userInfo.Username != "" { - userIdOrEmail = userInfo.Username - } else if userInfo.Email != "" { - userIdOrEmail = userInfo.Email - } else { - userIdOrEmail = userInfo.UserId.Hex() - } - indexUrl = blogUrl + "/" + userIdOrEmail - cateUrl = blogUrl + "/cate" // /notebookId - postUrl = blogUrl + "/post" // /xxxxx - searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId - singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId - archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId - tagsUrl = blogUrl + "/tags/" + userIdOrEmail - tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/userId - } - + blogUrls := blogService.GetBlogUrls(&userBlog, &userInfo) // 分类 // 搜索 // 查看 c.RenderArgs["siteUrl"] = siteUrl - c.RenderArgs["indexUrl"] = indexUrl - c.RenderArgs["cateUrl"] = cateUrl - c.RenderArgs["postUrl"] = postUrl - c.RenderArgs["searchUrl"] = searchUrl - c.RenderArgs["singleUrl"] = singleUrl // 单页 - c.RenderArgs["archiveUrl"] = archiveUrl - c.RenderArgs["archivesUrl"] = archiveUrl // 别名 - c.RenderArgs["tagsUrl"] = tagsUrl - c.RenderArgs["tagPostsUrl"] = tagPostsUrl - c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"] // 别名 + c.RenderArgs["indexUrl"] = blogUrls.IndexUrl + c.RenderArgs["cateUrl"] = blogUrls.CateUrl + c.RenderArgs["postUrl"] = blogUrls.PostUrl + c.RenderArgs["searchUrl"] = blogUrls.SearchUrl + c.RenderArgs["singleUrl"] = blogUrls.SingleUrl // 单页 + c.RenderArgs["archiveUrl"] = blogUrls.ArchiveUrl + c.RenderArgs["archivesUrl"] = blogUrls.ArchiveUrl // 别名 + c.RenderArgs["tagsUrl"] = blogUrls.TagsUrl + c.RenderArgs["tagPostsUrl"] = blogUrls.TagPostsUrl + c.RenderArgs["tagUrl"] = blogUrls.TagPostsUrl // 别名 // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的 c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath // 其它static js c.RenderArgs["jQueryUrl"] = siteUrl + "/js/jquery-1.9.0.min.js" - + c.RenderArgs["prettifyJsUrl"] = siteUrl + "/js/google-code-prettify/prettify.js" c.RenderArgs["prettifyCssUrl"] = siteUrl + "/js/google-code-prettify/prettify.css" - + c.RenderArgs["blogCommonJsUrl"] = siteUrl + "/public/blog/js/common.js" - + c.RenderArgs["shareCommentCssUrl"] = siteUrl + "/public/blog/css/share_comment.css" c.RenderArgs["shareCommentJsUrl"] = siteUrl + "/public/blog/js/share_comment.js" - + c.RenderArgs["fontAwesomeUrl"] = staticUrl + "/css/font-awesome-4.2.0/css/font-awesome.css" - + c.RenderArgs["bootstrapCssUrl"] = siteUrl + "/css/bootstrap.css" c.RenderArgs["bootstrapJsUrl"] = siteUrl + "/js/bootstrap-min.js" } // 笔记本分类 // cates = [{title:"xxx", cateId: "xxxx"}, {}] +func (c Blog) getCateUrlTitle(n *info.Notebook) string { + if n.UrlTitle != "" { + return n.UrlTitle + } + return n.NotebookId.Hex() +} func (c Blog) getCates(userBlog info.UserBlog) { notebooks := blogService.ListBlogNotebooks(userBlog.UserId.Hex()) notebooksMap := map[string]info.Notebook{} @@ -236,7 +201,7 @@ func (c Blog) getCates(userBlog info.UserBlog) { if cateIds != nil && len(cateIds) > 0 { for _, cateId := range cateIds { if n, ok := notebooksMap[cateId]; ok { - cates[i] = map[string]string{"Title": n.Title, "CateId": n.NotebookId.Hex()} + cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": n.NotebookId.Hex()} i++ has[cateId] = true } @@ -246,7 +211,7 @@ func (c Blog) getCates(userBlog info.UserBlog) { for _, n := range notebooks { id := n.NotebookId.Hex() if !has[id] { - cates[i] = map[string]string{"Title": n.Title, "CateId": id} + cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": id} i++ } } @@ -279,39 +244,15 @@ func (c Blog) setBlog(userBlog info.UserBlog, userInfo info.User) { "Logo": userBlog.Logo, "OpenComment": userBlog.CanComment, "CommentType": userBlog.CommentType, // leanote, or disqus - "DisqusId": userBlog.DisqusId, + "DisqusId": userBlog.DisqusId, "ThemeId": userBlog.ThemeId, "SubDomain": userBlog.SubDomain, "Domain": userBlog.Domain, } c.RenderArgs["blogInfo"] = blogInfo - /* - blogInfo := info.BlogInfoCustom{ - UserId: userBlog.UserId.Hex(), - Username: userInfo.Username, - UserLogo: userInfo.Logo, - Title: userBlog.Title, - SubTitle: userBlog.SubTitle, - Logo: userBlog.Logo, - OpenComment: userBlog.CanComment, - CommentType: userBlog.CommentType, // leanote, or disqus - ThemeId: userBlog.ThemeId, - SubDomain: userBlog.SubDomain, - Domain: userBlog.Domain, - } - */ } func (c Blog) setPaging(pageInfo info.Page) { - /* - // 这些分类信息用一个变量 - paging := map[string]interface{}{ // 分页信息 - "CurPage": pageInfo.CurPage, // 当前页 - "TotalPage": pageInfo.TotalPage, // 总页数 - "PerPageSize": pageInfo.PerPageSize, // 每一页的记录数 - "Count": pageInfo.Count, // 总记录数 - } - */ c.RenderArgs["paging"] = pageInfo } @@ -323,13 +264,13 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us return false, userBlog } } -// c.RenderArgs["userInfo"] = userInfo + // c.RenderArgs["userInfo"] = userInfo // 最新笔记 _, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc) - c.RenderArgs["recentPosts"] = c.fixBlogs(recentBlogs) - c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"] - c.RenderArgs["tags"] = blogService.GetBlogTags(userId) + c.RenderArgs["recentPosts"] = blogService.FixBlogs(recentBlogs) + c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"] + c.RenderArgs["tags"] = blogService.GetBlogTags(userId) // 语言, url地址 c.SetLocale() @@ -339,7 +280,7 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us userBlog = blogService.GetUserBlog(userId) } c.setBlog(userBlog, userInfo) -// c.RenderArgs["userBlog"] = userBlog + // c.RenderArgs["userBlog"] = userBlog // 分类导航 c.getCates(userBlog) @@ -352,42 +293,14 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us // 当前分类Id, 全设为"" c.RenderArgs["curCateId"] = "" c.RenderArgs["curSingleId"] = "" - + // 得到主题信息 themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style) - LogJ(themeInfo) c.RenderArgs["themeInfo"] = themeInfo return true, userBlog } -// 修复博客, index, cate用到 -func (c Blog) fixBlog(blog info.BlogItem) info.Post { - blog2 := info.Post{ - NoteId: blog.NoteId.Hex(), - Title: blog.Title, - CreatedTime: blog.CreatedTime, - UpdatedTime: blog.UpdatedTime, - PublicTime: blog.PublicTime, - Desc: blog.Desc, - Abstract: blog.Abstract, - Content: blog.Content, - Tags: blog.Tags, - CommentNum: blog.CommentNum, - ReadNum: blog.ReadNum, - LikeNum: blog.LikeNum, - IsMarkdown: blog.IsMarkdown, - } - return blog2 -} -func (c Blog) fixBlogs(blogs []info.BlogItem) []info.Post { - blogs2 := make([]info.Post, len(blogs)) - for i, blog := range blogs { - blogs2[i] = c.fixBlog(blog) - } - return blogs2 -} - // 404 func (c Blog) E(userIdOrEmail, tag string) revel.Result { ok, userBlog := c.domain() @@ -403,8 +316,8 @@ func (c Blog) E(userIdOrEmail, tag string) revel.Result { userInfo = userService.GetUserInfoByAny(userIdOrEmail) } userId = userInfo.UserId.Hex() - _, userBlog = c.blogCommon(userId, userBlog, userInfo); - + _, userBlog = c.blogCommon(userId, userBlog, userInfo) + return c.e404(userBlog.ThemePath) } @@ -413,10 +326,10 @@ func (c Blog) Tags(userIdOrEmail string) (re revel.Result) { hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() - + userId := "" if hasDomain { userId = userBlog.UserId.Hex() @@ -448,10 +361,10 @@ func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) { hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() - + userId := "" if hasDomain { userId = userBlog.UserId.Hex() @@ -465,23 +378,23 @@ func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) { userInfo = userService.GetUserInfoByAny(userIdOrEmail) } userId = userInfo.UserId.Hex() - + var ok = false if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 } - + if hasDomain && tag == "" { tag = userIdOrEmail } - + c.RenderArgs["curIsTagPosts"] = true c.RenderArgs["curTag"] = tag page := c.GetPage() pageInfo, blogs := blogService.SearchBlogByTags([]string{tag}, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) c.setPaging(pageInfo) - c.RenderArgs["posts"] = c.fixBlogs(blogs) + c.RenderArgs["posts"] = blogService.FixBlogs(blogs) tagPostsUrl := c.RenderArgs["tagPostsUrl"].(string) c.RenderArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag @@ -496,7 +409,7 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re defer func() { if err := recover(); err != nil { fmt.Println(err) - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() userId := "" @@ -532,59 +445,52 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re } c.RenderArgs["curYear"] = year c.RenderArgs["curMonth"] = month - return c.render("archive.html", userBlog.ThemePath) } // 进入某个用户的博客 -// TODO 可以配置, 排序和数目 var blogPageSize = 5 var searchBlogPageSize = 30 - // 分类 /cate/xxxxxxxx?notebookId=1212 -func (c Blog) Cate(notebookId string) (re revel.Result) { +func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { - re = c.e404(userBlog.ThemePath); + fmt.Println(err) + re = c.e404(userBlog.ThemePath) } }() - - if notebookId == "" { - return c.e404(userBlog.ThemePath); - } - userId := "" - if hasDomain { - userId = userBlog.UserId.Hex() - } + userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail) + notebookId2 := notebookId var notebook info.Notebook - notebook = notebookService.GetNotebookById(notebookId) + if userId == "" { // 证明没有userIdOrEmail, 只有singleId, 那么直接查 + notebook = notebookService.GetNotebookById(notebookId) + userId = notebook.UserId.Hex() + } else { + notebook = notebookService.GetNotebookByUserIdAndUrlTitle(userId, notebookId) + notebookId2 = notebook.NotebookId.Hex() + } + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 + } if !notebook.IsBlog { return c.e404("") } - if userId != "" && userId != notebook.UserId.Hex() { - return c.e404("") - } - userId = notebook.UserId.Hex() - - var ok = false - if ok, userBlog = c.blogCommon(userId, userBlog, info.User{}); !ok { - return c.e404(userBlog.ThemePath) - } // 分页的话, 需要分页信息, totalPage, curPage page := c.GetPage() - pageInfo, blogs := blogService.ListBlogs(userId, notebookId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) - blogs2 := c.fixBlogs(blogs) + pageInfo, blogs := blogService.ListBlogs(userId, notebookId2, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) + blogs2 := blogService.FixBlogs(blogs) c.RenderArgs["posts"] = blogs2 c.setPaging(pageInfo) c.RenderArgs["curCateTitle"] = notebook.Title - c.RenderArgs["curCateId"] = notebookId + c.RenderArgs["curCateId"] = notebookId2 cateUrl := c.RenderArgs["cateUrl"].(string) c.RenderArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId c.RenderArgs["curIsCate"] = true @@ -592,31 +498,37 @@ func (c Blog) Cate(notebookId string) (re revel.Result) { return c.render("cate.html", userBlog.ThemePath) } +func (c Blog) userIdOrEmail(hasDomain bool, userBlog info.UserBlog, userIdOrEmail string) (userId string, userInfo info.User) { + userId = "" + if hasDomain { + userId = userBlog.UserId.Hex() + } + if userId != "" { + userInfo = userService.GetUserInfoByAny(userId) + } else { + if userIdOrEmail != "" { + userInfo = userService.GetUserInfoByAny(userIdOrEmail) + } else { + return + } + } + userId = userInfo.UserId.Hex() + return +} + func (c Blog) Index(userIdOrEmail string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() - userId := "" - if hasDomain { - userId = userBlog.UserId.Hex() - } - - // 用户id为空, 转至博客平台 + // 用户id为空, 则是admin用户的博客 if userIdOrEmail == "" { userIdOrEmail = configService.GetAdminUsername() } - var userInfo info.User - if userId != "" { - userInfo = userService.GetUserInfoByAny(userId) - } else { - userInfo = userService.GetUserInfoByAny(userIdOrEmail) - } - userId = userInfo.UserId.Hex() - + userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail) var ok = false if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 @@ -625,7 +537,7 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) { // 分页的话, 需要分页信息, totalPage, curPage page := c.GetPage() pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) - blogs2 := c.fixBlogs(blogs) + blogs2 := blogService.FixBlogs(blogs) c.RenderArgs["posts"] = blogs2 c.setPaging(pageInfo) @@ -636,66 +548,36 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) { return c.render("index.html", userBlog.ThemePath) } -// 详情 -// 为了上一篇, 下一篇 -func (c Blog) fixNote(note info.Note) map[string]interface{} { - if note.NoteId == "" { - return nil - } - return map[string]interface{}{ - "NoteId": note.NoteId.Hex(), - "Title": note.Title, - "CreatedTime": note.CreatedTime, - "UpdatedTime": note.UpdatedTime, - "PublicTime": note.PublicTime, - "Desc": note.Desc, - "Tags": note.Tags, - "CommentNum": note.CommentNum, - "ReadNum": note.ReadNum, - "LikeNum": note.LikeNum, - "IsMarkdown": note.IsMarkdown, - } -} - -func (c Blog) Post(noteId string) (re revel.Result) { +func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { Log(err) - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() - userId := "" - if hasDomain { - userId = userBlog.UserId.Hex() + + userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail) + var blogInfo info.BlogItem + if userId == "" { // 证明没有userIdOrEmail, 只有singleId, 那么直接查 + blogInfo = blogService.GetBlog(noteId) + userId = blogInfo.UserId.Hex() + } else { + blogInfo = blogService.GetBlogByIdAndUrlTitle(userId, noteId) + } + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 + } + if blogInfo.NoteId == "" { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 } - blogInfo := blogService.GetBlog(noteId) - userInfo := userService.GetUserInfo(blogInfo.UserId.Hex()) - if userId != "" && userInfo.UserId.Hex() != userId { - panic("error") - } - - userId = userInfo.UserId.Hex() - _, userBlog = c.blogCommon(userId, userBlog, info.User{}) - - c.RenderArgs["post"] = c.fixBlog(blogInfo) + c.RenderArgs["post"] = blogService.FixBlog(blogInfo) // c.RenderArgs["userInfo"] = userInfo c.RenderArgs["curIsPost"] = true - // 得到访问者id - /* - visitUserId := c.GetUserId() - if visitUserId != "" { - visitUserInfo := userService.GetUserInfo(visitUserId) - c.RenderArgs["visitUserInfoJson"] = c.Json(visitUserInfo) - c.RenderArgs["visitUserInfo"] = visitUserInfo - } else { - c.RenderArgs["visitUserInfoJson"] = "{}" - } - */ - // 上一篇, 下一篇 var baseTime interface{} if userBlog.SortField == "PublicTime" { @@ -708,44 +590,46 @@ func (c Blog) Post(noteId string) (re revel.Result) { baseTime = blogInfo.Title } - preNote, nextNote := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, baseTime) - c.RenderArgs["prePost"] = c.fixNote(preNote) - c.RenderArgs["nextPost"] = c.fixNote(nextNote) - Log("---------") + prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, baseTime) + c.RenderArgs["prePost"] = prePost + c.RenderArgs["nextPost"] = nextPost return c.render("post.html", userBlog.ThemePath) } -func (c Blog) Single(singleId string) (re revel.Result) { +func (c Blog) Single(userIdOrEmail, singleId string) (re revel.Result) { // 自定义域名 hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() - - userId := "" - if hasDomain { - userId = userBlog.UserId.Hex() - } - single := blogService.GetSingle(singleId) - userInfo := userService.GetUserInfo(single.UserId.Hex()) - if userId != "" && userInfo.UserId.Hex() != userId { - return c.e404(userBlog.ThemePath) + userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail) + var single info.BlogSingle + if userId == "" { // 证明没有userIdOrEmail, 只有singleId, 那么直接查 + single = blogService.GetSingle(singleId) + userId = single.UserId.Hex() + } else { + single = blogService.GetSingleByUserIdAndUrlTitle(userId, singleId) + } + var ok = false + if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { + return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404 + } + if single.SingleId == "" { + panic("") } - - userId = userInfo.UserId.Hex() - _, userBlog = c.blogCommon(userId, userBlog, info.User{}) c.RenderArgs["single"] = map[string]interface{}{ "SingleId": single.SingleId.Hex(), "Title": single.Title, + "UrlTitle": single.UrlTitle, "Content": single.Content, "CreatedTime": single.CreatedTime, "UpdatedTime": single.UpdatedTime, } - c.RenderArgs["curSingleId"] = singleId + c.RenderArgs["curSingleId"] = single.SingleId.Hex() c.RenderArgs["curIsSingle"] = true return c.render("single.html", userBlog.ThemePath) @@ -757,7 +641,7 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) { hasDomain, userBlog := c.domain() defer func() { if err := recover(); err != nil { - re = c.e404(userBlog.ThemePath); + re = c.e404(userBlog.ThemePath) } }() userId := "" @@ -771,7 +655,7 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) { } else { userInfo = userService.GetUserInfoByAny(userIdOrEmail) } -// c.RenderArgs["userInfo"] = userInfo + // c.RenderArgs["userInfo"] = userInfo userId = userInfo.UserId.Hex() var ok = false if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok { @@ -782,7 +666,7 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) { pageInfo, blogs := blogService.SearchBlog(keywords, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc) c.setPaging(pageInfo) - c.RenderArgs["posts"] = c.fixBlogs(blogs) + c.RenderArgs["posts"] = blogService.FixBlogs(blogs) c.RenderArgs["keywords"] = keywords searchUrl, _ := c.RenderArgs["searchUrl"].(string) c.RenderArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords @@ -808,7 +692,7 @@ func (c Blog) GetPostStat(noteId string) revel.Result { re.Ok = true statInfo := blogService.GetBlogStat(noteId) re.Item = statInfo - return c.RenderJson(re); + return c.RenderJson(re) } // jsonP @@ -819,7 +703,7 @@ func (c Blog) GetLikes(noteId string, callback string) revel.Result { userId := c.GetUserId() result := map[string]interface{}{} isILikeIt := false - if userId != "" { + if userId != "" { isILikeIt = blogService.IsILikeIt(noteId, userId) result["visitUserInfo"] = userService.GetUserAndBlog(userId) } @@ -841,11 +725,11 @@ func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result { // 我也点过? isILikeIt := false - if userId != "" { + if userId != "" { isILikeIt = blogService.IsILikeIt(noteId, userId) result["visitUserInfo"] = userService.GetUserAndBlog(userId) } - + // 点赞用户列表 likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false) // 评论 @@ -892,18 +776,21 @@ func (c Blog) GetComments(noteId string) revel.Result { return c.RenderJson(re) } + // jsonp func (c Blog) DeleteComment(noteId, commentId string, callback string) revel.Result { re := info.NewRe() re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId()) return c.RenderJsonP(callback, re) } + // jsonp func (c Blog) CommentPost(noteId, content, toCommentId string, callback string) revel.Result { re := info.NewRe() re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content) return c.RenderJsonP(callback, re) } + // jsonp func (c Blog) LikeComment(commentId string, callback string) revel.Result { re := info.NewRe() diff --git a/app/controllers/IndexController.go b/app/controllers/IndexController.go index b6a86a6..bc4b86d 100644 --- a/app/controllers/IndexController.go +++ b/app/controllers/IndexController.go @@ -14,6 +14,10 @@ type Index struct { // leanote展示页, 没有登录的, 或已登录明确要进该页的 func (c Index) Index() revel.Result { + if configService.HomePageIsAdminsBlog(){ + blog := Blog{c.BaseController} + return blog.Index(configService.GetAdminUsername()); + } c.SetUserInfo() c.RenderArgs["title"] = "leanote" c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"] diff --git a/app/controllers/PreviewController.go b/app/controllers/PreviewController.go index c049f56..03cfca9 100644 --- a/app/controllers/PreviewController.go +++ b/app/controllers/PreviewController.go @@ -71,25 +71,25 @@ func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month i return c.Blog.Archives(c.GetUserId(), notebookId, year, month) // return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) } -func (c Preview) Cate(notebookId string) revel.Result { +func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result { if !c.getPreviewThemeAbsolutePath("") { return c.E404() } - return c.Blog.Cate(notebookId) + return c.Blog.Cate(userIdOrEmail, notebookId) // return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) } -func (c Preview) Post(noteId string) revel.Result { +func (c Preview) Post(userIdOrEmail, noteId string) revel.Result { if !c.getPreviewThemeAbsolutePath("") { return c.E404() } - return c.Blog.Post(noteId) + return c.Blog.Post(userIdOrEmail, noteId) // return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) } -func (c Preview) Single(singleId string) revel.Result { +func (c Preview) Single(userIdOrEmail, singleId string) revel.Result { if !c.getPreviewThemeAbsolutePath("") { return c.E404() } - return c.Blog.Single(singleId) + return c.Blog.Single(userIdOrEmail, singleId) // return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath("")) } func (c Preview) Search(userIdOrEmail, keywords string) revel.Result { diff --git a/app/controllers/ShareController.go b/app/controllers/ShareController.go index 15dc17c..9630b0b 100644 --- a/app/controllers/ShareController.go +++ b/app/controllers/ShareController.go @@ -4,7 +4,7 @@ import ( "github.com/revel/revel" // "encoding/json" // "gopkg.in/mgo.v2/bson" -// . "github.com/leanote/leanote/app/lea" + . "github.com/leanote/leanote/app/lea" "github.com/leanote/leanote/app/info" // "github.com/leanote/leanote/app/types" // "io/ioutil" @@ -87,6 +87,8 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result { noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId()) c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos + c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId()) + c.RenderArgs["isNote"] = true c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex(); c.RenderArgs["title"] = note.Title @@ -99,6 +101,9 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result { notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId()) c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos + c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId()) + LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"]) + c.RenderArgs["isNote"] = false c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex(); c.RenderArgs["title"] = notebook.Title @@ -139,4 +144,45 @@ func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId str // 删除fromUserId分享给我的所有note, notebook func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result { return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId())); +} + +//------------- +// 用户组 + + +// 将笔记分享给分组 +func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result { + re := info.NewRe() + re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm); + return c.RenderJson(re); +} +// 删除 +func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result { + re := info.NewRe() + re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId); + return c.RenderJson(re); +} +// 更新, 也是一样, 先删后加 +func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result { + return c.AddShareNoteGroup(noteId, groupId, perm) +} + + +//------ + +// 将笔记分享给分组 +func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result { + re := info.NewRe() + re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm); + return c.RenderJson(re); +} +// 删除 +func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result { + re := info.NewRe() + re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId); + return c.RenderJson(re); +} +// 更新, 也是一样, 先删后加 +func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result { + return c.AddShareNotebookGroup(notebookId, groupId, perm) } \ No newline at end of file diff --git a/app/controllers/admin/AdminBlogController.go b/app/controllers/admin/AdminBlogController.go index 9843938..ca8a48d 100644 --- a/app/controllers/admin/AdminBlogController.go +++ b/app/controllers/admin/AdminBlogController.go @@ -16,7 +16,7 @@ type AdminBlog struct { func (c AdminBlog) Index(sorter, keywords string) revel.Result { pageNumber := c.GetPage() sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"}); - pageInfo, blogs := blogService.ListAllBlogs("", keywords, false, pageNumber, userPageSize, sorterField, isAsc); + pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc); c.RenderArgs["pageInfo"] = pageInfo c.RenderArgs["blogs"] = blogs c.RenderArgs["keywords"] = keywords @@ -27,4 +27,4 @@ func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result { re := info.NewRe() re.Ok = blogService.SetRecommend(noteId, recommend); return c.RenderJson(re) -} \ No newline at end of file +} diff --git a/app/controllers/admin/AdminController.go b/app/controllers/admin/AdminController.go index dad63d1..c3215a5 100644 --- a/app/controllers/admin/AdminController.go +++ b/app/controllers/admin/AdminController.go @@ -30,6 +30,7 @@ func (c Admin) T(t string) revel.Result { c.RenderArgs["arr"] = configService.GlobalArrayConfigs c.RenderArgs["map"] = configService.GlobalMapConfigs c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs + c.RenderArgs["version"] = configService.GetVersion() return c.RenderTemplate("admin/" + t + ".html") } diff --git a/app/controllers/admin/AdminSettingController.go b/app/controllers/admin/AdminSettingController.go index f36e892..8a4ce51 100644 --- a/app/controllers/admin/AdminSettingController.go +++ b/app/controllers/admin/AdminSettingController.go @@ -111,6 +111,15 @@ func (c AdminSetting) OpenRegister(openRegister string) revel.Result { return c.RenderJson(re) } +func (c AdminSetting) HomePage(homePage string) revel.Result { + re := info.NewRe() + if homePage == "0" { + homePage = "" + } + re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage) + return c.RenderJson(re) +} + func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result { re := info.NewRe() re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath) diff --git a/app/controllers/admin/AdminUpgradeController.go b/app/controllers/admin/AdminUpgradeController.go index 8580acf..3835d68 100644 --- a/app/controllers/admin/AdminUpgradeController.go +++ b/app/controllers/admin/AdminUpgradeController.go @@ -17,8 +17,8 @@ func (c AdminUpgrade) UpgradeBlog() revel.Result { return nil; } -func (c AdminUpgrade) UpgradeBetaToSelfBlog() revel.Result { +func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result { re := info.NewRe() - re.Ok, re.Msg = upgradeService.UpgradeBetaToSelfBlog(c.GetUserId()) + re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId()) return c.RenderJson(re) -} +} \ No newline at end of file diff --git a/app/controllers/member/MemberBlogController.go b/app/controllers/member/MemberBlogController.go index 9dca66c..daa75b5 100644 --- a/app/controllers/member/MemberBlogController.go +++ b/app/controllers/member/MemberBlogController.go @@ -8,10 +8,11 @@ import ( "io/ioutil" "time" "fmt" + "strings" // "github.com/leanote/leanote/app/lea/blog" ) -// admin 首页 +// 博客管理 type MemberBlog struct { MemberBaseController @@ -33,6 +34,82 @@ func (c MemberBlog) common() info.UserBlog { return userBlog } + +// 得到sorterField 和 isAsc +// okSorter = ['email', 'username'] +func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){ + sorter := "" + c.Params.Bind(&sorter, "sorter") + if sorter == "" { + return sorterField, isAsc; + } + + // sorter形式 email-up, email-down + s2 := strings.Split(sorter, "-") + if len(s2) != 2 { + return sorterField, isAsc; + } + + // 必须是可用的sorter + if okSorter != nil && len(okSorter) > 0 { + if !InArray(okSorter, s2[0]) { + return sorterField, isAsc; + } + } + + sorterField = strings.Title(s2[0]) + if s2[1] == "up" { + isAsc = true + } else { + isAsc = false + } + c.RenderArgs["sorter"] = sorter + return sorterField, isAsc; +} + +// 博客列表 +var userPageSize = 15 +func (c MemberBlog) Index(sorter, keywords string) revel.Result { + c.RenderArgs["title"] = "Posts" + pageNumber := c.GetPage() + sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"}); + pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc); + c.RenderArgs["pageInfo"] = pageInfo + c.RenderArgs["blogs"] = blogs + c.RenderArgs["keywords"] = keywords + + userAndBlog := userService.GetUserAndBlog(c.GetUserId()) + c.RenderArgs["userAndBlog"] = userAndBlog + + return c.RenderTemplate("member/blog/list.html"); +} + +// 修改笔记的urlTitle +func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result { + re := info.NewRe() + re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle) + return c.RenderJson(re) +} + + +// 修改笔记的urlTitle +func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result { + c.RenderArgs["title"] = "Update Post Abstract" + note := noteService.GetNoteAndContent(noteId, c.GetUserId()); + if !note.Note.IsBlog { + return c.E404(); + } + c.RenderArgs["note"] = note + c.RenderArgs["noteId"] = noteId + return c.RenderTemplate("member/blog/update_abstract.html"); +} +func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result { + + re := info.NewRe() + re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract) + return c.RenderJson(re) +} + // 基本信息设置 func (c MemberBlog) Base() revel.Result { c.common() @@ -101,6 +178,12 @@ func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result { return c.RenderJson(re) } +func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result { + re := info.NewRe() + re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle) + return c.RenderJson(re) +} + // 保存之, 包含增加与保存 func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result { re := info.NewRe() @@ -127,6 +210,14 @@ func (c MemberBlog) DeleteSingle(singleId string) revel.Result { re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId) return c.RenderJson(re) } + +// 修改页面标题 +func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result { + re := info.NewRe() + re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle) + return c.RenderJson(re) +} + func (c MemberBlog) Single() revel.Result { c.common() c.RenderArgs["title"] = "Cate" @@ -425,4 +516,4 @@ func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc b re := info.NewRe() re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc) return c.RenderRe(re) -} \ No newline at end of file +} diff --git a/app/controllers/member/MemberGroupController.go b/app/controllers/member/MemberGroupController.go new file mode 100644 index 0000000..815857d --- /dev/null +++ b/app/controllers/member/MemberGroupController.go @@ -0,0 +1,58 @@ +package member + +import ( + "github.com/revel/revel" + "github.com/leanote/leanote/app/info" +) + +// 分组管理 +type MemberGroup struct { + MemberBaseController +} + +// 首页, 显示所有分组和用户 +func (c MemberGroup) Index() revel.Result { + c.SetUserInfo() + c.SetLocale() + c.RenderArgs["title"] = "My Group" + c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId()) + return c.RenderTemplate("member/group/index.html"); +} + +// 添加分组 +func (c MemberGroup) AddGroup(title string) revel.Result { + re := info.NewRe() + re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title) + return c.RenderJson(re) +} + +func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result { + re := info.NewRe() + re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title) + return c.RenderJson(re) +} + +func (c MemberGroup) DeleteGroup(groupId string) revel.Result { + re := info.NewRe() + re.Ok, re.Msg = groupService.DeleteGroup(c.GetUserId(), groupId) + return c.RenderJson(re) +} + +// 添加用户 +func (c MemberGroup) AddUser(groupId, email string) revel.Result { + re := info.NewRe() + userInfo := userService.GetUserInfoByAny(email) + if userInfo.UserId == "" { + re.Msg = "userNotExists" + } else { + re.Ok, re.Msg = groupService.AddUser(c.GetUserId(), groupId, userInfo.UserId.Hex()) + re.Item = userInfo + } + return c.RenderRe(re) +} + +func (c MemberGroup) DeleteUser(groupId, userId string) revel.Result { + re := info.NewRe() + re.Ok, re.Msg = groupService.DeleteUser(c.GetUserId(), groupId, userId) + return c.RenderRe(re) +} diff --git a/app/controllers/member/init.go b/app/controllers/member/init.go index 2737265..d891db2 100644 --- a/app/controllers/member/init.go +++ b/app/controllers/member/init.go @@ -9,6 +9,7 @@ import ( ) var userService *service.UserService +var groupService *service.GroupService var noteService *service.NoteService var trashService *service.TrashService var notebookService *service.NotebookService @@ -106,6 +107,7 @@ func InitService() { trashService = service.TrashS shareService = service.ShareS userService = service.UserS + groupService = service.GroupS tagService = service.TagS blogService = service.BlogS tokenService = service.TokenS diff --git a/app/info/BlogCustom.go b/app/info/BlogCustom.go index 0da02b8..c309c21 100644 --- a/app/info/BlogCustom.go +++ b/app/info/BlogCustom.go @@ -23,6 +23,8 @@ type BlogInfoCustom struct { type Post struct { NoteId string Title string + UrlTitle string + ImgSrc string CreatedTime time.Time UpdatedTime time.Time PublicTime time.Time diff --git a/app/info/BlogInfo.go b/app/info/BlogInfo.go index 68eaef3..24dafae 100644 --- a/app/info/BlogInfo.go +++ b/app/info/BlogInfo.go @@ -74,9 +74,10 @@ type BlogStat struct { // 单页 type BlogSingle struct { - SingleId bson.ObjectId `bson:"_id"` + SingleId bson.ObjectId `bson:"_id,omitempty"` UserId bson.ObjectId `UserId` Title string `Title` + UrlTitle string `UrlTitle` // 2014/11/11 Content string `Content` UpdatedTime time.Time `UpdatedTime` CreatedTime time.Time `CreatedTime` @@ -87,7 +88,7 @@ type BlogSingle struct { // 点赞记录 type BlogLike struct { - LikeId bson.ObjectId `bson:"_id"` + LikeId bson.ObjectId `bson:"_id,omitempty"` NoteId bson.ObjectId `NoteId` UserId bson.ObjectId `UserId` CreatedTime time.Time `CreatedTime` @@ -95,7 +96,7 @@ type BlogLike struct { // 评论 type BlogComment struct { - CommentId bson.ObjectId `bson:"_id"` + CommentId bson.ObjectId `bson:"_id,omitempty"` NoteId bson.ObjectId `NoteId` UserId bson.ObjectId `UserId` // UserId回复ToUserId @@ -114,3 +115,14 @@ type BlogCommentPublic struct { BlogComment IsILikeIt bool } + +type BlogUrls struct { + IndexUrl string + CateUrl string + SearchUrl string + SingleUrl string + PostUrl string + ArchiveUrl string + TagsUrl string + TagPostsUrl string +} diff --git a/app/info/GroupInfo.go b/app/info/GroupInfo.go new file mode 100644 index 0000000..e75b352 --- /dev/null +++ b/app/info/GroupInfo.go @@ -0,0 +1,25 @@ +package info + +import ( + "gopkg.in/mgo.v2/bson" + "time" +) + +// 分组 +type Group struct { + GroupId bson.ObjectId `bson:"_id"` // 谁的 + UserId bson.ObjectId `UserId` // 所有者Id + Title string `Title` // 标题 + UserCount int `UserCount` // 用户数 + CreatedTime time.Time `CreatedTime` + + Users []User `Users,omitempty` // 分组下的用户, 不保存, 仅查看 +} + +// 分组好友 +type GroupUser struct { + GroupUserId bson.ObjectId `bson:"_id"` // 谁的 + GroupId bson.ObjectId `GroupId` // 分组 + UserId bson.ObjectId `UserId` // 用户 + CreatedTime time.Time `CreatedTime` +} diff --git a/app/info/NoteInfo.go b/app/info/NoteInfo.go index e8560e0..a1bce49 100644 --- a/app/info/NoteInfo.go +++ b/app/info/NoteInfo.go @@ -20,9 +20,11 @@ type Note struct { IsTrash bool `IsTrash` // 是否是trash, 默认是false - IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加 - IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加 - IsTop bool `IsTop,omitempty` // blog是否置顶 + IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加 + UrlTitle string `UrlTitle,omitempty` // 博客的url标题, 为了更友好的url, 在UserId, UrlName下唯一 + IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加 + IsTop bool `IsTop,omitempty` // blog是否置顶 + HasSelfDefined bool `HasSelfDefined` // 是否已经自定义博客图片, desc, abstract // 2014/9/28 添加评论社交功能 ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28 @@ -35,9 +37,9 @@ type Note struct { CreatedTime time.Time `CreatedTime` UpdatedTime time.Time `UpdatedTime` - RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间 - PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置 - UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了 + RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间 + PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置 + UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了 } // 内容 diff --git a/app/info/NotebookInfo.go b/app/info/NotebookInfo.go index 8275c9f..8d0db19 100644 --- a/app/info/NotebookInfo.go +++ b/app/info/NotebookInfo.go @@ -13,6 +13,7 @@ type Notebook struct { ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级 Seq int `Seq` // 排序 Title string `Title` // 标题 + UrlTitle string `UrlTitle` // Url标题 2014/11.11加 NumberNotes int `NumberNotes` // 笔记数 IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加 diff --git a/app/info/ShareNotebookNoteInfo.go b/app/info/ShareNotebookNoteInfo.go index dfea67b..401b720 100644 --- a/app/info/ShareNotebookNoteInfo.go +++ b/app/info/ShareNotebookNoteInfo.go @@ -76,7 +76,9 @@ type SharingNotebookAndNotes struct { type ShareNotebook struct { ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 UserId bson.ObjectId `bson:"UserId"` - ToUserId bson.ObjectId `bson:"ToUserId"` + ToUserId bson.ObjectId `bson:"ToUserId,omitempty"` + ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组 + ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息 NotebookId bson.ObjectId `bson:"NotebookId"` Seq int `bson:"Seq"` // 排序 Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改 @@ -134,7 +136,9 @@ type ShareNotebooksByUser struct { type ShareNote struct { ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 UserId bson.ObjectId `bson:"UserId"` - ToUserId bson.ObjectId `bson:"ToUserId"` + ToUserId bson.ObjectId `bson:"ToUserId,omitempty"` + ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组 + ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息 NoteId bson.ObjectId `bson:"NoteId"` Perm int `bson:"Perm"` // 权限, 0只读, 1可修改 CreatedTime time.Time `CreatedTime` diff --git a/app/info/UserInfo.go b/app/info/UserInfo.go index 8a406d5..7d4e49d 100644 --- a/app/info/UserInfo.go +++ b/app/info/UserInfo.go @@ -74,5 +74,7 @@ type UserAndBlog struct { Logo string `Logo` BlogTitle string `BlogTitle` // 博客标题 BlogLogo string `BlogLogo` // 博客Logo - BlogUrl string `BlogUrl` // 博客链接 + BlogUrl string `BlogUrl` // 博客链接, 主页 + + BlogUrls // 各个页面 } diff --git a/app/info/common.go b/app/info/common.go index 3ea4521..25ef0e0 100644 --- a/app/info/common.go +++ b/app/info/common.go @@ -9,6 +9,7 @@ import ( type Page struct { CurPage int // 当前页码 TotalPage int // 总页 + PerPageSize int Count int // 总记录数 List interface{} } @@ -18,5 +19,5 @@ func NewPage(page, perPageSize, count int, list interface{}) Page { if count > 0 { totalPage = int(math.Ceil(float64(count) / float64(perPageSize))) } - return Page{page, totalPage, count, list} -} \ No newline at end of file + return Page{page, totalPage, perPageSize, count, list} +} diff --git a/app/init.go b/app/init.go index f491511..a0cb922 100644 --- a/app/init.go +++ b/app/init.go @@ -20,6 +20,7 @@ import ( "strconv" "time" "encoding/json" + "net/url" ) func init() { @@ -78,6 +79,10 @@ func init() { } return str } + revel.TemplateFuncs["decodeUrlValue"] = func(i string) string { + v, _ := url.ParseQuery("a=" + i) + return v.Get("a") + } revel.TemplateFuncs["json"] = func(i interface{}) string { b, _ := json.Marshal(i) return string(b) @@ -318,4 +323,4 @@ func init() { member.InitService() service.ConfigS.InitGlobalConfigs() }) -} \ No newline at end of file +} diff --git a/app/service/AuthService.go b/app/service/AuthService.go index 1d4e66a..6e4fd24 100644 --- a/app/service/AuthService.go +++ b/app/service/AuthService.go @@ -35,7 +35,7 @@ func (this *AuthService) Login(emailOrUsername, pwd string) info.User { func (this *AuthService) Register(email, pwd string) (bool, string) { // 用户是否已存在 if userService.IsExistsUser(email) { - return false, email + " 已被注册" + return false, "userHasBeenRegistered-" + email } user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)} return this.register(user) @@ -90,7 +90,10 @@ func (this *AuthService) register(user info.User) (bool, string) { Title: user.Username + " 's Blog", SubTitle: "love leanote!", AboutMe: "Hello, I am (^_^)", + CanComment: true, }) + // 添加一个单页面 + blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)") } return true, "" diff --git a/app/service/BlogService.go b/app/service/BlogService.go index 33a2105..789a519 100644 --- a/app/service/BlogService.go +++ b/app/service/BlogService.go @@ -1,16 +1,15 @@ package service import ( - "github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/db" + "github.com/leanote/leanote/app/info" . "github.com/leanote/leanote/app/lea" -// "github.com/leanote/leanote/app/lea/netutil" "gopkg.in/mgo.v2/bson" -// "time" -// "sort" + // "time" + // "sort" + "strconv" "strings" "time" - "strconv" ) // blog @@ -39,20 +38,33 @@ func (this *BlogService) GetBlogStat(noteId string) (stat info.BlogStat) { stat = info.BlogStat{note.NoteId, note.ReadNum, note.LikeNum, note.CommentNum} return } + +// 通过id或urlTitle得到博客 +func (this *BlogService) GetBlogByIdAndUrlTitle(userId string, noteIdOrUrlTitle string) (blog info.BlogItem) { + if IsObjectId(noteIdOrUrlTitle) { + return this.GetBlog(noteIdOrUrlTitle) + } + note := info.Note{} + db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle), "IsBlog": true, "IsTrash": false}, ¬e) + return this.GetBlogItem(note) +} + // 得到某博客具体信息 func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) { note := noteService.GetBlogNote(noteId) - + return this.GetBlogItem(note) +} +func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) { if note.NoteId == "" || !note.IsBlog { return } - + // 内容 noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex()) - + // 组装成blogItem - blog = info.BlogItem{note, noteContent.Abstract, noteContent.Content, false, info.User{}} - + blog = info.BlogItem{note, noteContent.Abstract, noteContent.Content, false, info.User{}} + return } @@ -66,18 +78,18 @@ func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook { // 博客列表 // userId 表示谁的blog func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) { - count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true); - - if(notes == nil || len(notes) == 0) { + count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true) + + if notes == nil || len(notes) == 0 { return info.Page{}, nil } - + // 得到content, 并且每个都要substring noteIds := make([]bson.ObjectId, len(notes)) for i, note := range notes { noteIds[i] = note.NoteId } - + // 直接得到noteContents表的abstract // 这里可能是乱序的 noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent] @@ -85,7 +97,7 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int for _, noteContent := range noteContents { noteContentsMap[noteContent.NoteId] = noteContent } - + // 组装成blogItem // 按照notes的顺序 blogs := make([]info.BlogItem, len(noteIds)) @@ -99,9 +111,9 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int } blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}} } - + pageInfo := info.NewPage(page, pageSize, count, nil) - + return pageInfo, blogs } @@ -111,25 +123,26 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int {Tag:xxx, Count: 32} ] */ -func (this *BlogService) GetBlogTags(userId string) ([]info.TagCount) { +func (this *BlogService) GetBlogTags(userId string) []info.TagCount { // 得到所有博客 tagCounts := []info.TagCount{} query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true} db.TagCounts.Find(query).Sort("-Count").All(&tagCounts) return tagCounts } + // 重新计算博客的标签 -// 在设置设置/取消为博客时调用 -func (this *BlogService) ReCountBlogTags(userId string) (bool) { +// 在设置设置/取消为博客时调用 +func (this *BlogService) ReCountBlogTags(userId string) bool { // 得到所有博客 notes := []info.Note{} userIdO := bson.ObjectIdHex(userId) query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true} db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es) - - db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true}); - if(notes == nil || len(notes) == 0) { - return true + + db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true}) + if notes == nil || len(notes) == 0 { + return true } // 统计所有的Tags和数目 tagsCount := map[string]int{} @@ -145,11 +158,12 @@ func (this *BlogService) ReCountBlogTags(userId string) (bool) { } // 一个个插入 for tag, count := range tagsCount { - db.Insert(db.TagCounts, + db.Insert(db.TagCounts, info.TagCount{UserId: userIdO, IsBlog: true, Tag: tag, Count: count}) } return true } + // 归档博客 /* 数据: 按年汇总 @@ -157,14 +171,14 @@ func (this *BlogService) ReCountBlogTags(userId string) (bool) { archive1, archive2, ] -archive的数据类型是 +archive的数据类型是 { Year: 2014 Posts: [] } */ -func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) ([]info.Archive) { -// _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true); +func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) []info.Archive { + // _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true); q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false} if notebookId != "" { q["NotebookId"] = bson.ObjectIdHex(notebookId) @@ -192,18 +206,18 @@ func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month q["PublicTime"] = bson.M{"$gte": leftT, "$lt": rightT} } } - + sorter := sortField if !isAsc { sorter = "-" + sortField } notes := []info.Note{} db.Notes.Find(q).Sort(sorter).All(¬es) - - if(notes == nil || len(notes) == 0) { + + if notes == nil || len(notes) == 0 { return nil } - + arcs := []info.Archive{} // 按年汇总 arcsMap := map[int]info.Archive{} @@ -225,41 +239,31 @@ func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month if everYear == 0 { everYear = year } - + if everYear != year { yearArc := arcsMap[everYear] yearArc.MonthAchives = arcsMonth arcs = append(arcs, yearArc) everYear = year - + // 新的一年 arcsMonth = []info.ArchiveMonth{} } - + if arcT, ok := arcsMap[year]; ok { arc = arcT } else { arc = info.Archive{Year: year, Posts: []*info.Post{}} } - p := &info.Post{ - NoteId: note.NoteId.Hex(), - Title: note.Title, - CreatedTime: note.CreatedTime, - UpdatedTime: note.UpdatedTime, - PublicTime: note.PublicTime, - Desc: note.Desc, - Tags: note.Tags, - CommentNum: note.CommentNum, - ReadNum: note.ReadNum, - LikeNum: note.LikeNum, - IsMarkdown: note.IsMarkdown, - } - arc.Posts = append(arc.Posts, p); + + pt := this.FixNote(note) + p := &pt + arc.Posts = append(arc.Posts, p) arcsMap[year] = arc - + // month lm := len(arcsMonth) - if(lm == 0 || arcsMonth[lm-1].Month != month) { + if lm == 0 || arcsMonth[lm-1].Month != month { arcsMonth = append(arcsMonth, info.ArchiveMonth{month, []*info.Post{p}}) } else { arcsMonth[lm-1].Posts = append(arcsMonth[lm-1].Posts, p) @@ -271,7 +275,7 @@ func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month yearArc.MonthAchives = arcsMonth arcs = append(arcs, yearArc) } - + return arcs } @@ -279,39 +283,39 @@ func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumber, pageSize int, sortField string, isAsc bool) (pageInfo info.Page, blogs []info.BlogItem) { notes := []info.Note{} skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc) - + // 不是trash的 - query := bson.M{"UserId": bson.ObjectIdHex(userId), - "IsTrash": false, - "IsBlog": true, - "Tags": bson.M{"$all": tags}} - - q := db.Notes.Find(query); - + query := bson.M{"UserId": bson.ObjectIdHex(userId), + "IsTrash": false, + "IsBlog": true, + "Tags": bson.M{"$all": tags}} + + q := db.Notes.Find(query) + // 总记录数 count, _ := q.Count() if count == 0 { return } - + q.Sort(sortFieldR). Skip(skipNum). Limit(pageSize). All(¬es) - + blogs = this.notes2BlogItems(notes) pageInfo = info.NewPage(pageNumber, pageSize, count, nil) - + return } -func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem{ +func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem { // 得到content, 并且每个都要substring noteIds := make([]bson.ObjectId, len(notes)) for i, note := range notes { noteIds[i] = note.NoteId } - + // 直接得到noteContents表的abstract // 这里可能是乱序的 noteContents := noteService.ListNoteContentByNoteIds(noteIds) // 返回[info.NoteContent] @@ -319,7 +323,7 @@ func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem{ for _, noteContent := range noteContents { noteContentsMap[noteContent.NoteId] = noteContent } - + // 组装成blogItem // 按照notes的顺序 blogs := make([]info.BlogItem, len(noteIds)) @@ -335,12 +339,12 @@ func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem{ return blogs } func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) { - count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true); - - if(notes == nil || len(notes) == 0) { + count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true) + + if notes == nil || len(notes) == 0 { return info.Page{}, nil } - + blogs := this.notes2BlogItems(notes) pageInfo := info.NewPage(page, pageSize, count, nil) return pageInfo, blogs @@ -349,18 +353,18 @@ func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sort // 上一篇文章, 下一篇文章 // sorterField, baseTime是基准, sorterField=PublicTime, title // isAsc是用户自定义的排序方式 -func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, baseTime interface{}) (info.Note, info.Note) { +func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, baseTime interface{}) (info.Post, info.Post) { userIdO := bson.ObjectIdHex(userId) - + var sortFieldT1, sortFieldT2 bson.M var sortFieldR1, sortFieldR2 string if !isAsc { // 降序 /* -------- pre ------ now ---- next --- + ------- pre + ----- now + --- next + -- */ // 上一篇时间要比它大, 找最小的 sortFieldT1 = bson.M{"$gt": baseTime} @@ -370,12 +374,12 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo sortFieldR2 = "-" + sorterField } else { // 升序 -/* ---- pre ------ now -------- next ---------- -*/ + /* + --- pre + ----- now + ------- next + --------- + */ // 上一篇要比它小, 找最大的 sortFieldT1 = bson.M{"$lt": baseTime} sortFieldR1 = "-" + sorterField @@ -383,68 +387,71 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo sortFieldT2 = bson.M{"$gt": baseTime} sortFieldR2 = sorterField } - + // 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序 note := info.Note{} - query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true, + query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true, sorterField: sortFieldT1, } - q := db.Notes.Find(query); + q := db.Notes.Find(query) q.Sort(sortFieldR1).Limit(1).One(¬e) // 下一篇, 比基时间要大, 但是是第一篇, 所以是升序 note2 := info.Note{} query[sorterField] = sortFieldT2 -// Log(isAsc) -// LogJ(query) -// Log(sortFieldR2) - q = db.Notes.Find(query); + // Log(isAsc) + // LogJ(query) + // Log(sortFieldR2) + q = db.Notes.Find(query) q.Sort(sortFieldR2).Limit(1).One(¬e2) - - return note, note2 + + return this.FixNote(note), this.FixNote(note2) } //------- // p // 平台 lea+ // 博客列表 -func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend bool, page, pageSize int, sorterField string, isAsc bool) (info.Page, []info.BlogItem) { +func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRecommend bool, page, pageSize int, sorterField string, isAsc bool) (info.Page, []info.BlogItem) { pageInfo := info.Page{CurPage: page} notes := []info.Note{} - + skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc) - + // 不是trash的 - query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne":"欢迎来到leanote!"}} + query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}} if tag != "" { query["Tags"] = bson.M{"$in": []string{tag}} } + if userId != "" { + query["UserId"] = bson.ObjectIdHex(userId) + } // 不是demo的博客 demoUserId := configService.GetGlobalStringConfig("demoUserId") - if demoUserId != "" { + if userId == "" && demoUserId != "" { query["UserId"] = bson.M{"$ne": bson.ObjectIdHex(demoUserId)} } - + if isRecommend { query["IsRecommend"] = isRecommend } if keywords != "" { query["Title"] = bson.M{"$regex": bson.RegEx{".*?" + keywords + ".*", "i"}} } - q := db.Notes.Find(query); - + q := db.Notes.Find(query) + // 总记录数 count, _ := q.Count() - + q.Sort(sortFieldR). Skip(skipNum). Limit(pageSize). All(¬es) - - if(notes == nil || len(notes) == 0) { + + if notes == nil || len(notes) == 0 { return pageInfo, nil } - + // 得到content, 并且每个都要substring noteIds := make([]bson.ObjectId, len(notes)) userIds := make([]bson.ObjectId, len(notes)) @@ -452,21 +459,21 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b noteIds[i] = note.NoteId userIds[i] = note.UserId } - + // 可以不要的 // 直接得到noteContents表的abstract // 这里可能是乱序的 /* - noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent] - noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents)) - for _, noteContent := range noteContents { - noteContentsMap[noteContent.NoteId] = noteContent - } + noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent] + noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents)) + for _, noteContent := range noteContents { + noteContentsMap[noteContent.NoteId] = noteContent + } */ - + // 得到用户信息 userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds) - + // 组装成blogItem // 按照notes的顺序 blogs := make([]info.BlogItem, len(noteIds)) @@ -474,18 +481,17 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b hasMore := true var content string /* - if noteContent, ok := noteContentsMap[note.NoteId]; ok { - content = noteContent.Abstract - } + if noteContent, ok := noteContentsMap[note.NoteId]; ok { + content = noteContent.Abstract + } */ blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]} } pageInfo = info.NewPage(page, pageSize, count, nil) - + return pageInfo, blogs } - //------------------------ // 博客设置 func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) { @@ -494,14 +500,14 @@ func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) { userBlog.Logo = strings.Trim(userBlog.Logo, "/") userBlog.Logo = configService.GetSiteUrl() + "/" + userBlog.Logo } - + if userBlog.SortField == "" { userBlog.SortField = "PublicTime" } if userBlog.PerPageSize <= 0 { userBlog.PerPageSize = 10 } - + // themePath if userBlog.Style == "" { userBlog.Style = defaultStyle @@ -523,6 +529,7 @@ func (this *BlogService) GetUserBlog(userId string) info.UserBlog { func (this *BlogService) UpdateUserBlog(userBlog info.UserBlog) bool { return db.Upsert(db.UserBlogs, bson.M{"_id": userBlog.UserId}, userBlog) } + // 修改之UserBlogBase func (this *BlogService) UpdateUserBlogBase(userId string, userBlog info.UserBlogBase) bool { ok := db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog) @@ -534,12 +541,13 @@ func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.User func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool { return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog) } -// 分页与排序 + +// 分页与排序 func (this *BlogService) UpdateUserBlogPaging(userId string, perPageSize int, sortField string, isAsc bool) (ok bool, msg string) { if ok, msg = Vds(map[string]string{"perPageSize": strconv.Itoa(perPageSize), "sortField": sortField}); !ok { return } - ok = db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, + ok = db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, bson.M{"PerPageSize": perPageSize, "SortField": sortField, "IsAsc": isAsc}) return } @@ -577,23 +585,23 @@ func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.UserA // 默认前5 pageSize := 5 skipNum, sortFieldR := parsePageAndSort(1, pageSize, "CreatedTime", false) - + likes := []info.BlogLike{} query := bson.M{"NoteId": bson.ObjectIdHex(noteId)} - q := db.BlogLikes.Find(query); - + q := db.BlogLikes.Find(query) + // 总记录数 count, _ := q.Count() if count == 0 { return nil, false } - + if isAll { q.Sort(sortFieldR).Skip(skipNum).Limit(pageSize).All(&likes) } else { q.Sort(sortFieldR).All(&likes) } - + // 得到所有userIds userIds := make([]bson.ObjectId, len(likes)) for i, like := range likes { @@ -601,12 +609,12 @@ func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.UserA } // 得到用户信息 userMap := userService.MapUserAndBlogByUserIds(userIds) - - users := make([]info.UserAndBlog, len(likes)); + + users := make([]info.UserAndBlog, len(likes)) for i, like := range likes { users[i] = userMap[like.UserId.Hex()] } - + return users, count > pageSize } @@ -635,14 +643,14 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool) ok = false isLike = false if noteId == "" || userId == "" { - return + return } // 判断是否点过赞, 如果点过那么取消点赞 note := noteService.GetNoteById(noteId) - if !note.IsBlog /*|| note.UserId.Hex() == userId */{ - return + if !note.IsBlog /*|| note.UserId.Hex() == userId */ { + return } - + noteIdO := bson.ObjectIdHex(noteId) userIdO := bson.ObjectIdHex(userId) var n int @@ -658,7 +666,7 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool) isLike = false } ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}}) - + return } @@ -670,16 +678,16 @@ func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (b if content == "" { return false, comment } - + note := noteService.GetNoteById(noteId) if !note.IsBlog { return false, comment } - comment = info.BlogComment{CommentId: bson.NewObjectId(), - NoteId: bson.ObjectIdHex(noteId), - UserId: bson.ObjectIdHex(userId), - Content: content, + comment = info.BlogComment{CommentId: bson.NewObjectId(), + NoteId: bson.ObjectIdHex(noteId), + UserId: bson.ObjectIdHex(userId), + Content: content, CreatedTime: time.Now(), } var comment2 = info.BlogComment{} @@ -698,44 +706,44 @@ func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (b // 评论+1 db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": 1}}) } - + if userId != note.UserId.Hex() || toCommentId != "" { go func() { - this.sendEmail(note, comment2, userId, content); + this.sendEmail(note, comment2, userId, content) }() } - + return ok, comment } // 发送email func (this *BlogService) sendEmail(note info.Note, comment info.BlogComment, userId, content string) { - emailService.SendCommentEmail(note, comment, userId, content); + emailService.SendCommentEmail(note, comment, userId, content) /* - toUserId := note.UserId.Hex() - // title := "评论提醒" - - // 表示回复回复的内容, 那么发送给之前回复的 - if comment.CommentId != "" { - toUserId = comment.UserId.Hex() - } - toUserInfo := userService.GetUserInfo(toUserId) - sendUserInfo := userService.GetUserInfo(userId) - - subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论"; - if comment.CommentId != "" { - subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username; - if userId == note.UserId.Hex() { - subject += "(作者)"; - } - subject += " 的评论"; - } + toUserId := note.UserId.Hex() + // title := "评论提醒" - body := "{header}评论内容:
            " + content + "
            "; - href := "http://"+ configService.GetBlogDomain() + "/view/" + note.NoteId.Hex() - body += "
            博客链接:
            " + href + "{footer}"; - - emailService.SendEmail(toUserInfo.Email, subject, body) + // 表示回复回复的内容, 那么发送给之前回复的 + if comment.CommentId != "" { + toUserId = comment.UserId.Hex() + } + toUserInfo := userService.GetUserInfo(toUserId) + sendUserInfo := userService.GetUserInfo(userId) + + subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论"; + if comment.CommentId != "" { + subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username; + if userId == note.UserId.Hex() { + subject += "(作者)"; + } + subject += " 的评论"; + } + + body := "{header}评论内容:
            " + content + "
            "; + href := "http://"+ configService.GetBlogDomain() + "/view/" + note.NoteId.Hex() + body += "
            博客链接: " + href + "{footer}"; + + emailService.SendEmail(toUserInfo.Email, subject, body) */ } @@ -746,22 +754,22 @@ func (this *BlogService) DeleteComment(noteId, commentId, userId string) bool { if !note.IsBlog { return false } - + comment := info.BlogComment{} db.Get(db.BlogComments, commentId, &comment) - + if comment.CommentId == "" { return false } - + if userId == configService.GetAdminUserId() || note.UserId.Hex() == userId || comment.UserId.Hex() == userId { - if db.Delete(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}) { + if db.Delete(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}) { // 评论-1 db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": -1}}) return true - } + } } - + return false } @@ -771,33 +779,33 @@ func (this *BlogService) LikeComment(commentId, userId string) (ok bool, isILike isILike = false num = 0 comment := info.BlogComment{} - + db.Get(db.BlogComments, commentId, &comment) - + var n int if comment.LikeUserIds != nil && len(comment.LikeUserIds) > 0 && InArray(comment.LikeUserIds, userId) { n = -1 // 从点赞名单删除 - db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}, - bson.M{"$pull": bson.M{"LikeUserIds": userId}}) + db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}, + bson.M{"$pull": bson.M{"LikeUserIds": userId}}) isILike = false } else { n = 1 // 添加之 - db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}, + db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}, bson.M{"$push": bson.M{"LikeUserIds": userId}}) isILike = true } - + if comment.LikeUserIds == nil { num = 0 } else { num = len(comment.LikeUserIds) + n } - - ok = db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}, - bson.M{"$set": bson.M{"LikeNum": num}}) - + + ok = db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}, + bson.M{"$set": bson.M{"LikeNum": num}}) + return } @@ -806,22 +814,22 @@ func (this *BlogService) LikeComment(commentId, userId string) (ok bool, isILike // 还要获取用户信息 func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.UserAndBlog) { pageInfo := info.Page{CurPage: page} - + comments2 := []info.BlogComment{} - + skipNum, sortFieldR := parsePageAndSort(page, pageSize, "CreatedTime", false) - + query := bson.M{"NoteId": bson.ObjectIdHex(noteId)} - q := db.BlogComments.Find(query); - + q := db.BlogComments.Find(query) + // 总记录数 count, _ := q.Count() q.Sort(sortFieldR).Skip(skipNum).Limit(pageSize).All(&comments2) - - if(len(comments2) == 0) { + + if len(comments2) == 0 { return pageInfo, nil, nil } - + comments := make([]info.BlogCommentPublic, len(comments2)) // 我是否点过赞呢? for i, comment := range comments2 { @@ -830,9 +838,9 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) comments[i].IsILikeIt = true } } - - note := noteService.GetNoteById(noteId); - + + note := noteService.GetNoteById(noteId) + // 得到用户信息 userIdsMap := map[bson.ObjectId]bool{note.UserId: true} for _, comment := range comments { @@ -847,25 +855,25 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) userIds[i] = userId i++ } - + // 得到用户信息 userMap := userService.MapUserAndBlogByUserIds(userIds) pageInfo = info.NewPage(page, pageSize, count, nil) - + return pageInfo, comments, userMap } // 举报 -func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool) { +func (this *BlogService) Report(noteId, commentId, reason, userId string) bool { note := noteService.GetNoteById(noteId) if !note.IsBlog { return false } - report := info.Report{ReportId: bson.NewObjectId(), - NoteId: bson.ObjectIdHex(noteId), - UserId: bson.ObjectIdHex(userId), - Reason: reason, + report := info.Report{ReportId: bson.NewObjectId(), + NoteId: bson.ObjectIdHex(noteId), + UserId: bson.ObjectIdHex(userId), + Reason: reason, CreatedTime: time.Now(), } if commentId != "" { @@ -878,14 +886,62 @@ func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool) // 分类排序 // CateIds -func (this *BlogService) UpateCateIds(userId string, cateIds[] string) bool { +func (this *BlogService) UpateCateIds(userId string, cateIds []string) bool { return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "CateIds", cateIds) } +// 修改笔记本urlTitle +func (this *BlogService) UpateCateUrlTitle(userId string, cateId, urlTitle string) (ok bool, url string) { + url = urlTitle + /* + // 先清空 + ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{ + "UrlTitle": "", + }) + */ + url = GetUrTitle(userId, urlTitle, "notebook") + ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{ + "UrlTitle": url, + }) + // 返回给前端的是decode + url = decodeValue(url) + return +} + +// 修改笔记urlTitle +func (this *BlogService) UpateBlogUrlTitle(userId string, noteId, urlTitle string) (ok bool, url string) { + url = urlTitle + // 先清空 + ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{ + "UrlTitle": "", + }) + url = GetUrTitle(userId, urlTitle, "note") + ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{ + "UrlTitle": url, + }) + // 返回给前端的是decode + url = decodeValue(url) + return +} + +// 修改博客的图片, 描述, 摘要 +func (this *BlogService) UpateBlogAbstract(userId string, noteId, imgSrc, desc, abstract string) (ok bool) { + ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{ + "ImgSrc": imgSrc, + "Desc": desc, + "HasSelfDefined": true, + }) + ok = db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{ + "Abstract": abstract, + }) + return ok +} + // 单页 func (this *BlogService) GetSingles(userId string) []map[string]string { userBlog := this.GetUserBlog(userId) singles := userBlog.Singles + LogJ(singles) return singles } func (this *BlogService) GetSingle(singleId string) info.BlogSingle { @@ -893,8 +949,17 @@ func (this *BlogService) GetSingle(singleId string) info.BlogSingle { db.Get(db.BlogSingles, singleId, &page) return page } +func (this *BlogService) GetSingleByUserIdAndUrlTitle(userId, singleIdOrUrlTitle string) info.BlogSingle { + page := info.BlogSingle{} + if IsObjectId(singleIdOrUrlTitle) { + db.Get(db.BlogSingles, singleIdOrUrlTitle, &page) + } else { + db.GetByQ(db.BlogSingles, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(singleIdOrUrlTitle)}, &page) + } + return page +} -func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd bool, singleId, title string) (ok bool) { +func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd bool, singleId, title, urlTitle string) (ok bool) { userBlog := this.GetUserBlog(userId) singles := userBlog.Singles if singles == nil { @@ -904,7 +969,7 @@ func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd b i := 0 for _, p := range singles { if p["SingleId"] == singleId { - break; + break } i++ } @@ -914,14 +979,20 @@ func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd b } else { // 找到了, 如果是删除, 则删除 if isDelete { - singles = append(singles[:i], singles[i+1:]...) + singles = append(singles[:i], singles[i+1:]...) } else { - singles[i]["Title"] = title + // 是更新 + if title != "" { + singles[i]["Title"] = title + } + if urlTitle != "" { + singles[i]["UrlTitle"] = urlTitle + } } } } else { // 是添加, 直接添加到最后 - singles = append(singles, map[string]string{"SingleId": singleId, "Title": title}) + singles = append(singles, map[string]string{"SingleId": singleId, "Title": title, "UrlTitle": urlTitle}) } return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles) } @@ -931,36 +1002,64 @@ func (this *BlogService) DeleteSingle(userId, singleId string) (ok bool) { ok = db.DeleteByIdAndUserId(db.BlogSingles, singleId, userId) if ok { // 还要修改UserBlog中的Singles - this.updateBlogSingles(userId, true, false, singleId, "") + this.updateBlogSingles(userId, true, false, singleId, "", "") } return } + +// 修改urlTitle +func (this *BlogService) UpdateSingleUrlTitle(userId, singleId, urlTitle string) (ok bool, url string) { + url = urlTitle + /* + // 先清空 + ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{ + "UrlTitle": "", + }) + */ + url = GetUrTitle(userId, urlTitle, "single") + ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{ + "UrlTitle": url, + }) + if ok { + // 还要修改UserBlog中的Singles + this.updateBlogSingles(userId, false, false, singleId, "", url) + } + // 返回给前端的是decode + url = decodeValue(url) + return +} + // 更新或添加 func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content string) (ok bool) { ok = false if singleId != "" { ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{ - "Title": title, - "Content": content, + "Title": title, + "Content": content, "UpdatedTime": time.Now(), }) if ok { // 还要修改UserBlog中的Singles - this.updateBlogSingles(userId, false, false, singleId, title) + this.updateBlogSingles(userId, false, false, singleId, title, "") } - return + return } // 添加 - page := info.BlogSingle{SingleId: bson.NewObjectId(), UserId: bson.ObjectIdHex(userId), Title: title, Content: content, + page := info.BlogSingle{ + SingleId: bson.NewObjectId(), + UserId: bson.ObjectIdHex(userId), + Title: title, + Content: content, + UrlTitle: GetUrTitle(userId, title, "single"), CreatedTime: time.Now(), } page.UpdatedTime = page.CreatedTime ok = db.Insert(db.BlogSingles, page) - + // 还要修改UserBlog中的Singles - this.updateBlogSingles(userId, false, true, page.SingleId.Hex(), title) - - return + this.updateBlogSingles(userId, false, true, page.SingleId.Hex(), title, page.UrlTitle) + + return } // 重新排序 @@ -973,26 +1072,142 @@ func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool if singles == nil || len(singles) == 0 { return } - + singlesMap := map[string]map[string]string{} for _, page := range singles { singlesMap[page["SingleId"]] = page } - + singles2 := make([]map[string]string, len(singles)) for i, singleId := range singleIds { singles2[i] = singlesMap[singleId] } - + return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles2) } // 得到用户的博客url -func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog) (string) { +func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string { if userBlog.Domain != "" && configService.AllowCustomDomain() { return configService.GetUserUrl(userBlog.Domain) } else if userBlog.SubDomain != "" { return configService.GetUserSubUrl(userBlog.SubDomain) } - return configService.GetBlogUrl() + "/" + userBlog.UserId.Hex() + if username == "" { + username = userBlog.UserId.Hex() + } + return configService.GetBlogUrl() + "/" + username +} + +// 得到所有url +func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.User) info.BlogUrls { + var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl string + if userBlog.Domain != "" && configService.AllowCustomDomain() { // http://demo.com + // ok + indexUrl = configService.GetUserUrl(userBlog.Domain) + cateUrl = indexUrl + "/cate" // /xxxxx + postUrl = indexUrl + "/post" // /xxxxx + searchUrl = indexUrl + "/search" // /xxxxx + singleUrl = indexUrl + "/single" + archiveUrl = indexUrl + "/archives" + tagsUrl = indexUrl + "/tags" + tagPostsUrl = indexUrl + "/tag" + } else if userBlog.SubDomain != "" { // demo.leanote.com + indexUrl = configService.GetUserSubUrl(userBlog.SubDomain) + cateUrl = indexUrl + "/cate" // /xxxxx + postUrl = indexUrl + "/post" // /xxxxx + searchUrl = indexUrl + "/search" // /xxxxx + singleUrl = indexUrl + "/single" + archiveUrl = indexUrl + "/archives" + tagsUrl = indexUrl + "/tags" + tagPostsUrl = indexUrl + "/tag" + } else { + // ok + blogUrl := configService.GetBlogUrl() // blog.leanote.com + userIdOrEmail := "" + if userInfo.Username != "" { + userIdOrEmail = userInfo.Username + } else if userInfo.Email != "" { + userIdOrEmail = userInfo.Email + } else { + userIdOrEmail = userInfo.UserId.Hex() + } + indexUrl = blogUrl + "/" + userIdOrEmail + cateUrl = blogUrl + "/cate/" + userIdOrEmail // /username/notebookId + postUrl = blogUrl + "/post/" + userIdOrEmail // /username/xxxxx + searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/username + singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/username/singleId + archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/username + tagsUrl = blogUrl + "/tags/" + userIdOrEmail + tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/username + } + + return info.BlogUrls{ + IndexUrl: indexUrl, + CateUrl: cateUrl, + SearchUrl: searchUrl, + SingleUrl: singleUrl, + PostUrl: postUrl, + ArchiveUrl: archiveUrl, + TagsUrl: tagsUrl, + TagPostsUrl: tagPostsUrl, + } +} + +// 转成post +func (this *BlogService) FixBlogs(blogs []info.BlogItem) []info.Post { + blogs2 := make([]info.Post, len(blogs)) + for i, blog := range blogs { + blogs2[i] = this.FixBlog(blog) + } + return blogs2 +} +func (this *BlogService) FixBlog(blog info.BlogItem) info.Post { + urlTitle := blog.UrlTitle + if urlTitle == "" { + urlTitle = blog.NoteId.Hex() + } + blog2 := info.Post{ + NoteId: blog.NoteId.Hex(), + Title: blog.Title, + UrlTitle: urlTitle, + ImgSrc: blog.ImgSrc, + CreatedTime: blog.CreatedTime, + UpdatedTime: blog.UpdatedTime, + PublicTime: blog.PublicTime, + Desc: blog.Desc, + Abstract: blog.Abstract, + Content: blog.Content, + Tags: blog.Tags, + CommentNum: blog.CommentNum, + ReadNum: blog.ReadNum, + LikeNum: blog.LikeNum, + IsMarkdown: blog.IsMarkdown, + } + return blog2 +} + +func (this *BlogService) FixNote(note info.Note) info.Post { + if note.NoteId == "" { + return info.Post{} + } + urlTitle := note.UrlTitle + if urlTitle == "" { + urlTitle = note.NoteId.Hex() + } + return info.Post{ + NoteId: note.NoteId.Hex(), + Title: note.Title, + ImgSrc: note.ImgSrc, + UrlTitle: urlTitle, + CreatedTime: note.CreatedTime, + UpdatedTime: note.UpdatedTime, + PublicTime: note.PublicTime, + Desc: note.Desc, + Tags: note.Tags, + CommentNum: note.CommentNum, + ReadNum: note.ReadNum, + LikeNum: note.LikeNum, + IsMarkdown: note.IsMarkdown, + } } diff --git a/app/service/ConfigService.go b/app/service/ConfigService.go index 5d1c4e6..422190d 100644 --- a/app/service/ConfigService.go +++ b/app/service/ConfigService.go @@ -573,3 +573,12 @@ func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} { } return config } + +// 主页是否是管理员的博客页 +func (this *ConfigService) HomePageIsAdminsBlog() bool { + return this.GetGlobalStringConfig("homePage") == "" +} + +func (this *ConfigService) GetVersion() string { + return "1.0-beta2" +} diff --git a/app/service/GroupService.go b/app/service/GroupService.go new file mode 100644 index 0000000..3dfc273 --- /dev/null +++ b/app/service/GroupService.go @@ -0,0 +1,130 @@ +package service + +import ( + "github.com/leanote/leanote/app/info" + "github.com/leanote/leanote/app/db" +// . "github.com/leanote/leanote/app/lea" + "gopkg.in/mgo.v2/bson" + "time" +// "strings" +) + +// 用户组, 用户组用户管理 + +type GroupService struct { +} + +// 添加分组 +func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) { + group := info.Group { + GroupId: bson.NewObjectId(), + UserId: bson.ObjectIdHex(userId), + Title: title, + CreatedTime: time.Now(), + } + return db.Insert(db.Groups, group), group +} +// 删除分组 +// 判断是否有好友 +func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) { + if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) { + return false, "hasUsers" + } + return db.DeleteByIdAndUserId(db.Groups, groupId, userId), "" + + // TODO 删除分组后, 在shareNote, shareNotebook中也要删除 +} +// 修改group标题 +func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) { + return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title) +} + +// 得到用户的所有分组(包括下的所有用户) +func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) { + // 得到分组s + groups := []info.Group{} + db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups) + // 得到其下的用户 + for i, group := range groups { + group.Users = this.GetUsers(group.GroupId.Hex()) + groups[i] = group + } + return groups +} +// 仅仅得到所有分组 +func (this *GroupService) GetGroups(userId string) ([]info.Group) { + // 得到分组s + groups := []info.Group{} + db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups) + return groups +} +// 得到分组, shareService用 +func (this *GroupService) GetGroup(userId, groupId string) (info.Group) { + // 得到分组s + group := info.Group{} + db.GetByIdAndUserId(db.Groups, groupId, userId, &group) + return group +} + +// 得到某分组下的用户 +func (this *GroupService) GetUsers(groupId string) ([]info.User) { + // 得到UserIds + groupUsers := []info.GroupUser{} + db.ListByQWithFields(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}, []string{"UserId"}, &groupUsers) + if len(groupUsers) == 0 { + return nil + } + userIds := make([]bson.ObjectId, len(groupUsers)) + for i, each := range groupUsers { + userIds[i] = each.UserId + } + // 得到userInfos + return userService.ListUserInfosByUserIds(userIds) +} + +// 得到我所属的所有分组ids +func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) { + // 得到UserIds + groupUsers := []info.GroupUser{} + db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers) + if len(groupUsers) == 0 { + return nil + } + groupIds := make([]bson.ObjectId, len(groupUsers)) + for i, each := range groupUsers { + groupIds[i] = each.GroupId + } + return groupIds +} + +func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) { + return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)}) +} +// 为group添加用户 +// 用户是否已存在? +func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) { + // groupId是否是ownUserId的? + if !this.isMyGroup(ownUserId, groupId) { + return false, "forbidden" + } + + // 是否已存在 + if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) { + return false, "hasUsers" + } + + return db.Insert(db.GroupUsers, info.GroupUser{ + GroupUserId: bson.NewObjectId(), + GroupId: bson.ObjectIdHex(groupId), + UserId: bson.ObjectIdHex(userId), + CreatedTime: time.Now(), + }), "" +} +// 删除用户 +func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) { + // groupId是否是ownUserId的? + if !this.isMyGroup(ownUserId, groupId) { + return false, "forbidden" + } + return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), "" +} diff --git a/app/service/NoteImageService.go b/app/service/NoteImageService.go index 11dcf6d..5470889 100644 --- a/app/service/NoteImageService.go +++ b/app/service/NoteImageService.go @@ -32,7 +32,12 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) { // 解析内容中的图片, 建立图片与note的关系 // // 图片必须是我的, 不然不添加 -func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool { +// imgSrc 防止博客修改了, 但内容删除了 +func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content string) bool { + // 让主图成为内容的一员 + if imgSrc != "" { + content = "" + content + } reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})") find := reg.FindAllStringSubmatch(content, -1) // 查找所有的 diff --git a/app/service/NoteService.go b/app/service/NoteService.go index 9ca994c..a169abe 100644 --- a/app/service/NoteService.go +++ b/app/service/NoteService.go @@ -120,6 +120,7 @@ func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (note // 添加笔记 // 首先要判断Notebook是否是Blog, 是的话设为blog // [ok] + func (this *NoteService) AddNote(note info.Note) info.Note { if(note.NoteId.Hex() == "") { noteId := bson.NewObjectId(); @@ -129,6 +130,7 @@ func (this *NoteService) AddNote(note info.Note) info.Note { note.UpdatedTime = note.CreatedTime note.IsTrash = false note.UpdatedUserId = note.UserId + note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note") // 设为blog notebookId := note.NotebookId.Hex() @@ -169,7 +171,7 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC db.Insert(db.NoteContents, noteContent) // 更新笔记图片 - noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content) + noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), "", noteContent.Content) return noteContent; } @@ -205,7 +207,6 @@ func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.Note } // 修改笔记 -// [ok] TODO perm还没测 func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool { // updatedUserId 要修改userId的note, 此时需要判断是否有修改权限 if userId != updatedUserId { @@ -217,6 +218,13 @@ func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUp } } + // 是否已自定义 + note := this.GetNoteById(noteId) + if note.IsBlog && note.HasSelfDefined { + delete(needUpdate, "ImgSrc") + delete(needUpdate, "Desc") + } + needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId); needUpdate["UpdatedTime"] = time.Now(); @@ -260,12 +268,18 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten } } - if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, - bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), + data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Content": content, "Abstract": abstract, - "UpdatedTime": time.Now()}) { - + "UpdatedTime": time.Now()} + + // 是否已自定义 + note := this.GetNoteById(noteId) + if note.IsBlog && note.HasSelfDefined { + delete(data, "Abstract") + } + + if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) { // 这里, 添加历史记录 noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId), Content: content, @@ -273,7 +287,7 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten }) // 更新笔记图片 - noteImageService.UpdateNoteImages(userId, noteId, content) + noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content) return true } @@ -306,6 +320,8 @@ func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool noteUpdate["IsTop"] = isTop if isBlog { noteUpdate["PublicTime"] = time.Now() + } else { + noteUpdate["HasSelfDefined"] = false } ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate) // 重新计算tags diff --git a/app/service/NotebookService.go b/app/service/NotebookService.go index a64b16e..686f82a 100644 --- a/app/service/NotebookService.go +++ b/app/service/NotebookService.go @@ -101,6 +101,15 @@ func (this *NotebookService) GetNotebookById(notebookId string) info.Notebook { db.Get(db.Notebooks, notebookId, ¬ebook) return notebook } +func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOrUrlTitle string) info.Notebook { + notebook := info.Notebook{} + if IsObjectId(notebookIdOrUrlTitle) { + db.Get(db.Notebooks, notebookIdOrUrlTitle, ¬ebook) + } else { + db.GetByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(notebookIdOrUrlTitle)}, ¬ebook) + } + return notebook +} // 得到用户下所有的notebook // 排序好之后返回 @@ -133,6 +142,7 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object // 添加 // [ok] func (this *NotebookService) AddNotebook(notebook info.Notebook) bool { + notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook") err := db.Notebooks.Insert(notebook) if err != nil { panic(err) @@ -180,6 +190,8 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo data := bson.M{"IsBlog": isBlog} if isBlog { data["PublicTime"] = time.Now() + } else { + data["HasSelfDefined"] = false } db.UpdateByQMap(db.Notes, q, data) diff --git a/app/service/ShareService.go b/app/service/ShareService.go index ebad5b0..40219b3 100644 --- a/app/service/ShareService.go +++ b/app/service/ShareService.go @@ -13,7 +13,10 @@ import ( type ShareService struct { } -//----------------- +//----------------------------------- +// 返回shareNotebooks, sharedUserInfos +// info.ShareNotebooksByUser, []info.User + // 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据 // 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!! @@ -27,23 +30,48 @@ type ShareService struct { // 3 每个层按seq进行排序 // 4 按用户分组 // [ok] -func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) { - //------------- - // 查询HasShareNote表得到所有其它用户信息 - hasShareNotes := []info.HasShareNote{} - db.ListByQ(db.HasShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId)}, &hasShareNotes); - - userIds := make([]bson.ObjectId, len(hasShareNotes)) - for i, each := range hasShareNotes { - userIds[i] = each.UserId + +// 谁共享给了我的Query +func (this *ShareService) getOrQ(userId string) bson.M { + // 得到我参与的组织 + groupIds := groupService.GetBelongToGroupIds(userId) + q := bson.M{} + if len(groupIds) > 0 { + orQ := []bson.M{ + bson.M{"ToUserId": bson.ObjectIdHex(userId)}, + bson.M{"ToGroupId": bson.M{"$in": groupIds}}, + } + // 不是trash的 + q["$or"] = orQ + } else { + q["ToUserId"] = bson.ObjectIdHex(userId); } + return q +} + +func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) { + // 得到共享给我的用户s信息 + // 得到我参与的组织 + q := this.getOrQ(userId) + + // 不查hasShareNotes + // 直接查shareNotes, shareNotebooks表得到userId + userIds1 := []bson.ObjectId{} + db.Distinct(db.ShareNotes, q, "UserId", &userIds1) + + userIds2 := []bson.ObjectId{} + db.Distinct(db.ShareNotebooks, q, "UserId", &userIds1) + + userIds := append(userIds1, userIds2...) userInfos := userService.GetUserInfosOrderBySeq(userIds); //-------------------- // 得到他们共享给我的notebooks + // 这里可能会得到重复的记录 + // 权限: 笔记本分享给个人 > 笔记本分享给组织 shareNotebooks := []info.ShareNotebook{} - db.ShareNotebooks.Find(bson.M{"ToUserId": bson.ObjectIdHex(userId)}).All(&shareNotebooks) + db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shareNotebooks) // 按ToUserId降序排序, 那么有ToUserId的在前面 if len(shareNotebooks) == 0 { return nil, userInfos @@ -52,12 +80,15 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB shareNotebooksLen := len(shareNotebooks) // 找到了所有的notbookId, 那么找notebook表得到其详细信息 - notebookIds := make([]bson.ObjectId, shareNotebooksLen) + notebookIds := []bson.ObjectId{} shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen) - for i, each := range shareNotebooks { - // 默认的是没有notebookId的 - notebookIds[i] = each.NotebookId - shareNotebooksMap[each.NotebookId] = each + for _, each := range shareNotebooks { + // 之后的就不要了, 只留权限高的 + if _, ok := shareNotebooksMap[each.NotebookId]; !ok { + // 默认的是没有notebookId的 + notebookIds = append(notebookIds, each.NotebookId) + shareNotebooksMap[each.NotebookId] = each + } } // 1, 2 @@ -127,9 +158,13 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string, page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) { // 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId + q := this.getOrQ(myUserId) + q["NotebookId"] = bson.ObjectIdHex(notebookId); + q["UserId"] = bson.ObjectIdHex(sharedUserId); shareNotebook := info.ShareNotebook{} - db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId), - "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook) + db.GetByQ(db.ShareNotebooks, + q, + &shareNotebook) if shareNotebook.NotebookId == "" { return nil @@ -146,7 +181,19 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share for i, note := range notes { noteIds[i] = note.NoteId } - notePerms := this.getNotesPerm(noteIds, myUserId, sharedUserId); + // 笔记的权限 + shareNotes := []info.ShareNote{} + delete(q, "NotebookId") + q["NoteId"] = bson.M{"$in": noteIds} + db.ShareNotes.Find(q).Sort("-ToUserId").All(&shareNotes) // 给个的权限>给组织的权限 + notePerms := map[bson.ObjectId]int{} + for _, each := range shareNotes { + if _, ok := notePerms[each.NoteId]; !ok { + notePerms[each.NoteId] = each.Perm + } + } + Log("笔记权限") + LogJ(notePerms); // 3.2 组合 notesWithPerm := make([]info.ShareNoteWithPerm, len(notes)) @@ -162,17 +209,21 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share } // 得到note的perm信息 -func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int { - shareNotes := []info.ShareNote{} - db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes) - - notesPerm := make(map[bson.ObjectId]int, len(shareNotes)) - for _, each := range shareNotes { - notesPerm[each.NoteId] = each.Perm - } - - return notesPerm -} +//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int { +// shareNotes := []info.ShareNote{} +// db.ListByQ(db.ShareNotes, +// bson.M{ +// "NoteId": bson.M{"$in": noteIds}, +// "UserId": bson.ObjectIdHex(sharedUserId), +// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes) +// +// notesPerm := make(map[bson.ObjectId]int, len(shareNotes)) +// for _, each := range shareNotes { +// notesPerm[each.NoteId] = each.Perm +// } +// +// return notesPerm +//} // 得到默认的单个的notes 共享集 // 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit @@ -184,9 +235,12 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string, skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc) shareNotes := []info.ShareNote{} + q := this.getOrQ(myUserId) + q["UserId"] = bson.ObjectIdHex(sharedUserId); + db.ShareNotes. - Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}). -// Sort(sortFieldR). + Find(q). + Sort("-ToUserId"). // 给个人的权限 > 给组织的权限 Skip(skipNum). Limit(pageSize). All(&shareNotes) @@ -200,15 +254,20 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string, noteIds[i] = each.NoteId } notes := noteService.ListNotesByNoteIds(noteIds) - notesMap := make(map[bson.ObjectId]info.Note, len(notes)) + notesMap := map[bson.ObjectId]info.Note{} for _, each := range notes { notesMap[each.NoteId] = each } // 将shareNotes与notes结合起来 - notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes)) - for i, each := range shareNotes { - notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm} + notesWithPerm := []info.ShareNoteWithPerm{} + hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的 + for _, each := range shareNotes { + if !hasAdded[each.NoteId] { + // 待优化 + notesWithPerm = append(notesWithPerm, info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}) + hasAdded[each.NoteId] = true + } } return notesWithPerm } @@ -286,19 +345,25 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st return db.Insert(db.ShareNotes, shareNote), "", toUserId } + // updatedUserId是否有查看userId noteId的权限? +// userId是所有者 func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool { - if !db.Has(db.ShareNotes, - bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) { + q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3)) + q["UserId"] = bson.ObjectIdHex(userId) + q["NoteId"] = bson.ObjectIdHex(noteId) + if !db.Has(db.ShareNotes, q) { // noteId的notebookId是否被共享了? notebookId := noteService.GetNotebookId(noteId) if notebookId.Hex() == "" { return false } + delete(q, "NoteId") + q["NotebookId"] = notebookId + // 判断notebook是否被共享 - if !db.Has(db.ShareNotebooks, - bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) { + if !db.Has(db.ShareNotebooks, q) { return false } else { return true @@ -310,43 +375,44 @@ func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool // updatedUserId是否有修改userId noteId的权限? func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool { - // 1. noteId是否被共享了? - // 得到该note share的信息 - /* - UserId bson.ObjectId `bson:"UserId"` - ToUserId bson.ObjectId `bson:"ToUserId"` - NoteId bson.ObjectId `bson:"NoteId"` - Perm int `bson:"Perm"` // 权限, 0只读, 1可修改 - */ - if !db.Has(db.ShareNotes, - bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) { - // noteId的notebookId是否被共享了? - notebookId := noteService.GetNotebookId(noteId) - if notebookId.Hex() == "" { - return false - } - - // 判断notebook是否被共享 - if !db.Has(db.ShareNotebooks, - bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId, "Perm": 1}) { - return false - } else { - return true - } - } else { - return true + q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3)) + q["UserId"] = bson.ObjectIdHex(userId) + q["NoteId"] = bson.ObjectIdHex(noteId) + + // note的权限 + shares := []info.ShareNote{} + db.ShareNotes.Find(q).Sort("-ToUserId").All(&shares) // 个人 > 组织 + for _, share := range shares { + return share.Perm == 1 // 第1个权限最大 } + + // notebook的权限 + notebookId := noteService.GetNotebookId(noteId) + if notebookId.Hex() == "" { + return false + } + + delete(q, "NoteId") + q["NotebookId"] = notebookId + shares2 := []info.ShareNotebook{} + db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织 + for _, share := range shares2 { + return share.Perm == 1 // 第1个权限最大 + } + return false } // updatedUserId是否有修改userId notebookId的权限? func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool { - // 判断notebook是否被共享 - if !db.Has(db.ShareNotebooks, - bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) { - return false - } else { - return true - } + q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3)) + q["UserId"] = bson.ObjectIdHex(userId) + q["NotebookId"] = bson.ObjectIdHex(notebookId) + shares2 := []info.ShareNotebook{} + db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织 + for _, share := range shares2 { + return share.Perm == 1 // 第1个权限最大 + } + return false } // 共享note, notebook时使用 @@ -372,12 +438,16 @@ func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId strin } // 得到共享的笔记内容 -// 首先要判断这个note是否我被共享了 +// 并返回笔记的权限!!! func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) { noteContent = info.NoteContent{} // 是否单独共享了该notebook // 或者, 其notebook共享了我 - if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) { +// Log(this.HasSharedNote(noteId, myUserId)) +// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId)) + Log(this.HasReadPerm(sharedUserId, myUserId, noteId)) + if this.HasReadPerm(sharedUserId, myUserId, noteId) { +// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) { db.Get(db.NoteContents, noteId, ¬eContent) } else { } @@ -391,7 +461,15 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo { // 得到shareNote信息, 得到所有的ToUserId shareNotes := []info.ShareNote{} - db.ListByQLimit(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}, &shareNotes, 100) + db.ListByQLimit(db.ShareNotes, + bson.M{ + "NoteId": bson.ObjectIdHex(noteId), + "UserId": bson.ObjectIdHex(userId), + "ToGroupId": bson.M{"$exists": false}, + }, &shareNotes, 100) + +// Log("<<>>>>") +// Log(len(shareNotes)) if len(shareNotes) == 0 { return nil @@ -450,7 +528,11 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [ shareNotebooks := []info.ShareNotebook{} db.ListByQLimit(db.ShareNotebooks, - bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)}, + bson.M{ + "NotebookId": bson.ObjectIdHex(notebookId), + "UserId": bson.ObjectIdHex(userId), + "ToGroupId": bson.M{"$exists": false}, + }, &shareNotebooks, 100) if len(shareNotebooks) == 0 { @@ -555,7 +637,7 @@ func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool { } } -// 用户userId是否有修改noteId的权限 +// 用户userId是否有查看noteId的权限 func (this *ShareService) HasReadNotePerm(noteId, userId string) bool { if noteId == "" || userId == "" { return false; @@ -576,4 +658,121 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool { } else { return false; } -} \ No newline at end of file +} + +//---------------- +// 用户分组 + +// 得到笔记分享给的groups +func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote { + // 得到分组s + groups := groupService.GetGroups(userId) + + // 得到有分享的分组 + shares := []info.ShareNote{} + db.ListByQ(db.ShareNotes, + bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares) + mapShares := map[bson.ObjectId]info.ShareNote{} + for _, share := range shares { + mapShares[share.ToGroupId] = share + } + + // 所有的groups都有share, 但没有share的group没有shareId + shares2 := make([]info.ShareNote, len(groups)) + for i, group := range groups { + share, ok := mapShares[group.GroupId] + if !ok { + share = info.ShareNote{} + } + share.ToGroup = group; + shares2[i] = share + } + + return shares2 +} + +// 共享笔记给分组 +func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) { + // 得到group, 是否是我的group + group := groupService.GetGroup(userId, groupId) + if group.GroupId == "" { + return false + } + + // 先删除之 + this.DeleteShareNoteGroup(userId, noteId, groupId) + + shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId), + UserId: bson.ObjectIdHex(userId), // 冗余字段 + ToGroupId: bson.ObjectIdHex(groupId), + Perm: perm, + CreatedTime: time.Now(), + } + return db.Insert(db.ShareNotes, shareNote) +} + +// 删除 +func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) bool { + return db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), + "UserId": bson.ObjectIdHex(userId), + "ToGroupId": bson.ObjectIdHex(groupId), + }); +} + +//------- + +// 得到笔记本分享给的groups +func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook { + // 得到分组s + groups := groupService.GetGroups(userId) + + // 得到有分享的分组 + shares := []info.ShareNotebook{} + db.ListByQ(db.ShareNotebooks, + bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares) + mapShares := map[bson.ObjectId]info.ShareNotebook{} + for _, share := range shares { + mapShares[share.ToGroupId] = share + } + LogJ(shares) + + // 所有的groups都有share, 但没有share的group没有shareId + shares2 := make([]info.ShareNotebook, len(groups)) + for i, group := range groups { + share, ok := mapShares[group.GroupId] + if !ok { + share = info.ShareNotebook{} + } + share.ToGroup = group; + shares2[i] = share + } + + return shares2 +} +// 共享笔记给分组 +func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) { + // 得到group, 是否是我的group + group := groupService.GetGroup(userId, groupId) + if group.GroupId == "" { + return false + } + + // 先删除之 + this.DeleteShareNotebookGroup(userId, notebookId, groupId) + + shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId), + UserId: bson.ObjectIdHex(userId), // 冗余字段 + ToGroupId: bson.ObjectIdHex(groupId), + Perm: perm, + CreatedTime: time.Now(), + } + return db.Insert(db.ShareNotebooks, shareNotebook) +} + +// 删除 +func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId string) bool { + return db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId), + "UserId": bson.ObjectIdHex(userId), + "ToGroupId": bson.ObjectIdHex(groupId), + }); +} diff --git a/app/service/ThemeService.go b/app/service/ThemeService.go index e5b18fb..d1385ec 100644 --- a/app/service/ThemeService.go +++ b/app/service/ThemeService.go @@ -433,6 +433,36 @@ func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string) return } +// 升级用 +// public/ + +func (this *ThemeService) UpgradeThemeBeta2() (ok bool) { + adminUserId := configService.GetAdminUserId() + this.upgradeThemeBeta2(adminUserId, this.GetDefaultThemePath(defaultStyle), true) + this.upgradeThemeBeta2(adminUserId, this.GetDefaultThemePath(elegantStyle), false) + this.upgradeThemeBeta2(adminUserId, this.GetDefaultThemePath(fixedStyle), false) + return true +} +func (this *ThemeService) upgradeThemeBeta2(userId, targetPath string, isActive bool) (ok bool) { + // 解压成功, 那么新建之 + // 保存到数据库中 + theme, _ := this.getThemeConfig(revel.BasePath + "/" + targetPath) + if theme.Name == "" { + ok = false + return + } + themeIdO := bson.NewObjectId() + theme.ThemeId = themeIdO + theme.Path = targetPath // public + theme.CreatedTime = time.Now() + theme.UpdatedTime = theme.CreatedTime + theme.UserId = bson.ObjectIdHex(userId) + theme.IsActive = isActive + theme.IsDefault = true + ok = db.Insert(db.Themes, theme) + return ok +} + // 安装主题 // 得到该主题路径 func (this *ThemeService) InstallTheme(userId, themeId string) (ok bool) { diff --git a/app/service/UpgradeService.go b/app/service/UpgradeService.go index 117ea0b..740a14d 100644 --- a/app/service/UpgradeService.go +++ b/app/service/UpgradeService.go @@ -29,8 +29,15 @@ func (this *UpgradeService) UpgradeBlog() bool { } // 11-5自定义博客升级, 将aboutMe移至pages -func (this *UpgradeService) UpgradeBetaToSelfBlog(userId string) (ok bool, msg string) { - if configService.GetGlobalStringConfig("UpgradeBetaToSelfBlog") != "" { +/* +
          • Migrate "About me" to single(a single post)
          • +
          • Add some default themes to administrator
          • +
          • Generate "UrlTitle" for all notes. "UrlTitle" is a friendly url for post
          • +
          • Generate "UrlTitle" for all notebooks
          • +
          • Generate "UrlTitle" for all singles
          • +*/ +func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) { + if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" { return false, "已升级" } @@ -42,11 +49,58 @@ func (this *UpgradeService) UpgradeBetaToSelfBlog(userId string) (ok bool, msg s blogService.AddOrUpdateSingle(userBlog.UserId.Hex(), "", "About Me", userBlog.AboutMe) } - configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToSelfBlog", "ok") + + // 2. 默认主题, 给admin用户 + themeService.UpgradeThemeBeta2() + + // 3. UrlTitles + + // 3.1 note + notes := []info.Note{} + db.ListByQ(db.Notes, bson.M{}, ¬es) + for _, note := range notes { + data := bson.M{} + noteId := note.NoteId.Hex() + // PublicTime, RecommendTime = UpdatedTime + if note.IsBlog && note.PublicTime.Year() < 100 { + data["PublicTime"] = note.UpdatedTime + data["RecommendTime"] = note.UpdatedTime + Log("Time " + noteId) + } + data["UrlTitle"] = GetUrTitle(note.UserId.Hex(), note.Title, "note") + db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, data) + Log(noteId) + } + + // 3.2 + Log("notebook") + notebooks := []info.Notebook{} + db.ListByQ(db.Notebooks, bson.M{}, ¬ebooks) + for _, notebook := range notebooks { + notebookId := notebook.NotebookId.Hex() + data := bson.M{} + data["UrlTitle"] = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook") + db.UpdateByIdAndUserIdMap2(db.Notebooks, notebook.NotebookId, notebook.UserId, data) + Log(notebookId) + } + + // 3.3 single + /* + singles := []info.BlogSingle{} + db.ListByQ(db.BlogSingles, bson.M{}, &singles) + for _, single := range singles { + singleId := single.SingleId.Hex() + blogService.UpdateSingleUrlTitle(single.UserId.Hex(), singleId, single.Title) + Log(singleId) + } + */ + + // 删除索引 + db.ShareNotes.DropIndex("UserId", "ToUserId", "NoteId") ok = true msg = "success" + configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToBeta2", "1") - // 2. 默认主题, 给admin用户 return } diff --git a/app/service/UserService.go b/app/service/UserService.go index 5a3461c..cea7c79 100644 --- a/app/service/UserService.go +++ b/app/service/UserService.go @@ -41,6 +41,13 @@ func (this *UserService) GetUserId(email string) string { return user.UserId.Hex() } +// 得到用户名 +func (this *UserService) GetUsername(userId string) string { + user := info.User{} + db.GetByQWithFields(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, []string{"Username"}, &user) + return user.Username +} + // 是否存在该用户 email func (this *UserService) IsExistsUser(email string) bool { if this.GetUserId(email) == "" { @@ -163,7 +170,7 @@ func (this *UserService) MapUserAndBlogByUserIds(userIds []bson.ObjectId) map[st Logo: user.Logo, BlogTitle: userBlog.Title, BlogLogo: userBlog.Logo, - BlogUrl: blogService.GetUserBlogUrl(&userBlog), + BlogUrl: blogService.GetUserBlogUrl(&userBlog, user.Username), } } return userAndBlogMap @@ -180,7 +187,8 @@ func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog { Logo: user.Logo, BlogTitle: userBlog.Title, BlogLogo: userBlog.Logo, - BlogUrl: blogService.GetUserBlogUrl(&userBlog), + BlogUrl: blogService.GetUserBlogUrl(&userBlog, user.Username), + BlogUrls: blogService.GetBlogUrls(&userBlog, &user), } } @@ -269,6 +277,20 @@ func (this *UserService) UpdateTheme(userId, theme string) (bool) { return ok } +// 帐户类型设置 +func (this *UserService) UpdateAccount(userId, accountType string, accountStartTime, accountEndTime time.Time, + maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) bool { + return db.UpdateByQI(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, info.UserAccount{ + AccountType: accountType, + AccountStartTime: accountStartTime, + AccountEndTime: accountEndTime, + MaxImageNum: maxImageNum, + MaxImageSize: maxImageSize, + MaxAttachNum: maxAttachNum, + MaxAttachSize: maxAttachSize, + MaxPerAttachSize: maxPerAttachSize, + }) +} //--------------- // 修改email diff --git a/app/service/init.go b/app/service/init.go index 2c7cb7e..a07e1de 100644 --- a/app/service/init.go +++ b/app/service/init.go @@ -1,6 +1,13 @@ package service import ( + "regexp" + "strings" + "net/url" + "strconv" + "gopkg.in/mgo.v2" + "github.com/leanote/leanote/app/db" + "gopkg.in/mgo.v2/bson" ) // init service, for share service bettween services @@ -13,6 +20,7 @@ var noteContentHistoryService, NoteContentHistoryS *NoteContentHistoryService var trashService, TrashS *TrashService var shareService, ShareS *ShareService var userService, UserS *UserService +var groupService, GroupS *GroupService var tagService, TagS *TagService var blogService, BlogS *BlogService var tokenService, TokenS *TokenService @@ -37,6 +45,7 @@ func InitService() { TrashS = &TrashService{} ShareS = &ShareService{} UserS = &UserService{} + GroupS = &GroupService{} TagS = &TagService{} BlogS = &BlogService{} TokenS = &TokenService{} @@ -59,6 +68,7 @@ func InitService() { trashService = TrashS shareService = ShareS userService = UserS + groupService = GroupS tagService = TagS blogService = BlogS tokenService = TokenS @@ -71,3 +81,70 @@ func InitService() { sessionService = SessionS themeService = ThemeS } + +//---------------- +// service 公用方法 + +// 将name=val的val进行encoding +func decodeValue(val string) string { + v, _ := url.ParseQuery("a=" + val) + return v.Get("a") +} + +func encodeValue(val string) string { + if val == "" { + return val + } + v := url.Values{} + v.Set("", val) + return v.Encode()[1:] +} +// 添加笔记时通过title得到urlTitle +func fixUrlTitle(urlTitle string) string { + if urlTitle != "" { + // 把特殊字段给替换掉 +// str := `life "%&()+,/:;<>=?@\|` + reg, _ := regexp.Compile("/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\") + urlTitle = reg.ReplaceAllString(urlTitle, "-") + urlTitle = strings.Trim(urlTitle, "-") // 左右单独的-去掉 + // 把空格替换成- +// urlTitle = strings.Replace(urlTitle, " ", "-", -1) + for strings.Index(urlTitle, "--") >= 0 { // 防止出现连续的-- + urlTitle = strings.Replace(urlTitle, "--", "-", -1) + } + return encodeValue(urlTitle) + } + return urlTitle +} + +func getUniqueUrlTitle(userId string, urlTitle string, types string, padding int) string { + urlTitle2 := urlTitle + if padding > 1 { + urlTitle2 = urlTitle + "-" + strconv.Itoa(padding) + } + userIdO := bson.ObjectIdHex(userId) + + var collection *mgo.Collection + if types == "note" { + collection = db.Notes + } else if types == "notebook" { + collection = db.Notebooks + } else if types == "single" { + collection = db.BlogSingles + } + for db.Has(collection, bson.M{"UserId": userIdO, "UrlTitle": urlTitle2}) { // 用户下唯一 + padding++ + urlTitle2 = urlTitle + "-" + strconv.Itoa(padding) + } + + return urlTitle2 +} +// types == note,notebook,single +func GetUrTitle(userId string, title string, types string) string { + urlTitle := strings.Trim(title, " ") + if urlTitle == "" { + urlTitle = "Untitled-" + userId + } + urlTitle = fixUrlTitle(urlTitle) + return getUniqueUrlTitle(userId, urlTitle, types, 1) +} diff --git a/app/views/admin/nav.html b/app/views/admin/nav.html index bda8028..11af6f4 100644 --- a/app/views/admin/nav.html +++ b/app/views/admin/nav.html @@ -128,10 +128,18 @@ - Setting + Configuration +
          • + + + + + + + + + + + + + + Upgrade + + + +
          • \ No newline at end of file diff --git a/app/views/admin/setting/home_page.html b/app/views/admin/setting/home_page.html new file mode 100644 index 0000000..f23eaaa --- /dev/null +++ b/app/views/admin/setting/home_page.html @@ -0,0 +1,49 @@ +{{template "admin/top.html" .}} +

            Home Page

            + +
            + +
            +
            +
            +
            + + +
            + + +
            +
            + +
            + +
            +
            +
            +
            + +
            + +{{template "admin/footer.html" .}} + + +{{template "admin/end.html" .}} \ No newline at end of file diff --git a/app/views/admin/setting/openRegister.html b/app/views/admin/setting/open_register.html similarity index 100% rename from app/views/admin/setting/openRegister.html rename to app/views/admin/setting/open_register.html diff --git a/app/views/admin/upgrade/beta2.html b/app/views/admin/upgrade/beta2.html new file mode 100644 index 0000000..8de190c --- /dev/null +++ b/app/views/admin/upgrade/beta2.html @@ -0,0 +1,47 @@ +{{template "admin/top.html" .}} +

            Upgrade v1.0-beta to v1.0-beta2

            + +
            + +
            +
            +
            +
            + Current Version: leanote v{{.version}} +
              +
            • Migrate "About me" to single(a single post)
            • +
            • Add some default themes to administrator
            • +
            • Generate "UrlTitle" for all notes. "UrlTitle" is a friendly url for post
            • +
            • Generate "UrlTitle" for all notebooks
            • +
            • Generate "UrlTitle" for all singles
            • +
            +
            +
            + +
            +
            +
            +
            + +
            + +{{template "admin/footer.html" .}} + + +{{template "admin/end.html" .}} \ No newline at end of file diff --git a/app/views/member/blog/cate.html b/app/views/member/blog/cate.html index 314f205..b391bd6 100644 --- a/app/views/member/blog/cate.html +++ b/app/views/member/blog/cate.html @@ -12,6 +12,9 @@ {{range .notebooks}}
          • +
            + 固定链接: /cate/ +
            {{.Title}}
          • {{end}} @@ -33,7 +36,7 @@ $(function() { $(".list-group-item").each(function() { ids.push($(this).data("id")); }); - ajaxPost("/member/blog/upateCateIds", {cateIds: ids}, function(re){ + ajaxPost("/member/blog/", {cateIds: ids}, function(re){ if(reIsOk(re)) { art.tips("Success"); } else { @@ -41,6 +44,19 @@ $(function() { } }); }); + + $(".url-title").change(function(){ + var $t = $(this); + var url = $t.val(); + var cateId = $t.data('id'); + ajaxPost("/member/blog/updateCateUrlTitle", {cateId: cateId, urlTitle: url}, function(re){ + if(reIsOk(re)) { + $t.val(re.Item); + } else { + art.alert(re.Msg || "error"); + } + }); + }); }); diff --git a/app/views/member/blog/comment.html b/app/views/member/blog/comment.html index 8a1c071..487ecf9 100644 --- a/app/views/member/blog/comment.html +++ b/app/views/member/blog/comment.html @@ -9,8 +9,7 @@
            - -
            +