diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/.meteor/.finished-upgraders b/.meteor/.finished-upgraders new file mode 100755 index 0000000..aa60704 --- /dev/null +++ b/.meteor/.finished-upgraders @@ -0,0 +1,15 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package diff --git a/.meteor/.gitignore b/.meteor/.gitignore old mode 100644 new mode 100755 diff --git a/.meteor/.id b/.meteor/.id new file mode 100755 index 0000000..82bc3eb --- /dev/null +++ b/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +1slbx1514ogf6j1s44x8f diff --git a/.meteor/packages b/.meteor/packages index 49f31b9..d40b418 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -1,15 +1,31 @@ # Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. # # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -standard-app-packages -preserve-inputs -bootstrap -coffeescript -router -accounts-ui-bootstrap-dropdown +meteor-base@1.0.4 # Packages every Meteor app needs to have +mobile-experience@1.0.4 # Packages for a great mobile UX +mongo@1.1.12 # The database Meteor supports right now +blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views +reactive-var@1.0.10 # Reactive variable for tracker +jquery@1.11.9 # Helpful client-side library +tracker@1.1.0 # Meteor's client-side reactive programming library + +standard-minifier-css@1.2.0 # CSS minifier run for production mode +standard-minifier-js@1.2.0 # JS minifier run for production mode +es5-shim@4.6.14 # ECMAScript 5 compatibility for older browsers. +ecmascript@0.5.8 # Enable ECMAScript2015+ syntax in app code +shell-server@0.2.1 # Server-side component of the `meteor shell` command + +session +iron:router +sacha:spin +stylus accounts-password -errors -paginated-subscription -spin +twbs:bootstrap +ian:accounts-ui-bootstrap-3 +check +audit-argument-checks +mquandalle:jade +coffeescript diff --git a/.meteor/platforms b/.meteor/platforms new file mode 100755 index 0000000..efeba1b --- /dev/null +++ b/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/.meteor/release b/.meteor/release old mode 100644 new mode 100755 index b6e6316..72980bc --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -0.7.0.1 +METEOR@1.4.1.1 diff --git a/.meteor/versions b/.meteor/versions new file mode 100644 index 0000000..b7b4a06 --- /dev/null +++ b/.meteor/versions @@ -0,0 +1,98 @@ +accounts-base@1.2.11 +accounts-password@1.3.0 +allow-deny@1.0.5 +anti:i18n@0.4.3 +audit-argument-checks@1.0.7 +autoupdate@1.2.11 +babel-compiler@6.9.1 +babel-runtime@0.1.11 +base64@1.0.9 +binary-heap@1.0.9 +blaze@2.1.8 +blaze-html-templates@1.0.4 +blaze-tools@1.0.9 +boilerplate-generator@1.0.9 +caching-compiler@1.0.6 +caching-html-compiler@1.0.6 +callback-hook@1.0.9 +check@1.2.3 +coffeescript@1.1.4 +ddp@1.2.5 +ddp-client@1.2.9 +ddp-common@1.2.6 +ddp-rate-limiter@1.0.5 +ddp-server@1.2.10 +deps@1.0.12 +diff-sequence@1.0.6 +ecmascript@0.5.8 +ecmascript-runtime@0.3.14 +ejson@1.0.12 +email@1.1.17 +es5-shim@4.6.14 +fastclick@1.0.12 +geojson-utils@1.0.9 +hot-code-push@1.0.4 +html-tools@1.0.10 +htmljs@1.0.10 +http@1.1.8 +ian:accounts-ui-bootstrap-3@1.2.89 +id-map@1.0.8 +iron:controller@1.0.12 +iron:core@1.0.11 +iron:dynamic-template@1.0.12 +iron:layout@1.0.12 +iron:location@1.0.11 +iron:middleware-stack@1.1.0 +iron:router@1.0.13 +iron:url@1.0.11 +jquery@1.11.9 +launch-screen@1.0.12 +livedata@1.0.18 +localstorage@1.0.11 +logging@1.1.15 +meteor@1.2.17 +meteor-base@1.0.4 +minifier-css@1.2.14 +minifier-js@1.2.14 +minifiers@1.1.7 +minimongo@1.0.17 +mobile-experience@1.0.4 +mobile-status-bar@1.0.12 +modules@0.7.6 +modules-runtime@0.7.6 +mongo@1.1.12 +mongo-id@1.0.5 +mquandalle:jade@0.4.9 +mquandalle:jade-compiler@0.4.5 +npm-bcrypt@0.9.1 +npm-mongo@1.5.49 +observe-sequence@1.0.12 +ordered-dict@1.0.8 +promise@0.8.4 +random@1.0.10 +rate-limit@1.0.5 +reactive-dict@1.1.8 +reactive-var@1.0.10 +reload@1.1.10 +retry@1.0.8 +routepolicy@1.0.11 +sacha:spin@2.3.1 +service-configuration@1.0.10 +session@1.1.6 +sha@1.0.8 +shell-server@0.2.1 +spacebars@1.0.12 +spacebars-compiler@1.0.12 +srp@1.0.9 +standard-minifier-css@1.2.0 +standard-minifier-js@1.2.0 +stylus@2.512.5 +templating@1.1.14 +templating-tools@1.0.4 +tracker@1.1.0 +twbs:bootstrap@3.3.6 +ui@1.0.11 +underscore@1.0.9 +url@1.0.10 +webapp@1.3.11 +webapp-hashing@1.0.9 diff --git a/README.md b/README.md index 30b9663..aea165a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Microscope (CoffeeScript) -============================== +# Microscope-Coffee-Jade +The CoffeeScript version of Microscope. -The official community-maintained [CoffeeScript](http://coffeescript.org/) version of [Microscope](https://github.com/DiscoverMeteor/Microscope), [Discover Meteor](https://www.discovermeteor.com/)'s' sample application. +I make it compatible with the latest Meteor release (1.4.1.1) diff --git a/client/helpers/config.coffee b/client/helpers/config.coffee new file mode 100644 index 0000000..70c5563 --- /dev/null +++ b/client/helpers/config.coffee @@ -0,0 +1,2 @@ +Accounts.ui.config + passwordSignupFields: 'USERNAME_ONLY' diff --git a/client/helpers/config.js.coffee b/client/helpers/config.js.coffee deleted file mode 100644 index 421f3d1..0000000 --- a/client/helpers/config.js.coffee +++ /dev/null @@ -1,2 +0,0 @@ -Accounts.ui.config - passwordSignupFields: 'USERNAME_ONLY' diff --git a/client/helpers/error.coffee b/client/helpers/error.coffee new file mode 100644 index 0000000..6862099 --- /dev/null +++ b/client/helpers/error.coffee @@ -0,0 +1,5 @@ +@Errors = new Mongo.Collection null + +throwError = (message) -> + Errors.insert + message: message diff --git a/client/helpers/handlebars.coffee b/client/helpers/handlebars.coffee new file mode 100644 index 0000000..20d79b0 --- /dev/null +++ b/client/helpers/handlebars.coffee @@ -0,0 +1,5 @@ +Template.registerHelper 'pluralize', (n, thing) -> + if n is 1 + '1 ' + thing + else + n + ' ' + thing + 's' diff --git a/client/helpers/handlebars.js.coffee b/client/helpers/handlebars.js.coffee deleted file mode 100644 index 38a1926..0000000 --- a/client/helpers/handlebars.js.coffee +++ /dev/null @@ -1,6 +0,0 @@ -Handlebars.registerHelper 'pluralize', (n, thing) -> - if n == 1 - "1 #{thing}" - else - "#{n} #{thing}s" - diff --git a/client/helpers/router.js.coffee b/client/helpers/router.js.coffee deleted file mode 100644 index a81b9e7..0000000 --- a/client/helpers/router.js.coffee +++ /dev/null @@ -1,26 +0,0 @@ -Meteor.Router.add - '/': {to: 'bestPosts', as: 'home'} - '/best': to: 'bestPosts' - '/new': 'newPosts' - '/posts/:_id': - to: 'postPage' - and: (id) -> Session.set 'currentPostId', id - '/posts/:_id/edit': - to: 'postEdit' - and: (id) -> Session.set 'currentPostId', id - '/submit': 'postSubmit' - -Meteor.Router.filters - 'requireLogin': (page) -> - if Meteor.user() - page - else if Meteor.loggingIn() - 'loading' - else - 'accessDenied' - 'clearErrors': (page) -> - Meteor.Errors.clear() - page - -Meteor.Router.filter 'requireLogin', only: 'postSubmit' -Meteor.Router.filter 'clearErrors' diff --git a/client/main.css b/client/main.css new file mode 100644 index 0000000..67206b7 --- /dev/null +++ b/client/main.css @@ -0,0 +1,160 @@ +.grid-block, .main, .post, .comments li, .comment-form { + background: #fff; + border-radius: 3px; + padding: 10px; + margin-bottom: 10px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); } + +body { + background: #eee; + color: #666666; } + +#main { + position: relative; +} +.page { + position: absolute; + top: 0px; + width: 100%; +} + +.navbar { + margin-bottom: 10px; } + /* line 32, ../sass/style.scss */ + .navbar .navbar-inner { + border-radius: 0px 0px 3px 3px; } + +#spinner { + height: 300px; } + +.post { + /* For modern browsers */ + /* For IE 6/7 (trigger hasLayout) */ + *zoom: 1; + position: relative; + opacity: 1; } + .post:before, .post:after { + content: ""; + display: table; } + .post:after { + clear: both; } + .post.invisible { + opacity: 0; } + .post.instant { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; } + .post.animate{ + -webkit-transition: all 300ms 0ms; + -moz-transition: all 300ms 0ms ease-in; + -o-transition: all 300ms 0ms ease-in; + transition: all 300ms 0ms ease-in; } + .post .upvote { + display: block; + margin: 7px 12px 0 0; + float: left; } + .post .post-content { + float: left; } + .post .post-content h3 { + margin: 0; + line-height: 1.4; + font-size: 18px; } + .post .post-content h3 a { + display: inline-block; + margin-right: 5px; } + .post .post-content h3 span { + font-weight: normal; + font-size: 14px; + display: inline-block; + color: #aaaaaa; } + .post .post-content p { + margin: 0; } + .post .discuss { + display: block; + float: right; + margin-top: 7px; } + +.comments { + list-style-type: none; + margin: 0; } + .comments li h4 { + font-size: 16px; + margin: 0; } + .comments li h4 .date { + font-size: 12px; + font-weight: normal; } + .comments li h4 a { + font-size: 12px; } + .comments li p:last-child { + margin-bottom: 0; } + +.dropdown-menu span { + display: block; + padding: 3px 20px; + clear: both; + line-height: 20px; + color: #bbb; + white-space: nowrap; } + +.load-more { + display: block; + border-radius: 3px; + background: rgba(0, 0, 0, 0.05); + text-align: center; + height: 60px; + line-height: 60px; + margin-bottom: 10px; } + .load-more:hover { + text-decoration: none; + background: rgba(0, 0, 0, 0.1); } + +.posts .spinner-container{ + position: relative; + height: 100px; +} + +.jumbotron{ + text-align: center; +} +.jumbotron h2{ + font-size: 60px; + font-weight: 100; +} + +@-webkit-keyframes fadeOut { + 0% {opacity: 0;} + 10% {opacity: 1;} + 90% {opacity: 1;} + 100% {opacity: 0;} +} + +@keyframes fadeOut { + 0% {opacity: 0;} + 10% {opacity: 1;} + 90% {opacity: 1;} + 100% {opacity: 0;} +} + +.errors{ + position: fixed; + z-index: 10000; + padding: 10px; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + pointer-events: none; +} +.alert { + animation: fadeOut 2700ms ease-in 0s 1 forwards; + -webkit-animation: fadeOut 2700ms ease-in 0s 1 forwards; + -moz-animation: fadeOut 2700ms ease-in 0s 1 forwards; + width: 250px; + float: right; + clear: both; + margin-bottom: 5px; + pointer-events: auto; +} diff --git a/client/main.html b/client/main.html deleted file mode 100644 index 6c469d1..0000000 --- a/client/main.html +++ /dev/null @@ -1,12 +0,0 @@ - - Microscope - - -
- {{> header}} - {{> meteorErrors}} -
- {{renderPage}} -
-
- diff --git a/client/main.jade b/client/main.jade new file mode 100644 index 0000000..46745d0 --- /dev/null +++ b/client/main.jade @@ -0,0 +1,2 @@ +head + title Microscope diff --git a/client/main.js b/client/main.js new file mode 100644 index 0000000..e69de29 diff --git a/client/main.js.coffee b/client/main.js.coffee deleted file mode 100644 index 86491fd..0000000 --- a/client/main.js.coffee +++ /dev/null @@ -1,6 +0,0 @@ -@newPostsHandle = Meteor.subscribeWithPagination 'newPosts', 10 -@topPostsHandle = Meteor.subscribeWithPagination 'newPosts', 10 -Meteor.autorun -> - Meteor.subscribe 'singlePost', Session.get 'currentPostId' - Meteor.subscribe 'comments', Session.get 'currentPostId' -Meteor.subscribe 'notifications' diff --git a/client/stylesheets/style.css b/client/stylesheets/style.css deleted file mode 100644 index 3b94240..0000000 --- a/client/stylesheets/style.css +++ /dev/null @@ -1,52 +0,0 @@ -.grid-block, .main, .post, .comments li, .comment-form { - background: #fff; - border-radius: 3px; - padding:10px; - margin-bottom: 10px; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); -} -body { background: #eee; color: #666666; } -.navbar { margin-bottom: 10px } -.navbar .navbar-inner { border-radius: 0px 0px 3px 3px; } -#spinner { height: 300px } -.post { - *zoom: 1; - -webkit-transition: all 300ms 0ms; - -webkit-transition-delay: ease-in; - -moz-transition: all 300ms 0ms ease-in; - -o-transition: all 300ms 0ms ease-in; - transition: all 300ms 0ms ease-in; - position: relative; - opacity: 1; -} -.post:before, .post:after { content: ""; display: table; } -.post:after { clear: both } .post.invisible { opacity: 0 } -.post .upvote { display: block; margin: 7px 12px 0 0; float: left; } -.post .post-content { float: left } -.post .post-content h3 { margin: 0; line-height: 1.4; font-size: 18px; } -.post .post-content h3 a { display: inline-block; margin-right: 5px; } -.post .post-content h3 span { - font-weight: normal; font-size: 14px; display: inline-block; color: #aaaaaa; -} -.post .post-content p { margin: 0 } -.post .discuss { display: block; float: right; margin-top: 7px; } -.comments { list-style-type: none; margin: 0; } -.comments li h4 { font-size: 16px; margin: 0; } -.comments li h4 .date { font-size: 12px; font-weight: normal; } -.comments li h4 a { font-size: 12px } .comments li p:last-child { margin-bottom: 0 } -.dropdown-menu span { - display: block; - padding: 3px 20px; - clear: both; - line-height: 20px; - color: #bbb; - white-space: nowrap; -} -.load-more { - display: block; - border-radius: 3px; - background: rgba(0, 0, 0, 0.05); text-align: center; - height: 60px; - line-height: 60px; margin-bottom: 10px; -} -.load-more:hover { text-decoration: none; background: rgba(0, 0, 0, 0.1); } diff --git a/client/templates/application/layout.coffee b/client/templates/application/layout.coffee new file mode 100644 index 0000000..bedbec1 --- /dev/null +++ b/client/templates/application/layout.coffee @@ -0,0 +1,10 @@ +Template.layout.onRendered -> + this.find('#main')._uihooks = + insertElement: (node, next) -> + $(node) + .hide() + .insertBefore(next) + .fadeIn() + removeElement: (node) -> + $(node).fadeOut -> + $(this).remove() diff --git a/client/templates/application/layout.html b/client/templates/application/layout.html new file mode 100644 index 0000000..ea30944 --- /dev/null +++ b/client/templates/application/layout.html @@ -0,0 +1,9 @@ + diff --git a/client/templates/application/notFound.tpl.jade b/client/templates/application/notFound.tpl.jade new file mode 100644 index 0000000..2e74fec --- /dev/null +++ b/client/templates/application/notFound.tpl.jade @@ -0,0 +1,3 @@ +div.not-found.page.jumbotron + h2 404 + p Sorry, we couldn't find a page at this address diff --git a/client/templates/comments/commentItem.coffee b/client/templates/comments/commentItem.coffee new file mode 100644 index 0000000..9ed5ce0 --- /dev/null +++ b/client/templates/comments/commentItem.coffee @@ -0,0 +1,3 @@ +Template.commentItem.helpers + submittedText: -> + this.submitted.toString() diff --git a/client/templates/comments/commentItem.tpl.jade b/client/templates/comments/commentItem.tpl.jade new file mode 100644 index 0000000..714e2e4 --- /dev/null +++ b/client/templates/comments/commentItem.tpl.jade @@ -0,0 +1,5 @@ +li + h4 + span.author {{author}} + span.date on {{submittedText}} + p {{body}} diff --git a/client/templates/comments/commentSubmit.coffee b/client/templates/comments/commentSubmit.coffee new file mode 100644 index 0000000..33f4a0a --- /dev/null +++ b/client/templates/comments/commentSubmit.coffee @@ -0,0 +1,25 @@ +Template.commentSubmit.onCreated -> + Session.set 'commentSubmitErrors', {} + +Template.commentSubmit.helpers + errorMessage: (field) -> + Session.get('commentSubmitErrors')[field] + errorClass: (field) -> + !! Session.get('commentSubmitErrors')[field] ? "has-error" : '' + +Template.commentSubmit.events + 'submit form': (e, template) -> + e.preventDefault() + $body = $(e.target).find('[name=body]') + comment = + body: $body.val() + postId: template.data._id + errors = {} + if not comment.body + errors.body = "Please write some" + Session.set 'commentSubmitErrors', errors + Meteor.call 'commentInsert', comment, (error, commentId) -> + if error + throwError error.reason + else + $body.val '' diff --git a/client/templates/comments/commentSubmit.tpl.jade b/client/templates/comments/commentSubmit.tpl.jade new file mode 100644 index 0000000..a00756f --- /dev/null +++ b/client/templates/comments/commentSubmit.tpl.jade @@ -0,0 +1,7 @@ +form.comment-form.form(name="comment") + div.form-group(class="{{errorClass 'body'}}") + div.controls + label(for="body") Comment on this post + textarea.form-control#body(name="body", rows="3") + span.help-block {{errorMessage 'body'}} + button.btn.btn-primary(type="submit") Add Comment diff --git a/client/templates/includes/accessDenied.tpl.jade b/client/templates/includes/accessDenied.tpl.jade new file mode 100644 index 0000000..e8d4102 --- /dev/null +++ b/client/templates/includes/accessDenied.tpl.jade @@ -0,0 +1,3 @@ +div.access-denied.page.jumbotron + h2 Access Denied + p You can't get here! Please log in. diff --git a/client/templates/includes/error.tpl.jade b/client/templates/includes/error.tpl.jade new file mode 100644 index 0000000..f18be7f --- /dev/null +++ b/client/templates/includes/error.tpl.jade @@ -0,0 +1,3 @@ +div.alert.alert-danger(role='alert') + button.close(type="button", data-dismiss="alert") × + {{message}} diff --git a/client/templates/includes/errors.coffee b/client/templates/includes/errors.coffee new file mode 100644 index 0000000..e9171ae --- /dev/null +++ b/client/templates/includes/errors.coffee @@ -0,0 +1,9 @@ +Template.errors.helpers + errors: -> + Errors.find() + +Template.error.onRendered -> + error = this.data + Meteor.setTimeout -> + Errors.remove error._id + 3000 diff --git a/client/templates/includes/errors.tpl.jade b/client/templates/includes/errors.tpl.jade new file mode 100644 index 0000000..7ff031a --- /dev/null +++ b/client/templates/includes/errors.tpl.jade @@ -0,0 +1 @@ +div.errors {{#each errors}} {{> error}} {{/each}} diff --git a/client/templates/includes/header.coffee b/client/templates/includes/header.coffee new file mode 100644 index 0000000..2e46c59 --- /dev/null +++ b/client/templates/includes/header.coffee @@ -0,0 +1,8 @@ +Template.header.helpers + activeRouteClass: -> + args = Array.prototype.slice.call arguments, 0 + args.pop() + + active = _.any args (name) -> + Router.current() and Router.current().route.getName() is name + active and 'active' diff --git a/client/templates/includes/header.tpl.jade b/client/templates/includes/header.tpl.jade new file mode 100644 index 0000000..48991c7 --- /dev/null +++ b/client/templates/includes/header.tpl.jade @@ -0,0 +1,21 @@ +nav.navbar.navbar-default(role="navigation") + div.navbar-header + button.navbar-toggle.collapsed(type="button") + span.sr-only Toggle navigation + span.icon-bar + span.icon-bar + span.icon-bar + a.navbar-brand(href="{{pathFor 'home'}}") Microscope + div.collapse.navbar-collapse#navigation + ul.nav.navbar-nav + li(class="{{activeRouteClass 'home' 'newPosts'}}") + a(href="{{pathFor 'newPosts'}}") New + li(class="{{activeRouteClass 'bestPosts'}}") + a(href="{{pathFor 'bestPosts'}}") Best + if currentUser + li(class="{{activeRouteClass 'postSubmit'}}") + a(href="{{pathFor 'postSubmit'}}") Submit Post + li.dropdown + +notifications + ul.nav.navbar-nav.navbar-right + +loginButtons diff --git a/client/templates/includes/loading.tpl.jade b/client/templates/includes/loading.tpl.jade new file mode 100644 index 0000000..67df502 --- /dev/null +++ b/client/templates/includes/loading.tpl.jade @@ -0,0 +1 @@ ++spinner diff --git a/client/templates/notifications/notificationItem.tpl.jade b/client/templates/notifications/notificationItem.tpl.jade new file mode 100644 index 0000000..c31abb7 --- /dev/null +++ b/client/templates/notifications/notificationItem.tpl.jade @@ -0,0 +1,4 @@ +li + a(href="{{notificationPostPath}}") + strong {{commenterName}} + commented on your post diff --git a/client/templates/notifications/notifications.coffee b/client/templates/notifications/notifications.coffee new file mode 100644 index 0000000..5e0db23 --- /dev/null +++ b/client/templates/notifications/notifications.coffee @@ -0,0 +1,22 @@ +Template.notifications.helpers + notifications: -> + Notifications.find + userId: Meteor.userId() + read: false + notificationCount: -> + selector = + userId: Meteor.userId() + read: false + counter = Notifications.find selector + counter.count() + +Template.notificationItem.helpers + notificationPostPath: -> + Router.routes.postPage.path + _id: this.postId + +Template.notificationItem.events + 'click a': -> + Notifications.update this._id, + $set: + read: true diff --git a/client/templates/notifications/notifications.tpl.jade b/client/templates/notifications/notifications.tpl.jade new file mode 100644 index 0000000..ef493f3 --- /dev/null +++ b/client/templates/notifications/notifications.tpl.jade @@ -0,0 +1,16 @@ +a.dropdown-toggle(href="#", data-toggle="dropdown") Notifications + if notificationCount + span.badge.badge-inverse {{notificationCount}} + b.caret + +ul.notification.dropdown-menu + if notificationCount + {{#each notifications}} {{> notificationItem}} {{/each}} + else + li + span No notifications + + +// {{#if notificationCount}} {{notificationCount}} {{/if}} +// {{#if notificationCount}} {{#each notifications}} {{> notificationItem}} {{/each}} {{else}}
  • No notifications
  • {{/if}} + diff --git a/client/templates/posts/postEdit.coffee b/client/templates/posts/postEdit.coffee new file mode 100644 index 0000000..5c3962f --- /dev/null +++ b/client/templates/posts/postEdit.coffee @@ -0,0 +1,33 @@ +Template.postEdit.onCreated -> + Session.set 'postEditErrors', {} + +Template.postEdit.helpers + errorMessage: (field) -> + Session.get('postEditErrors')[field] + errorClass: (field) -> + !! Session.get('postEditErrors')[field] ? 'has-error' : '' + +Template.postEdit.events + 'submit form': (e) -> + e.preventDefault() + currentPostId = this._id + postProperties = + url: $(e.target).find('[name=url]').val() + title: $(e.target).find('[name=title]').val() + errors = validatePost postProperties + if errors.title or errors.url + Session.set 'postEditErrors', errors + Posts.update currentPostId, + $set: postProperties, + (error) -> + if error + throwError error.reason + else + Router.go 'postPage', + _id: currentPostId + 'click .delete': (e) -> + e.preventDefault() + if confirm "Delete this Post?" + currentPostId = this._id + Posts.remove currentPostId + Router.go 'home' diff --git a/client/templates/posts/postEdit.tpl.jade b/client/templates/posts/postEdit.tpl.jade new file mode 100644 index 0000000..e1d3d8c --- /dev/null +++ b/client/templates/posts/postEdit.tpl.jade @@ -0,0 +1,16 @@ +form.main.form.page + + div.form-group(class='{{errorClass "url"}}') + label.control-label(for='url') URL + div.controls + input.form-control#url(name='url', type='text', value='{{url}}', placeholder='Your URL') + span.help-block {{errorMessage 'url'}} + + div.form-group(class='{{errorClass "title"}}') + label.control-label(for='title') Title + div.controls + input.form-control#title(name='title', type='text', value='{{title}}', placeholder='Your Title') + span.help-block {{errorMessage 'title'}} + + input.btn.btn-primary.submit(type='submit', value='Submit') + a.btn.btn-danger.delete(href='#') Delete post diff --git a/client/templates/posts/postItem.coffee b/client/templates/posts/postItem.coffee new file mode 100644 index 0000000..88ee52a --- /dev/null +++ b/client/templates/posts/postItem.coffee @@ -0,0 +1,21 @@ +Template.postItem.helpers + + ownPost: -> + this.userId is Meteor.userId() + + domain: -> + a = document.createElement 'a' + a.href = this.url + a.hostname + + upvotedClass: -> + userId = Meteor.userId() + if userId and not _.include this.upvoters, userId + 'btn-primary upvotable' + else + 'disabled' + +Template.postItem.events + 'click .upvotable': (e) -> + e.preventDefault() + Meteor.call 'upvote', this._id diff --git a/client/templates/posts/postItem.tpl.jade b/client/templates/posts/postItem.tpl.jade new file mode 100644 index 0000000..d28ae4e --- /dev/null +++ b/client/templates/posts/postItem.tpl.jade @@ -0,0 +1,12 @@ +div.post + a.upvote.btn.btn-default(class="#{upvotedClass}", href="#") Up + div.post-content + h3 + a(href='#{url}') #{title} + span #{domain} + p {{pluralize votes 'Vote'}}, submitted by #{author} + a(href="{{pathFor 'postPage'}}") {{pluralize commentsCount 'comment'}} + if ownPost + a(href="{{pathFor 'postEdit'}}") Edit + a.discuss.btn.btn-default(href="{{pathFor 'postPage'}}") Discuss + diff --git a/client/templates/posts/postPage.coffee b/client/templates/posts/postPage.coffee new file mode 100644 index 0000000..1b7b20a --- /dev/null +++ b/client/templates/posts/postPage.coffee @@ -0,0 +1,4 @@ +Template.postPage.helpers + comments: -> + Comments.find + postId: this._id diff --git a/client/templates/posts/postPage.tpl.jade b/client/templates/posts/postPage.tpl.jade new file mode 100644 index 0000000..79ccc98 --- /dev/null +++ b/client/templates/posts/postPage.tpl.jade @@ -0,0 +1,9 @@ + +div.post-page.page + +postItem + ul.comments + {{#each comments}} {{> commentItem}} {{/each}} + if currentUser + +commentSubmit + else + p Please log in to leave a comment. diff --git a/client/templates/posts/postSubmit.coffee b/client/templates/posts/postSubmit.coffee new file mode 100644 index 0000000..4588af4 --- /dev/null +++ b/client/templates/posts/postSubmit.coffee @@ -0,0 +1,25 @@ +Template.postSubmit.onCreated -> + Session.set 'postSubmitErrors', {} + +Template.postSubmit.helpers + errorMessage: (field) -> + Session.get('postSubmitErrors')[field] + errorClass: (field) -> + !! Session.get('postSubmitErrors')[field] ? 'has-error' : '' + +Template.postSubmit.events + 'submit form': (e) -> + e.preventDefault() + post = + url: $(e.target).find('[name=url]').val() + title: $(e.target).find('[name=title]').val() + errors = validatePost post + if errors.title or errors.url + Session.set 'postSubmitErrors', errors + Meteor.call 'postInsert', post, (error, result) -> + if error + throwError error.reason + if result.postExists + throwError 'This link has already been posted' + Router.go 'postPage', + _id: result._id diff --git a/client/templates/posts/postSubmit.tpl.jade b/client/templates/posts/postSubmit.tpl.jade new file mode 100644 index 0000000..acb8996 --- /dev/null +++ b/client/templates/posts/postSubmit.tpl.jade @@ -0,0 +1,14 @@ +form.main.form.page + + div.form-group(class="{{errorClass 'url'}}") + label.control-label(for="url") URL + div.controls + input.form-control#url(name="url", type="text", value="", placeholder="Your URL") + span.help-block {{errorMessage 'url'}} + + div.form-group(class="{{errorClass 'title'}}") + label.control-label(for='title') Title + div.controls + input.form-control#title(name="title", type="text", value="", placeholder="Your Title") + + input.btn.btn-primary(type="submit", value="Submit") diff --git a/client/templates/posts/postsList.coffee b/client/templates/posts/postsList.coffee new file mode 100644 index 0000000..65fb5ce --- /dev/null +++ b/client/templates/posts/postsList.coffee @@ -0,0 +1,31 @@ +Template.postsList.onRendered -> + this.find('.wrapper')._uihooks = + insertElement: (node, next) -> + $(node) + .hide() + .insertBefore next + .fadeIn() + + moveElement: (node, next) -> + $node = $(node) + $next = $(next) + oldTop = $node.offset().top + height = $(node).outerHeight true + $inBetween = $(next).nextUntil node + if $inBetween.length is 0 + $inBetween = $(node).nextUntil next + $(node).insertBefore next + newTop = $(node).offset().top + $(node) + .removeClass 'animate' + .css('top', oldTop - newTop) + $inBetween + .removeClass 'animate' + .css('top', oldTop < newTop ? height : -1 * height) + $(node).offset() + $(node).addClass('animate').css('top', 0) + $inBetween.addClass('animate').css('top', 0) + + removeElement: (node) -> + $(node).fadeOut -> + $(this).remove() diff --git a/client/templates/posts/postsList.tpl.jade b/client/templates/posts/postsList.tpl.jade new file mode 100644 index 0000000..5720baf --- /dev/null +++ b/client/templates/posts/postsList.tpl.jade @@ -0,0 +1,9 @@ + +div.posts.page + div.wrapper + {{#each posts}} {{> postItem}} {{/each}} + if nextPath + a.load-more(href="{{nextPath}}") Load more + else + unless ready + +spinner diff --git a/client/views/comments/comment.html b/client/views/comments/comment.html deleted file mode 100644 index e880da2..0000000 --- a/client/views/comments/comment.html +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/client/views/comments/comment.js.coffee b/client/views/comments/comment.js.coffee deleted file mode 100644 index e7160ac..0000000 --- a/client/views/comments/comment.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -Template.comment.helpers - submittedText: -> - new Date(this.submitted).toString() diff --git a/client/views/comments/comment_submit.html b/client/views/comments/comment_submit.html deleted file mode 100644 index b7263c1..0000000 --- a/client/views/comments/comment_submit.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/client/views/comments/comment_submit.js.coffee b/client/views/comments/comment_submit.js.coffee deleted file mode 100644 index 90398b2..0000000 --- a/client/views/comments/comment_submit.js.coffee +++ /dev/null @@ -1,10 +0,0 @@ -Template.commentSubmit.events - 'submit form': (event, template) -> - event.preventDefault() - - comment = - body: $(event.target).find('[name=body]').val() - postId: template.data._id - - Meteor.call 'comment', comment, (error, commentId) -> - error && throwError error.reason diff --git a/client/views/includes/access_denied.html b/client/views/includes/access_denied.html deleted file mode 100644 index 1794b37..0000000 --- a/client/views/includes/access_denied.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/client/views/includes/header.html b/client/views/includes/header.html deleted file mode 100644 index 7b54a71..0000000 --- a/client/views/includes/header.html +++ /dev/null @@ -1,22 +0,0 @@ - diff --git a/client/views/includes/header.js.coffee b/client/views/includes/header.js.coffee deleted file mode 100644 index 983e74c..0000000 --- a/client/views/includes/header.js.coffee +++ /dev/null @@ -1,9 +0,0 @@ -Template.header.helpers - activeRouteClass: -> - args = Array.prototype.slice.call arguments, 0 - args.pop() - - active = _.any args, (name) -> - location.pathname == Meteor.Router[name + "Path"]() - - active && 'active' diff --git a/client/views/includes/loading.html b/client/views/includes/loading.html deleted file mode 100644 index 23fb015..0000000 --- a/client/views/includes/loading.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/client/views/notifications/notifications.html b/client/views/notifications/notifications.html deleted file mode 100644 index 4663d18..0000000 --- a/client/views/notifications/notifications.html +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/client/views/notifications/notifications.js.coffee b/client/views/notifications/notifications.js.coffee deleted file mode 100644 index 580968a..0000000 --- a/client/views/notifications/notifications.js.coffee +++ /dev/null @@ -1,10 +0,0 @@ -Template.notifications.helpers - notifications: -> - Notifications.find userId: Meteor.userId(), read: false - - notificationCount: => - Notifications.find(userId: Meteor.userId(), read: false).count() - -Template.notification.events - 'click a': -> - Notifications.update this._id, {$set: {read: true}} diff --git a/client/views/posts/post_edit.html b/client/views/posts/post_edit.html deleted file mode 100644 index 59548c3..0000000 --- a/client/views/posts/post_edit.html +++ /dev/null @@ -1,32 +0,0 @@ - diff --git a/client/views/posts/post_edit.js.coffee b/client/views/posts/post_edit.js.coffee deleted file mode 100644 index c43e2f3..0000000 --- a/client/views/posts/post_edit.js.coffee +++ /dev/null @@ -1,27 +0,0 @@ -Template.postEdit.helpers - post: -> - Posts.findOne Session.get 'currentPostId' - -Template.postEdit.events - 'submit form': (e) -> - e.preventDefault() - - currentPostId = Session.get 'currentPostId' - - postProperties = - url: $(e.target).find('[name=url]').val() - title: $(e.target).find('[name=title]').val() - - Posts.update currentPostId, {$set: postProperties}, (error) -> - if error - Meteor.Errors.throw error.reason - else - Meteor.Router.to 'postPage', currentPostId - - 'click .delete': (e) -> - e.preventDefault() - - if confirm 'Delete this post?' - currentPostId = Session.get 'currentPostId' - Posts.remove currentPostId - Meteor.Router.to 'postsList' diff --git a/client/views/posts/post_item.html b/client/views/posts/post_item.html deleted file mode 100644 index 09dcd88..0000000 --- a/client/views/posts/post_item.html +++ /dev/null @@ -1,18 +0,0 @@ - diff --git a/client/views/posts/post_item.js.coffee b/client/views/posts/post_item.js.coffee deleted file mode 100644 index 4a31ce9..0000000 --- a/client/views/posts/post_item.js.coffee +++ /dev/null @@ -1,38 +0,0 @@ -Template.postItem.helpers - ownPost: -> - this.userId == Meteor.userId() - - domain: -> - a = document.createElement('a') - a.href = this.url - a.hostname - - upvotedClass: -> - userId = Meteor.userId() - if userId && !_.include this.upvoters, userId - 'btn-primary upvoteable' - else - 'disabled' - -Template.postItem.events - 'click .upvoteable': (event) -> - event.preventDefault() - Meteor.call 'upvote', this._id - -Template.postItem.rendered = -> - instance = this - rank = instance.data._rank - $this = $(this.firstNode) - postHeight = 80 - newPosition = rank * postHeight - - if instance.currentPosition? - previousPosition = instance.currentPosition - delta = previousPosition - newPosition - $this.css 'top', "#{delta}px" - else - $this.addClass 'invisible' - - Meteor.defer -> - instance.currentPosition = newPosition - $this.css('top', '0px').removeClass 'invisible' diff --git a/client/views/posts/post_page.html b/client/views/posts/post_page.html deleted file mode 100644 index 993612f..0000000 --- a/client/views/posts/post_page.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/client/views/posts/post_page.js.coffee b/client/views/posts/post_page.js.coffee deleted file mode 100644 index f106efe..0000000 --- a/client/views/posts/post_page.js.coffee +++ /dev/null @@ -1,5 +0,0 @@ -Template.postPage.helpers - currentPost: -> - Posts.findOne Session.get('currentPostId') - comments: -> - Comments.find postId: this._id diff --git a/client/views/posts/post_submit.html b/client/views/posts/post_submit.html deleted file mode 100644 index 22463d6..0000000 --- a/client/views/posts/post_submit.html +++ /dev/null @@ -1,30 +0,0 @@ -