2016-09-13 17:45:13 +05:30
|
|
|
(function() {
|
|
|
|
this.AwardsHandler = (function() {
|
2016-09-29 09:46:39 +05:30
|
|
|
const FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence
|
2016-09-13 17:45:13 +05:30
|
|
|
function AwardsHandler() {
|
|
|
|
this.aliases = gl.emojiAliases();
|
|
|
|
$(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) {
|
|
|
|
return function(e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
return _this.showEmojiMenu($(e.currentTarget));
|
|
|
|
};
|
|
|
|
})(this));
|
|
|
|
$('html').on('click', function(e) {
|
|
|
|
var $target;
|
|
|
|
$target = $(e.target);
|
|
|
|
if (!$target.closest('.emoji-menu-content').length) {
|
|
|
|
$('.js-awards-block.current').removeClass('current');
|
|
|
|
}
|
|
|
|
if (!$target.closest('.emoji-menu').length) {
|
|
|
|
if ($('.emoji-menu').is(':visible')) {
|
|
|
|
$('.js-add-award.is-active').removeClass('is-active');
|
|
|
|
return $('.emoji-menu').removeClass('is-visible');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(document).off('click', '.js-emoji-btn').on('click', '.js-emoji-btn', (function(_this) {
|
|
|
|
return function(e) {
|
|
|
|
var $target, emoji;
|
|
|
|
e.preventDefault();
|
|
|
|
$target = $(e.currentTarget);
|
|
|
|
emoji = $target.find('.icon').data('emoji');
|
|
|
|
$target.closest('.js-awards-block').addClass('current');
|
|
|
|
return _this.addAward(_this.getVotesBlock(), _this.getAwardUrl(), emoji);
|
|
|
|
};
|
|
|
|
})(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
AwardsHandler.prototype.showEmojiMenu = function($addBtn) {
|
|
|
|
var $holder, $menu, url;
|
|
|
|
$menu = $('.emoji-menu');
|
|
|
|
if ($addBtn.hasClass('js-note-emoji')) {
|
|
|
|
$addBtn.closest('.note').find('.js-awards-block').addClass('current');
|
|
|
|
} else {
|
|
|
|
$addBtn.closest('.js-awards-block').addClass('current');
|
|
|
|
}
|
|
|
|
if ($menu.length) {
|
|
|
|
$holder = $addBtn.closest('.js-award-holder');
|
|
|
|
if ($menu.is('.is-visible')) {
|
|
|
|
$addBtn.removeClass('is-active');
|
|
|
|
$menu.removeClass('is-visible');
|
|
|
|
return $('#emoji_search').blur();
|
|
|
|
} else {
|
|
|
|
$addBtn.addClass('is-active');
|
|
|
|
this.positionMenu($menu, $addBtn);
|
|
|
|
$menu.addClass('is-visible');
|
|
|
|
return $('#emoji_search').focus();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$addBtn.addClass('is-loading is-active');
|
|
|
|
url = this.getAwardMenuUrl();
|
|
|
|
return this.createEmojiMenu(url, (function(_this) {
|
|
|
|
return function() {
|
|
|
|
$addBtn.removeClass('is-loading');
|
|
|
|
$menu = $('.emoji-menu');
|
|
|
|
_this.positionMenu($menu, $addBtn);
|
|
|
|
if (!_this.frequentEmojiBlockRendered) {
|
|
|
|
_this.renderFrequentlyUsedBlock();
|
|
|
|
}
|
|
|
|
return setTimeout(function() {
|
|
|
|
$menu.addClass('is-visible');
|
|
|
|
$('#emoji_search').focus();
|
|
|
|
return _this.setupSearch();
|
|
|
|
}, 200);
|
|
|
|
};
|
|
|
|
})(this));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.createEmojiMenu = function(awardMenuUrl, callback) {
|
|
|
|
return $.get(awardMenuUrl, function(response) {
|
|
|
|
$('body').append(response);
|
|
|
|
return callback();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.positionMenu = function($menu, $addBtn) {
|
|
|
|
var css, position;
|
|
|
|
position = $addBtn.data('position');
|
2016-09-29 09:46:39 +05:30
|
|
|
// The menu could potentially be off-screen or in a hidden overflow element
|
|
|
|
// So we position the element absolute in the body
|
2016-09-13 17:45:13 +05:30
|
|
|
css = {
|
|
|
|
top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px"
|
|
|
|
};
|
|
|
|
if ((position != null) && position === 'right') {
|
|
|
|
css.left = (($addBtn.offset().left - $menu.outerWidth()) + 20) + "px";
|
|
|
|
$menu.addClass('is-aligned-right');
|
|
|
|
} else {
|
|
|
|
css.left = ($addBtn.offset().left) + "px";
|
|
|
|
$menu.removeClass('is-aligned-right');
|
|
|
|
}
|
|
|
|
return $menu.css(css);
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.addAward = function(votesBlock, awardUrl, emoji, checkMutuality, callback) {
|
|
|
|
if (checkMutuality == null) {
|
|
|
|
checkMutuality = true;
|
|
|
|
}
|
|
|
|
emoji = this.normilizeEmojiName(emoji);
|
|
|
|
this.postEmoji(awardUrl, emoji, (function(_this) {
|
|
|
|
return function() {
|
|
|
|
_this.addAwardToEmojiBar(votesBlock, emoji, checkMutuality);
|
|
|
|
return typeof callback === "function" ? callback() : void 0;
|
|
|
|
};
|
|
|
|
})(this));
|
|
|
|
return $('.emoji-menu').removeClass('is-visible');
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.addAwardToEmojiBar = function(votesBlock, emoji, checkForMutuality) {
|
|
|
|
var $emojiButton, counter;
|
|
|
|
if (checkForMutuality == null) {
|
|
|
|
checkForMutuality = true;
|
|
|
|
}
|
|
|
|
if (checkForMutuality) {
|
|
|
|
this.checkMutuality(votesBlock, emoji);
|
|
|
|
}
|
|
|
|
this.addEmojiToFrequentlyUsedList(emoji);
|
|
|
|
emoji = this.normilizeEmojiName(emoji);
|
|
|
|
$emojiButton = this.findEmojiIcon(votesBlock, emoji).parent();
|
|
|
|
if ($emojiButton.length > 0) {
|
|
|
|
if (this.isActive($emojiButton)) {
|
|
|
|
return this.decrementCounter($emojiButton, emoji);
|
|
|
|
} else {
|
|
|
|
counter = $emojiButton.find('.js-counter');
|
|
|
|
counter.text(parseInt(counter.text()) + 1);
|
|
|
|
$emojiButton.addClass('active');
|
2016-09-29 09:46:39 +05:30
|
|
|
this.addYouToUserList(votesBlock, emoji);
|
2016-09-13 17:45:13 +05:30
|
|
|
return this.animateEmoji($emojiButton);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
votesBlock.removeClass('hidden');
|
|
|
|
return this.createEmoji(votesBlock, emoji);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.getVotesBlock = function() {
|
|
|
|
var currentBlock;
|
|
|
|
currentBlock = $('.js-awards-block.current');
|
|
|
|
if (currentBlock.length) {
|
|
|
|
return currentBlock;
|
|
|
|
} else {
|
|
|
|
return $('.js-awards-block').eq(0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.getAwardUrl = function() {
|
|
|
|
return this.getVotesBlock().data('award-url');
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.checkMutuality = function(votesBlock, emoji) {
|
|
|
|
var $emojiButton, awardUrl, isAlreadyVoted, mutualVote;
|
|
|
|
awardUrl = this.getAwardUrl();
|
|
|
|
if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
|
|
|
mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup';
|
|
|
|
$emojiButton = votesBlock.find("[data-emoji=" + mutualVote + "]").parent();
|
|
|
|
isAlreadyVoted = $emojiButton.hasClass('active');
|
|
|
|
if (isAlreadyVoted) {
|
|
|
|
this.addAward(votesBlock, awardUrl, mutualVote, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.isActive = function($emojiButton) {
|
|
|
|
return $emojiButton.hasClass('active');
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.decrementCounter = function($emojiButton, emoji) {
|
|
|
|
var counter, counterNumber;
|
|
|
|
counter = $('.js-counter', $emojiButton);
|
|
|
|
counterNumber = parseInt(counter.text(), 10);
|
|
|
|
if (counterNumber > 1) {
|
|
|
|
counter.text(counterNumber - 1);
|
2016-09-29 09:46:39 +05:30
|
|
|
this.removeYouFromUserList($emojiButton, emoji);
|
2016-09-13 17:45:13 +05:30
|
|
|
} else if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
|
|
|
$emojiButton.tooltip('destroy');
|
|
|
|
counter.text('0');
|
2016-09-29 09:46:39 +05:30
|
|
|
this.removeYouFromUserList($emojiButton, emoji);
|
2016-09-13 17:45:13 +05:30
|
|
|
if ($emojiButton.parents('.note').length) {
|
|
|
|
this.removeEmoji($emojiButton);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.removeEmoji($emojiButton);
|
|
|
|
}
|
|
|
|
return $emojiButton.removeClass('active');
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.removeEmoji = function($emojiButton) {
|
|
|
|
var $votesBlock;
|
|
|
|
$emojiButton.tooltip('destroy');
|
|
|
|
$emojiButton.remove();
|
|
|
|
$votesBlock = this.getVotesBlock();
|
|
|
|
if ($votesBlock.find('.js-emoji-btn').length === 0) {
|
|
|
|
return $votesBlock.addClass('hidden');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.getAwardTooltip = function($awardBlock) {
|
|
|
|
return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || '';
|
|
|
|
};
|
|
|
|
|
2016-09-29 09:46:39 +05:30
|
|
|
AwardsHandler.prototype.toSentence = function(list) {
|
|
|
|
if(list.length <= 2){
|
|
|
|
return list.join(' and ');
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
return list.slice(0, -1).join(', ') + ', and ' + list[list.length - 1];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.removeYouFromUserList = function($emojiButton, emoji) {
|
2016-09-13 17:45:13 +05:30
|
|
|
var authors, awardBlock, newAuthors, originalTitle;
|
|
|
|
awardBlock = $emojiButton;
|
|
|
|
originalTitle = this.getAwardTooltip(awardBlock);
|
2016-09-29 09:46:39 +05:30
|
|
|
authors = originalTitle.split(FROM_SENTENCE_REGEX);
|
|
|
|
authors.splice(authors.indexOf('You'), 1);
|
|
|
|
return awardBlock
|
|
|
|
.closest('.js-emoji-btn')
|
|
|
|
.removeData('title')
|
|
|
|
.removeAttr('data-title')
|
|
|
|
.removeAttr('data-original-title')
|
|
|
|
.attr('title', this.toSentence(authors))
|
|
|
|
.tooltip('fixTitle');
|
2016-09-13 17:45:13 +05:30
|
|
|
};
|
|
|
|
|
2016-09-29 09:46:39 +05:30
|
|
|
AwardsHandler.prototype.addYouToUserList = function(votesBlock, emoji) {
|
2016-09-13 17:45:13 +05:30
|
|
|
var awardBlock, origTitle, users;
|
|
|
|
awardBlock = this.findEmojiIcon(votesBlock, emoji).parent();
|
|
|
|
origTitle = this.getAwardTooltip(awardBlock);
|
|
|
|
users = [];
|
|
|
|
if (origTitle) {
|
2016-09-29 09:46:39 +05:30
|
|
|
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
2016-09-13 17:45:13 +05:30
|
|
|
}
|
2016-09-29 09:46:39 +05:30
|
|
|
users.unshift('You');
|
|
|
|
return awardBlock
|
|
|
|
.attr('title', this.toSentence(users))
|
|
|
|
.tooltip('fixTitle');
|
2016-09-13 17:45:13 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) {
|
|
|
|
var $emojiButton, buttonHtml, emojiCssClass;
|
|
|
|
emojiCssClass = this.resolveNameToCssClass(emoji);
|
2016-09-29 09:46:39 +05:30
|
|
|
buttonHtml = "<button class='btn award-control js-emoji-btn has-tooltip active' title='You' data-placement='bottom'> <div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div> <span class='award-control-text js-counter'>1</span> </button>";
|
2016-09-13 17:45:13 +05:30
|
|
|
$emojiButton = $(buttonHtml);
|
|
|
|
$emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('emoji', emoji);
|
|
|
|
this.animateEmoji($emojiButton);
|
|
|
|
$('.award-control').tooltip();
|
|
|
|
return votesBlock.removeClass('current');
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.animateEmoji = function($emoji) {
|
2016-09-29 09:46:39 +05:30
|
|
|
var className = 'pulse animated once short';
|
2016-09-13 17:45:13 +05:30
|
|
|
$emoji.addClass(className);
|
2016-09-29 09:46:39 +05:30
|
|
|
|
|
|
|
$emoji.on('webkitAnimationEnd animationEnd', function() {
|
|
|
|
$(this).removeClass(className);
|
|
|
|
});
|
2016-09-13 17:45:13 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.createEmoji = function(votesBlock, emoji) {
|
|
|
|
if ($('.emoji-menu').length) {
|
|
|
|
return this.createEmoji_(votesBlock, emoji);
|
|
|
|
}
|
|
|
|
return this.createEmojiMenu(this.getAwardMenuUrl(), (function(_this) {
|
|
|
|
return function() {
|
|
|
|
return _this.createEmoji_(votesBlock, emoji);
|
|
|
|
};
|
|
|
|
})(this));
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.getAwardMenuUrl = function() {
|
|
|
|
return gon.award_menu_url;
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.resolveNameToCssClass = function(emoji) {
|
|
|
|
var emojiIcon, unicodeName;
|
|
|
|
emojiIcon = $(".emoji-menu-content [data-emoji='" + emoji + "']");
|
|
|
|
if (emojiIcon.length > 0) {
|
|
|
|
unicodeName = emojiIcon.data('unicode-name');
|
|
|
|
} else {
|
2016-09-29 09:46:39 +05:30
|
|
|
// Find by alias
|
2016-09-13 17:45:13 +05:30
|
|
|
unicodeName = $(".emoji-menu-content [data-aliases*=':" + emoji + ":']").data('unicode-name');
|
|
|
|
}
|
|
|
|
return "emoji-" + unicodeName;
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.postEmoji = function(awardUrl, emoji, callback) {
|
|
|
|
return $.post(awardUrl, {
|
|
|
|
name: emoji
|
|
|
|
}, function(data) {
|
|
|
|
if (data.ok) {
|
|
|
|
return callback();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.findEmojiIcon = function(votesBlock, emoji) {
|
|
|
|
return votesBlock.find(".js-emoji-btn [data-emoji='" + emoji + "']");
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.scrollToAwards = function() {
|
|
|
|
var options;
|
|
|
|
options = {
|
|
|
|
scrollTop: $('.awards').offset().top - 110
|
|
|
|
};
|
|
|
|
return $('body, html').animate(options, 200);
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.normilizeEmojiName = function(emoji) {
|
|
|
|
return this.aliases[emoji] || emoji;
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.addEmojiToFrequentlyUsedList = function(emoji) {
|
|
|
|
var frequentlyUsedEmojis;
|
|
|
|
frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
|
|
|
frequentlyUsedEmojis.push(emoji);
|
|
|
|
return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), {
|
2016-09-29 09:46:39 +05:30
|
|
|
path: gon.relative_url_root || '/',
|
2016-09-13 17:45:13 +05:30
|
|
|
expires: 365
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.getFrequentlyUsedEmojis = function() {
|
|
|
|
var frequentlyUsedEmojis;
|
|
|
|
frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || '').split(',');
|
|
|
|
return _.compact(_.uniq(frequentlyUsedEmojis));
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.renderFrequentlyUsedBlock = function() {
|
|
|
|
var emoji, frequentlyUsedEmojis, i, len, ul;
|
|
|
|
if ($.cookie('frequently_used_emojis')) {
|
|
|
|
frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
|
|
|
ul = $("<ul class='clearfix emoji-menu-list frequent-emojis'>");
|
|
|
|
for (i = 0, len = frequentlyUsedEmojis.length; i < len; i++) {
|
|
|
|
emoji = frequentlyUsedEmojis[i];
|
|
|
|
$(".emoji-menu-content [data-emoji='" + emoji + "']").closest('li').clone().appendTo(ul);
|
|
|
|
}
|
|
|
|
$('.emoji-menu-content').prepend(ul).prepend($('<h5>').text('Frequently used'));
|
|
|
|
}
|
|
|
|
return this.frequentEmojiBlockRendered = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.setupSearch = function() {
|
|
|
|
return $('input.emoji-search').on('keyup', (function(_this) {
|
|
|
|
return function(ev) {
|
|
|
|
var found_emojis, h5, term, ul;
|
|
|
|
term = $(ev.target).val();
|
2016-09-29 09:46:39 +05:30
|
|
|
// Clean previous search results
|
2016-09-13 17:45:13 +05:30
|
|
|
$('ul.emoji-menu-search, h5.emoji-search').remove();
|
|
|
|
if (term) {
|
2016-09-29 09:46:39 +05:30
|
|
|
// Generate a search result block
|
2016-10-01 15:18:49 +05:30
|
|
|
h5 = $('<h5 class="emoji-search" />').text('Search results');
|
2016-09-13 17:45:13 +05:30
|
|
|
found_emojis = _this.searchEmojis(term).show();
|
|
|
|
ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(found_emojis);
|
|
|
|
$('.emoji-menu-content ul, .emoji-menu-content h5').hide();
|
|
|
|
return $('.emoji-menu-content').append(h5).append(ul);
|
|
|
|
} else {
|
|
|
|
return $('.emoji-menu-content').children().show();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
})(this));
|
|
|
|
};
|
|
|
|
|
|
|
|
AwardsHandler.prototype.searchEmojis = function(term) {
|
|
|
|
return $(".emoji-menu-list:not(.frequent-emojis) [data-emoji*='" + term + "']").closest('li').clone();
|
|
|
|
};
|
|
|
|
|
|
|
|
return AwardsHandler;
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
}).call(this);
|