Switching from manually generating urls to using IronRouter functions.

Using {{pathFor}}, path(), and url() where possible. Passing in path
to Meteor.absoluteUrl() where the IronRouter functions didn't make sense.
Also deleting some random unused code.
This commit is contained in:
Anthony Mayer 2014-12-03 00:06:00 -08:00
parent 93e201de5f
commit 23b72b9cb8
23 changed files with 105 additions and 104 deletions

View file

@ -2,5 +2,5 @@
<title>Loading...</title>
<meta name="viewport" content="initial-scale=1.0">
<link rel="shortcut icon" href="/img/favicon.ico"/>
<link id="rss-link" rel="alternate" type="application/rss+xml" title="New Posts" href="/feed.xml"/>
<link id="rss-link" rel="alternate" type="application/rss+xml" title="New Posts" href="{{pathFor route='feed'}}"/>
</head>

View file

@ -29,18 +29,17 @@ Template[getTemplate('comment_edit')].events({
});
trackEvent("edit comment", {'postId': comment.postId, 'commentId': comment._id});
Router.go("/posts/"+comment.postId+"/comment/"+comment._id);
Router.go('post_page_comment', {_id: comment.postId, commentId: comment._id});
},
'click .delete-link': function(e){
var comment = this;
e.preventDefault();
if(confirm(i18n.t("are_you_sure"))){
Meteor.call('removeComment', comment._id);
Router.go("/posts/"+comment.postId);
Router.go('post_page', {_id: comment.postId});
throwError("Your comment has been deleted.");
// Router.go("/comments/deleted");
}
}
});

View file

