69e4072f89
* master: (389 commits)
Document "No gems fetched from git repositories" policy [ci skip]
Typos
Small gramatical tweaks
Typos
Added PHP & NPM doc
Use `:empty_project` where possible in request specs
Add caching of droplab ajax requests
Use `:empty_project` where possible in model specs
Revert 3f17f29a
Remove unused js response from refs controller
Add MR id to changelog entry
fixed small mini pipeline graph line glitch
Prevent form to be submitted twice
Fix Error 500 when repositories contain annotated tags pointing to blobs
Fix /explore sorting (trending)
Simplify wording in "adding an image" docs
Remove "official merge window" from CONTRIBUTING.md [ci skip]
Update repository check documentation
Fixed flexbox and wrap issues
Update two_factor_authentication.md
...
380 lines
14 KiB
JavaScript
380 lines
14 KiB
JavaScript
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, brace-style, no-underscore-dangle, no-return-assign, camelcase */
|
|
/* global Cookies */
|
|
|
|
var emojiAliases = require('emoji-aliases');
|
|
|
|
(function() {
|
|
this.AwardsHandler = (function() {
|
|
var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence
|
|
function AwardsHandler() {
|
|
this.aliases = 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');
|
|
// The menu could potentially be off-screen or in a hidden overflow element
|
|
// So we position the element absolute in the body
|
|
css = {
|
|
top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px"
|
|
};
|
|
if (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(), 10) + 1);
|
|
$emojiButton.addClass('active');
|
|
this.addYouToUserList(votesBlock, emoji);
|
|
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);
|
|
this.removeYouFromUserList($emojiButton, emoji);
|
|
} else if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
|
$emojiButton.tooltip('destroy');
|
|
counter.text('0');
|
|
this.removeYouFromUserList($emojiButton, emoji);
|
|
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') || '';
|
|
};
|
|
|
|
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) {
|
|
var authors, awardBlock, newAuthors, originalTitle;
|
|
awardBlock = $emojiButton;
|
|
originalTitle = this.getAwardTooltip(awardBlock);
|
|
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');
|
|
};
|
|
|
|
AwardsHandler.prototype.addYouToUserList = function(votesBlock, emoji) {
|
|
var awardBlock, origTitle, users;
|
|
awardBlock = this.findEmojiIcon(votesBlock, emoji).parent();
|
|
origTitle = this.getAwardTooltip(awardBlock);
|
|
users = [];
|
|
if (origTitle) {
|
|
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
|
}
|
|
users.unshift('You');
|
|
return awardBlock
|
|
.attr('title', this.toSentence(users))
|
|
.tooltip('fixTitle');
|
|
};
|
|
|
|
AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) {
|
|
var $emojiButton, buttonHtml, emojiCssClass;
|
|
emojiCssClass = this.resolveNameToCssClass(emoji);
|
|
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>";
|
|
$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) {
|
|
var className = 'pulse animated once short';
|
|
$emoji.addClass(className);
|
|
|
|
$emoji.on('webkitAnimationEnd animationEnd', function() {
|
|
$(this).removeClass(className);
|
|
});
|
|
};
|
|
|
|
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 {
|
|
// Find by alias
|
|
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);
|
|
Cookies.set('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 });
|
|
};
|
|
|
|
AwardsHandler.prototype.getFrequentlyUsedEmojis = function() {
|
|
var frequentlyUsedEmojis;
|
|
frequentlyUsedEmojis = (Cookies.get('frequently_used_emojis') || '').split(',');
|
|
return _.compact(_.uniq(frequentlyUsedEmojis));
|
|
};
|
|
|
|
AwardsHandler.prototype.renderFrequentlyUsedBlock = function() {
|
|
var emoji, frequentlyUsedEmojis, i, len, ul;
|
|
if (Cookies.get('frequently_used_emojis')) {
|
|
frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
|
ul = $("<ul class='clearfix emoji-menu-list frequent-emojis'>");
|
|
for (i = 0, len = frequentlyUsedEmojis.length; i < len; i += 1) {
|
|
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();
|
|
// Clean previous search results
|
|
$('ul.emoji-menu-search, h5.emoji-search').remove();
|
|
if (term) {
|
|
// Generate a search result block
|
|
h5 = $('<h5 class="emoji-search" />').text('Search results');
|
|
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);
|