var timezone = 'America/New_York'; var contentApp = angular.module('content', ['ngSanitize']) .config(function ($interpolateProvider, $httpProvider){ $interpolateProvider.startSymbol('{[').endSymbol(']}'); $httpProvider.defaults.xsrfCookieName = CSRF_COOKIE_NAME; $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; }); contentApp.filter('date_format', function () { return function (ts) { if (!ts) { return ''; } return moment.tz(ts, timezone).format("MMMM D, YYYY"); } }); contentApp.filter('date_ago', function () { return function (ts) { if (!ts) { return ''; } return moment.tz(ts, timezone).fromNow(); } }); contentApp.filter('can_edit', function () { return function (date) { date = moment.tz(date, timezone); // Make sure it's no more than 10 minutes difference return (moment().tz(timezone).diff(date, 'seconds') < 600); } }); contentApp.filter('urlize', function ($sce) { return function (text) { return $sce.trustAsHtml(urlize(text, {nofollow: false, trim_url_limit: 25, target: '_blank'})) } }); contentApp.directive('bindCtrlEnter', function () { return function (scope, element, attrs) { element.keydown(function (e) { if(e.keyCode == 13 && (e.metaKey || e.ctrlKey)) { scope.$apply(attrs.bindCtrlEnter); return false; } }); }; }); contentApp.factory('CommentService', function ($http, $rootScope, $q) { return { getComments: function (contentId) { /* getComments - Takes the ID of a content object to get comments for */ var deferred = $q.defer(); $http.get('/api/v2/products/content/' + contentId + '/comments/') .success(function (d) { deferred.resolve(d); }) .error(function (d, status) { }); return deferred.promise; }, postComment: function (contentId, comment) { var deferred = $q.defer(); $http.post('/api/v2/products/content/'+ contentId + '/comments/', {'comment': comment}) .success(function (d) { deferred.resolve(d); }) .error(function (d, status) { deferred.reject(d); }); return deferred.promise; }, editComment: function (commentId, comment) { var deferred = $q.defer(); $http.put('/api/v2/products/comment/'+ commentId + '/', {'comment': comment}) .success(function (d) { deferred.resolve(d); }) .error(function (d, status) { }); return deferred.promise; }, deleteComment: function (commentId) { var deferred = $q.defer(); $http({ method: 'DELETE', url: '/api/v2/products/comment/' + commentId + '/' }).success(function (d) { deferred.resolve(d); }).error(function (d, status) { }); return deferred.promise; }, blockUser: function (commentObj,productUrl) { var deferred = $q.defer(); $.post(productUrl+'block_user/', {'comment_author': commentObj.username}) .success(function (d) { deferred.resolve(d); }) .error(function (d, status) { }); return deferred.promise; }, checkBlocked: function (productUrl, authorID) { var deferred = $q.defer(); $.post(productUrl + 'check_comment_block/', {'author_id': authorID}) .success(function (d) { deferred.resolve(d); }) .error(function (d, status) { }); return deferred.promise; } } }); contentApp.controller('commentsCtrl', ['$scope', '$attrs', 'CommentService', '$timeout', function ($scope, $attrs, CommentService, $timeout) { if (!$attrs.content) throw new Error('No content ID given for commentsCtrl'); $scope.isLoaded = false; $scope.isPosting = false; $scope.contentId = $attrs.content; $scope.authorId = $attrs.author; $scope.comments = []; $scope.comment = ''; $scope.user = currentUser; $scope.notificationChannel = $attrs.channel; $scope.sortOrder = '+date_posted'; $scope.filterBy = {}; $scope.product_link = productLink; // Setup auto-redraw for dates var refreshDates = function() { $timeout(refreshDates, 10000); }; refreshDates(); // Loads comment feed $scope.loadComments = function () { CommentService.getComments($scope.contentId).then(function (data) { $scope.comments = data; $scope.isLoaded = true; $scope.checkBlock(); }, function (error) { $scope.isUnavailable = true; }); }; // Hit it up!! Let's initialize the comment feed $scope.loadComments(); $scope.checkBlock = function() { CommentService.checkBlocked($scope.product_link, $scope.authorId).then(function (data) { $scope.canComment = data.data; }, function (error) { console.log(error); }); }; // Filtering and sorting of comments $scope.queryComments = function (q) { switch (q) { // Filter by Maven case 'maven': $scope.filterBy = {is_maven: true}; $scope.sortOrder = '+date_posted'; break; // Default is to sort by the filterVal default: $scope.sortOrder = q; $scope.filterBy = {}; } }; // Handle the posting of new comments $scope.postComment = function (comment) { if ($scope.isPosting) { return; } $scope.isPosting = true; CommentService.postComment($scope.contentId, comment).then(function (data) { $scope.comment = ''; $scope.isPosting = false; $scope.addComment(data, true); }, function (error) { console.log(error); $scope.isPosting = false; }); }; // Handle the editing of comments $scope.editComment = function (commentObj) { commentObj.isEditing = true; commentObj.originalComment = commentObj.comment; }; // Cancel editing of a comment $scope.cancelEdit = function (commentObj) { commentObj.comment = commentObj.originalComment; commentObj.isEditing = false; }; // Save comment edits $scope.saveEdit = function (commentObj) { CommentService.editComment(commentObj.id, commentObj.comment).then(function (data) { // Copy new values over for (var key in data) { if (data.hasOwnProperty(key)) { commentObj[key] = data[key]; } } commentObj.isEditing = false; }, function (error) { console.log(error); }); }; // Delete a comment $scope.deleteComment = function (commentObj) { if(!confirm('Are you sure you want to delete this comment?')){ return; } CommentService.deleteComment(commentObj.id).then(function (data) { document.getElementById('comment-' + commentObj.id).remove() }, function (error) { console.log(error); }); }; // Block a user $scope.blockUser = function (commentObj,productUrl) { if(!confirm('Are you sure you want to block this user?')){ return; } CommentService.blockUser(commentObj,productUrl).then(function (data) { window.location.reload(); }, function (error) { console.log(error); }); }; // Open message modal $scope.composeMessage = function (user) { if (!currentUser) { window.location.href = '/account/signup/'; } else { if (currentUser && currentUser.id == user.id) return false; if ($('#block-or-message-modal').hasClass('in')) { $('#block-or-message-modal').modal('hide'); } $scope.message_to = user; $('#comment-message-modal').modal(); } }; $scope.blockormessageUser = function (user, productURL) { if (!currentUser) { window.location.href = '/account/signup/'; } else { if (currentUser && currentUser.id == user.id) return false; $scope.commenting_user = user; $scope.product_url = productURL; $('#block-or-message-modal').modal(); } }; // ---- Internal Utilities ---- // Adds a comment to the list after making sure it doesn't exist $scope.addComment = function (commentObj, scrollTo) { var exists = false; for (var i=0; i < $scope.comments.length; i++) { if ($scope.comments[i].id === commentObj.id) { exists = true; } } if (!exists) { $scope.comments.push(commentObj); } // Even if it already exists, we want to scroll to it if scrollTo is true if (scrollTo === true) { // Give Angular time to render just in case setTimeout(function () { window.scrollTo(0, document.getElementById('comment-' + commentObj.id).offsetTop) }, 10); } }; if ($scope.user) { // Subscribe and listen to push notifications Mkfy.subscribe($scope.notificationChannel, function (data) { if(data.content == $scope.contentId) { $scope.addComment(data); } }, 'comment'); } else { $scope.comment = 'You need to login in order to post comments!'; } }]);