@ -28,7 +28,10 @@ Template[getTemplate('comment_form')].events({
throwError(error.reason);
}else{
trackEvent("newComment", newComment);
Router.go('/posts/'+parentComment.postId+'/comment/'+newComment._id);
Router.go('post_page_comment', {
_id: parentComment.postId,
commentId: newComment._id
});
}
});
}else{

View file

@ -21,9 +21,9 @@
<a class="comment-username" href="{{profileUrl}}">{{authorName}}</a>
<span class="comment-time">{{timeAgo ago}},</span>
<span class="points">{{upvotes}}</span> <span class="unit">points </span>
<a href="/comments/{{_id}}" class="comment-permalink icon-link goto-comment">{{_ "link"}}</a>
<a href="{{pathFor route='comment_reply' _id=_id}}" class="comment-permalink icon-link goto-comment">{{_ "link"}}</a>
{{#if can_edit}}
| <a class="edit-link" href="/comments/{{_id}}/edit">{{_ "edit"}}</a>
| <a class="edit-link" href="{{pathFor route='comment_edit' _id=_id}}">{{_ "edit"}}</a>
{{/if}}
{{#if isAdmin}}
| <span>{{full_date}}</span>
@ -31,7 +31,7 @@
</div>
<div class="comment-text markdown">{{{htmlBody}}}</div>
{{#if getSetting "nestedComments" true}}
<a href="/comments/{{_id}}" class="comment-reply goto-comment">{{_ "reply"}}</a>
<a href="{{pathFor route='comment_reply' _id=_id}}" class="comment-reply goto-comment">{{_ "reply"}}</a>
{{/if}}
</div>
</div>

View file

@ -21,8 +21,8 @@
color: {{getSetting "headerTextColor"}};
}
.logo-image a{
height:{{getSetting "logoHeight"}}px;
width:{{getSetting "logoWidth"}}px;
height:{{getSetting "logoHeight"}}px;
width:{{getSetting "logoWidth"}}px;
}
</style>
</template>

View file

@ -28,7 +28,7 @@ Template[getTemplate('nav')].helpers({
},
logo_top: function(){
return Math.floor((70-getSetting('logoHeight'))/2);
},
},
logo_offset: function(){
return -Math.floor(getSetting('logoWidth')/2);
},
@ -43,30 +43,9 @@ Template[getTemplate('nav')].helpers({
}
});
Template[getTemplate('nav')].rendered = function(){
if(!Meteor.loggingIn() && !Meteor.user()){
$('.login-link-text').text("Sign Up/Sign In");
}
};
Template[getTemplate('nav')].events({
'click #logout': function(e){
e.preventDefault();
Meteor.logout();
},
'click .mobile-menu-button': function(e){
e.preventDefault();
$('body').toggleClass('mobile-nav-open');
},
'click .login-header': function(e){
e.preventDefault();
Router.go('/account');
},
'click #login-name-link': function(){
if(Meteor.user() && !$('account-link').exists()){
var $loginButtonsLogout = $('#login-buttons-logout');
$loginButtonsLogout.before('<a href="/users/'+Meteor.user().slug+'" class="account-link button">View Profile</a>');
$loginButtonsLogout.before('<a href="/account" class="account-link button">Edit Account</a>');
}
}
});

View file

@ -11,7 +11,7 @@
</div>
</div>
{{else}}
<a class="account-link sign-in" href="/sign-in">{{_ "sign_in"}}</a>
<a class="account-link sign-up" href="/sign-up">{{_ "sign_up"}}</a>
<a class="account-link sign-in" href="{{pathFor route='atSignIn'}}">{{_ "sign_in"}}</a>
<a class="account-link sign-up" href="{{pathFor route='atSignUp'}}">{{_ "sign_up"}}</a>
{{/if}}
</template>

View file

@ -2,7 +2,7 @@
<div class="post-meta-item">
<span class="points">{{baseScore}} <span class="unit">{{pointsUnitDisplayText}} </span></span>by <a class="post-author" href="{{profileUrl}}">{{authorName}}</a> <span class="post-time">{{timeAgo ago}}</span>
{{#if can_edit}}
| <a href="/posts/{{_id}}/edit" class="edit-link goto-edit">{{_ "edit"}}</a>
| <a href="{{pathFor route='post_edit' _id=_id}}" class="edit-link goto-edit">{{_ "edit"}}</a>
{{/if}}
</div>
</template>

View file

@ -9,7 +9,7 @@ Template[getTemplate('postInfo')].helpers({
return getAuthorName(this);
},
ago: function(){
// if post is approved show submission time, else show creation time.
// if post is approved show submission time, else show creation time.
time = this.status == STATUS_APPROVED ? this.postedAt : this.createdAt;
return time;
},

View file

@ -26,7 +26,7 @@ AutoForm.hooks({
}else{
// note: find a way to do this in onSuccess instead?
trackEvent("edit post", {'postId': post._id});
Router.go('/posts/'+post._id);
Router.go('post_page', {_id: post._id});
submit.done();
}
});
@ -41,7 +41,7 @@ AutoForm.hooks({
// if(post.status === STATUS_PENDING)
// throwError('Thanks, your post is awaiting approval.');
// Router.go('/posts/'+post._id);
},
},
onError: function(operation, error, template) {
console.log(error)

View file

@ -28,9 +28,10 @@ AutoForm.hooks({
}else{
// note: find a way to do this in onSuccess instead?
trackEvent("new post", {'postId': post._id});
if(post.status === STATUS_PENDING)
if (post.status === STATUS_PENDING) {
throwError('Thanks, your post is awaiting approval.');
Router.go('/posts/'+post._id);
}
Router.go('post_page', {_id: post._id});
submit.done();
}
});
@ -45,7 +46,7 @@ AutoForm.hooks({
// if(post.status === STATUS_PENDING)
// throwError('Thanks, your post is awaiting approval.');
// Router.go('/posts/'+post._id);
},
},
onError: function(operation, error, template) {
throwError(error.reason.split('|')[0]); // workaround because error.details returns undefined

View file

@ -11,7 +11,7 @@
{{/if}}
</div>
</div>
{{> UI.dynamic template=postsListIncoming data=incoming}}
{{#if hasPosts}}

View file

@ -15,7 +15,7 @@ Template[getTemplate('user_edit')].helpers({
return getGitHubName(this) || "";
},
profileUrl: function(){
return Meteor.absoluteUrl()+"users/"+this.slug;
return getProfileUrlBySlugOrId(this.slug);
},
hasNotificationsUsers : function(){
return getUserSetting('notifications.users', '', this) ? 'checked' : '';

View file

@ -65,7 +65,7 @@
</thead>
{{#each posts}}
<tr>
<td><a href="/posts/{{_id}}/">{{title}}</a></td>
<td><a href="{{pathFor route='post_page' _id=_id}}">{{title}}</a></td>
<td>{{formatDate createdAt "MM/DD/YYYY, HH:mm"}}</td>
</tr>
{{/each}}
@ -90,7 +90,7 @@
</thead>
{{#each upvotedPosts}}
<tr>
<td><a href="/posts/{{_id}}/">{{title}}</a></td>
<td><a href="{{pathFor route='post_page' _id=_id}}">{{title}}</a></td>
<td>{{formatDate votedAt "MM/DD/YYYY, HH:mm"}}</td>
</tr>
{{/each}}
@ -115,7 +115,7 @@
</thead>
{{#each downvoted}}
<tr>
<td><a href="/posts/{{_id}}/">{{title}}</a></td>
<td><a href="{{pathFor route='post_page' _id=_id}}">{{title}}</a></td>
<td>{{formatDate votedAt "MM/DD/YYYY, HH:mm"}}</td>
</tr>
{{/each}}
@ -141,7 +141,7 @@
</thead>
{{#each comments}}
<tr>
<td><a href="/posts/{{postId}}/">{{postTitle}}</a></td>
<td><a href="{{pathFor route='post_page' _id=postId}}/">{{postTitle}}</a></td>
<td>{{{htmlBody}}}</td>
<td>{{formatDate createdAt "MM/DD/YYYY, HH:mm"}}</td>
</tr>

View file

@ -39,7 +39,7 @@ postSchemaObject = {
editable: true,
type: "bootstrap-url"
}
},
},
title: {
type: String,
optional: false,
@ -188,7 +188,7 @@ postSchemaObject = {
return {
value: user._id,
label: getDisplayName(user)
}
}
});
}
}
@ -229,12 +229,12 @@ getPostProperties = function (post) {
var p = {
postAuthorName : getDisplayName(postAuthor),
postTitle : cleanUp(post.title),
profileUrl: getProfileUrlById(post.userId),
profileUrl: getProfileUrlBySlugOrId(post.userId),
postUrl: getPostPageUrl(post),
thumbnailUrl: post.thumbnailUrl,
linkUrl: !!post.url ? getOutgoingUrl(post.url) : getPostPageUrl(post._id)
};
if(post.url)
p.url = post.url;
@ -265,7 +265,7 @@ checkForPostsWithSameUrl = function (url) {
if(typeof postWithSameLink !== 'undefined'){
Meteor.call('upvotePost', postWithSameLink);
// note: error.details returns undefined on the client, so add post ID to reason
// note: error.details returns undefined on the client, so add post ID to reason
throw new Meteor.Error('603', i18n.t('this_link_has_already_been_posted') + '|' + postWithSameLink._id, postWithSameLink._id);
}
}
@ -351,9 +351,9 @@ Meteor.methods({
inactive: false
};
// UserId
// UserId
if(isAdmin(Meteor.user()) && !!post.userId){ // only let admins post as other users
properties.userId = post.userId;
properties.userId = post.userId;
}
// Status
@ -361,7 +361,7 @@ Meteor.methods({
if(isAdmin(Meteor.user()) && !!post.status){ // if user is admin and a custom status has been set
properties.status = post.status;
}else{ // else use default status
properties.status = defaultPostStatus;
properties.status = defaultPostStatus;
}
// CreatedAt
@ -450,7 +450,7 @@ Meteor.methods({
setPostedAt: function(post, customPostedAt){
var postedAt = new Date(); // default to current date and time
if(isAdmin(Meteor.user()) && typeof customPostedAt !== 'undefined') // if user is admin and a custom datetime has been set
postedAt = customPostedAt;
@ -508,7 +508,7 @@ Meteor.methods({
// decrement post count
var post = Posts.findOne({_id: postId});
if(!Meteor.userId() || !canEditById(Meteor.userId(), post)) throw new Meteor.Error(606, 'You need permission to edit or delete a post');
Meteor.users.update({_id: post.userId}, {$inc: {postCount: -1}});
Posts.remove(postId);
}

View file

@ -12,19 +12,23 @@ t=function(message){
var d=new Date();
console.log("### "+message+" rendered at "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds());
};
nl2br= function(str) {
var breakTag = '<br />';
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
nl2br= function(str) {
var breakTag = '<br />';
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
};
getAuthorName = function(item){
var user = Meteor.users.findOne(item.userId);
return typeof user === 'undefined' ? '' : getDisplayName(user);
};
scrollPageTo = function(selector){
$('body').scrollTop($(selector).offset().top);
$('body').scrollTop($(selector).offset().top);
};
getDigestURL = function(moment){
return '/digest/'+moment.year()+'/'+(moment.month()+1)+'/'+moment.date();
return Router.routes['posts_digest'].path({
year: moment.year(),
month: moment.month() + 1,
day: moment.date()
});
};
getDateRange= function(pageNumber){
var now = moment(new Date());
@ -50,24 +54,27 @@ goTo = function(url){
};
getSignupUrl = function(){
return Meteor.absoluteUrl()+'sign-up';
return Router.routes['atSignUp'].url();
};
getSigninUrl = function(){
return Meteor.absoluteUrl()+'sign-in';
return Router.routes['atSignIn'].url();
};
getPostUrl = function(id){
return Meteor.absoluteUrl()+'posts/'+id;
return Router.routes['post_page'].url({_id: id});
};
getPostEditUrl = function(id){
return Meteor.absoluteUrl()+'posts/'+id+'/edit';
return Router.routes['post_edit'].url({_id: id});
};
getCommentUrl = function(id){
return Meteor.absoluteUrl()+'comments/'+id;
return Router.routes['comment_reply'].url({_id: id});
};
getPostCommentUrl = function(postId, commentId){
// get link to a comment on a post page
return Meteor.absoluteUrl()+'posts/'+postId+'/comment/'+commentId;
return Router.routes['post_page_comment'].url({
_id: postId,
commentId: commentId
});
};
slugify = function(text) {
if(text){
@ -78,7 +85,7 @@ slugify = function(text) {
return text;
};
getShortUrl = function(post){
return post.shortUrl ? post.shortUrl : post.url;
return post.shortUrl || post.url;
};
getDomain = function(url){
urlObject = Npm.require('url');
@ -88,7 +95,7 @@ invitesEnabled = function () {
return getSetting("requireViewInvite") || getSetting("requirePostInvite");
};
getOutgoingUrl = function(url){
return getSiteUrl() + 'out?url=' + encodeURIComponent(url);
return Router.routes['out'].url({}, {query: {url: url}});
};
// ---------------------------------- String Helper Functions ----------------------------------- //
cleanUp = function(s){
@ -99,11 +106,11 @@ sanitize = function (s) {
// console.log(s)
if(Meteor.isServer){
var s = sanitizeHtml(s, {
allowedTags: [
'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul',
'ol', 'nl', 'li', 'b', 'i', 'strong', 'em', 'strike',
'code', 'hr', 'br', 'div', 'table', 'thead', 'caption',
'tbody', 'tr', 'th', 'td', 'pre', 'img'
allowedTags: [
'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul',
'ol', 'nl', 'li', 'b', 'i', 'strong', 'em', 'strike',
'code', 'hr', 'br', 'div', 'table', 'thead', 'caption',
'tbody', 'tr', 'th', 'td', 'pre', 'img'
]
});
// console.log('// after sanitization:')

View file

@ -141,7 +141,7 @@ Meteor.startup( function (){
Session.set('categorySlug', null);
// if we're not on the search page itself, clear search query and field
if(getCurrentRoute().indexOf('search') == -1){
if(Router.current().route.getName() !== 'search'){
Session.set('searchQuery', '');
$('.search-field').val('').blur();
}

View file

@ -42,13 +42,10 @@ getDisplayNameById = function(userId){
return getDisplayName(Meteor.users.findOne(userId));
};
getProfileUrl = function(user) {
return Meteor.absoluteUrl()+'users/' + slugify(getUserName(user));
return getProfileUrlBySlugOrId(user.slug);
};
getProfileUrlById = function(id){
return Meteor.absoluteUrl()+'users/'+ id;
};
getProfileUrlBySlug = function(slug) {
return Meteor.absoluteUrl()+'users/' + slug;
getProfileUrlBySlugOrId = function(slugOrId) {
return Router.routes['user_profile'].url({_idOrSlug: slugOrId});
};
hasPassword = function(user) {
return !!user.services.password;
@ -77,8 +74,8 @@ getTwitterNameById = function(userId){
getEmail = function(user){
if(user.profile && user.profile.email){
return user.profile.email;
}else{
return null;
}else{
return null;
}
};
getEmailHash = function(user){

View file

@ -1,5 +1,5 @@
Meteor.startup(function () {
Herald.collection.deny({
update: ! can.editById,
remove: ! can.editById
@ -27,7 +27,7 @@ var getCommenterProfileUrl = function (comment) {
if(user) {
return getProfileUrl(user);
} else {
return getProfileUrlById(comment.userId)
return getProfileUrlBySlugOrId(comment.userId)
}
}
@ -37,7 +37,7 @@ var getAuthor = function (comment) {
return getUserName(user);
} else {
return comment.author;
}
}
}
Herald.addCourier('newPost', {

View file

@ -1,14 +1,14 @@
getUnsubscribeLink = function(user){
return Meteor.absoluteUrl()+'unsubscribe/'+user.email_hash;
return Router.routes['unsubscribe'].url({hash: user.email_hash});
};
// given a notification, return the correct subject and html to send an email
buildEmailNotification = function (notification) {
var subject, template;
var post = notification.data.post;
var comment = notification.data.comment;
switch(notification.courier){
case 'newReply':
subject = 'Someone replied to your comment on "'+post.title+'"';
@ -18,7 +18,7 @@ buildEmailNotification = function (notification) {
case 'newComment':
subject = 'A new comment on your post "'+post.title+'"';
template = 'emailNewComment';
break;
break;
default:
break;
@ -26,7 +26,7 @@ buildEmailNotification = function (notification) {
var emailProperties = _.extend(notification.data, {
body: marked(comment.body),
profileUrl: getProfileUrlById(comment.userId),
profileUrl: getProfileUrlBySlugOrId(comment.userId),
postCommentUrl: getPostCommentUrl(post._id, comment._id),
postLink: getPostLink(post)
});

View file

@ -5,34 +5,49 @@ Meteor.startup(function () {
Router.route('/feed.xml', function () {
this.response.write(servePostRSS('new', 'feed.xml'));
this.response.end();
}, {where: 'server'});
}, {
name: 'feed',
where: 'server'
});
// New Post RSS
Router.route('/rss/posts/new.xml', function () {
this.response.write(servePostRSS('top', 'rss/posts/new.xml'));
this.response.end();
}, {where: 'server'});
}, {
name: 'rss_posts_new',
where: 'server'
});
// Top Post RSS
Router.route('/rss/posts/top.xml', function () {
this.response.write(servePostRSS('top', 'rss/posts/top.xml'));
this.response.end();
}, {where: 'server'});
}, {
name: 'rss_posts_top',
where: 'server'
});
// Best Post RSS
Router.route('/rss/posts/best.xml', function () {
this.response.write(servePostRSS('best', 'rss/posts/best.xml'));
this.response.end();
}, {where: 'server'});
}, {
name: 'rss_posts_best',
where: 'server'
});
// Comment RSS
Router.route('/rss/comments.xml', function() {
this.response.write(serveCommentRSS());
this.response.end();
}, {where: 'server'});
}, {
name: 'rss_comments',
where: 'server'
});
});

View file

@ -4,9 +4,9 @@ var getMeta = function(url) {
return {
title: getSetting('title'),
description: getSetting('tagline'),
feed_url: Meteor.absoluteUrl()+url,
feed_url: Meteor.absoluteUrl(url),
site_url: Meteor.absoluteUrl(),
image_url: Meteor.absoluteUrl()+'img/favicon.png',
image_url: Meteor.absoluteUrl('img/favicon.png'),
};
};
@ -32,7 +32,7 @@ servePostRSS = function(view, url) {
};
serveCommentRSS = function() {
var feed = new RSS(getMeta('rss/comments.xml'));
var feed = new RSS(getMeta(Router.routes['rss_comments'].path()));
Comments.find({isDeleted: {$ne: true}}, {sort: {postedAt: -1}, limit: 20}).forEach(function(comment) {
post = Posts.findOne(comment.postId);

View file

@ -30,7 +30,7 @@ Meteor.startup(function () {
// if search field is empty, just do nothing and show an empty template
$search.addClass('empty');
Session.set('searchQuery', '');
Router.go('/search', null, {replaceState: true});
Router.go('search', null, {replaceState: true});
} else {
$search.removeClass('empty');
// if search field is not empty, add a delay to avoid firing new searches for every keystroke
@ -38,10 +38,10 @@ Meteor.startup(function () {
Session.set('searchQuery', val);
// Update the querystring.
var opts = {query: 'q=' + encodeURIComponent(val)};
var opts = {query: {q: val}};
// if we're already on the search page, do a replaceState. Otherwise,
// just use the pushState default.
if(getCurrentRoute().indexOf('/search') === 0) {
if(Router.current().route.getName() === 'search') {
opts.replaceState = true;
}
Router.go('search', null, opts);