refactor AwardsHandler into es class syntax
This commit is contained in:
parent
442bd2657c
commit
3b4c07ac5f
1 changed files with 392 additions and 397 deletions
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable class-methods-use-this */
|
||||
/* global Flash */
|
||||
|
||||
import Cookies from 'js-cookie';
|
||||
|
@ -68,141 +69,140 @@ function renderCategory(name, emojiList, opts = {}) {
|
|||
`;
|
||||
}
|
||||
|
||||
function AwardsHandler() {
|
||||
this.eventListeners = [];
|
||||
this.aliases = emojiAliases;
|
||||
// If the user shows intent let's pre-build the menu
|
||||
this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => {
|
||||
export default class AwardsHandler {
|
||||
constructor() {
|
||||
this.eventListeners = [];
|
||||
this.aliases = emojiAliases;
|
||||
// If the user shows intent let's pre-build the menu
|
||||
this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => {
|
||||
const $menu = $('.emoji-menu');
|
||||
if ($menu.length === 0) {
|
||||
requestAnimationFrame(() => {
|
||||
this.createEmojiMenu();
|
||||
});
|
||||
}
|
||||
// Prebuild the categoryMap
|
||||
categoryMap = categoryMap || buildCategoryMap();
|
||||
});
|
||||
this.registerEventListener('on', $(document), 'click', '.js-add-award', (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.showEmojiMenu($(e.currentTarget));
|
||||
});
|
||||
|
||||
this.registerEventListener('on', $('html'), 'click', (e) => {
|
||||
const $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');
|
||||
$('.emoji-menu').removeClass('is-visible');
|
||||
}
|
||||
}
|
||||
});
|
||||
this.registerEventListener('on', $(document), 'click', '.js-emoji-btn', (e) => {
|
||||
e.preventDefault();
|
||||
const $target = $(e.currentTarget);
|
||||
const $glEmojiElement = $target.find('gl-emoji');
|
||||
const $spriteIconElement = $target.find('.icon');
|
||||
const emoji = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name');
|
||||
|
||||
$target.closest('.js-awards-block').addClass('current');
|
||||
this.addAward(this.getVotesBlock(), this.getAwardUrl(), emoji);
|
||||
});
|
||||
}
|
||||
|
||||
registerEventListener(method = 'on', element, ...args) {
|
||||
element[method].call(element, ...args);
|
||||
this.eventListeners.push({
|
||||
element,
|
||||
args,
|
||||
});
|
||||
}
|
||||
|
||||
showEmojiMenu($addBtn) {
|
||||
if ($addBtn.hasClass('js-note-emoji')) {
|
||||
$addBtn.closest('.note').find('.js-awards-block').addClass('current');
|
||||
} else {
|
||||
$addBtn.closest('.js-awards-block').addClass('current');
|
||||
}
|
||||
|
||||
const $menu = $('.emoji-menu');
|
||||
if ($menu.length === 0) {
|
||||
requestAnimationFrame(() => {
|
||||
this.createEmojiMenu();
|
||||
const $thumbsBtn = $menu.find('[data-name="thumbsup"], [data-name="thumbsdown"]').parent();
|
||||
const $userAuthored = this.isUserAuthored($addBtn);
|
||||
if ($menu.length) {
|
||||
if ($menu.is('.is-visible')) {
|
||||
$addBtn.removeClass('is-active');
|
||||
$menu.removeClass('is-visible');
|
||||
$('.js-emoji-menu-search').blur();
|
||||
} else {
|
||||
$addBtn.addClass('is-active');
|
||||
this.positionMenu($menu, $addBtn);
|
||||
$menu.addClass('is-visible');
|
||||
$('.js-emoji-menu-search').focus();
|
||||
}
|
||||
} else {
|
||||
$addBtn.addClass('is-loading is-active');
|
||||
this.createEmojiMenu(() => {
|
||||
const $createdMenu = $('.emoji-menu');
|
||||
$addBtn.removeClass('is-loading');
|
||||
this.positionMenu($createdMenu, $addBtn);
|
||||
return setTimeout(() => {
|
||||
$createdMenu.addClass('is-visible');
|
||||
$('.js-emoji-menu-search').focus();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
// Prebuild the categoryMap
|
||||
|
||||
$thumbsBtn.toggleClass('disabled', $userAuthored);
|
||||
}
|
||||
|
||||
// Create the emoji menu with the first category of emojis.
|
||||
// Then render the remaining categories of emojis one by one to avoid jank.
|
||||
createEmojiMenu(callback) {
|
||||
if (this.isCreatingEmojiMenu) {
|
||||
return;
|
||||
}
|
||||
this.isCreatingEmojiMenu = true;
|
||||
|
||||
// Render the first category
|
||||
categoryMap = categoryMap || buildCategoryMap();
|
||||
});
|
||||
this.registerEventListener('on', $(document), 'click', '.js-add-award', (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.showEmojiMenu($(e.currentTarget));
|
||||
});
|
||||
const categoryNameKey = Object.keys(categoryMap)[0];
|
||||
const emojisInCategory = categoryMap[categoryNameKey];
|
||||
const firstCategory = renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory);
|
||||
|
||||
this.registerEventListener('on', $('html'), 'click', (e) => {
|
||||
const $target = $(e.target);
|
||||
if (!$target.closest('.emoji-menu-content').length) {
|
||||
$('.js-awards-block.current').removeClass('current');
|
||||
// Render the frequently used
|
||||
const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
||||
let frequentlyUsedCatgegory = '';
|
||||
if (frequentlyUsedEmojis.length > 0) {
|
||||
frequentlyUsedCatgegory = renderCategory('Frequently used', frequentlyUsedEmojis, {
|
||||
menuListClass: 'frequent-emojis',
|
||||
});
|
||||
}
|
||||
if (!$target.closest('.emoji-menu').length) {
|
||||
if ($('.emoji-menu').is(':visible')) {
|
||||
$('.js-add-award.is-active').removeClass('is-active');
|
||||
$('.emoji-menu').removeClass('is-visible');
|
||||
}
|
||||
}
|
||||
});
|
||||
this.registerEventListener('on', $(document), 'click', '.js-emoji-btn', (e) => {
|
||||
e.preventDefault();
|
||||
const $target = $(e.currentTarget);
|
||||
const $glEmojiElement = $target.find('gl-emoji');
|
||||
const $spriteIconElement = $target.find('.icon');
|
||||
const emoji = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name');
|
||||
|
||||
$target.closest('.js-awards-block').addClass('current');
|
||||
this.addAward(this.getVotesBlock(), this.getAwardUrl(), emoji);
|
||||
});
|
||||
}
|
||||
const emojiMenuMarkup = `
|
||||
<div class="emoji-menu">
|
||||
<input type="text" name="emoji-menu-search" value="" class="js-emoji-menu-search emoji-search search-input form-control" placeholder="Search emoji" />
|
||||
|
||||
AwardsHandler.prototype.registerEventListener = function registerEventListener(method = 'on', element, ...args) {
|
||||
element[method].call(element, ...args);
|
||||
this.eventListeners.push({
|
||||
element,
|
||||
args,
|
||||
});
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.showEmojiMenu = function showEmojiMenu($addBtn) {
|
||||
if ($addBtn.hasClass('js-note-emoji')) {
|
||||
$addBtn.closest('.note').find('.js-awards-block').addClass('current');
|
||||
} else {
|
||||
$addBtn.closest('.js-awards-block').addClass('current');
|
||||
}
|
||||
|
||||
const $menu = $('.emoji-menu');
|
||||
const $thumbsBtn = $menu.find('[data-name="thumbsup"], [data-name="thumbsdown"]').parent();
|
||||
const $userAuthored = this.isUserAuthored($addBtn);
|
||||
if ($menu.length) {
|
||||
if ($menu.is('.is-visible')) {
|
||||
$addBtn.removeClass('is-active');
|
||||
$menu.removeClass('is-visible');
|
||||
$('.js-emoji-menu-search').blur();
|
||||
} else {
|
||||
$addBtn.addClass('is-active');
|
||||
this.positionMenu($menu, $addBtn);
|
||||
$menu.addClass('is-visible');
|
||||
$('.js-emoji-menu-search').focus();
|
||||
}
|
||||
} else {
|
||||
$addBtn.addClass('is-loading is-active');
|
||||
this.createEmojiMenu(() => {
|
||||
const $createdMenu = $('.emoji-menu');
|
||||
$addBtn.removeClass('is-loading');
|
||||
this.positionMenu($createdMenu, $addBtn);
|
||||
return setTimeout(() => {
|
||||
$createdMenu.addClass('is-visible');
|
||||
$('.js-emoji-menu-search').focus();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
$thumbsBtn.toggleClass('disabled', $userAuthored);
|
||||
};
|
||||
|
||||
// Create the emoji menu with the first category of emojis.
|
||||
// Then render the remaining categories of emojis one by one to avoid jank.
|
||||
AwardsHandler.prototype.createEmojiMenu = function createEmojiMenu(callback) {
|
||||
if (this.isCreatingEmojiMenu) {
|
||||
return;
|
||||
}
|
||||
this.isCreatingEmojiMenu = true;
|
||||
|
||||
// Render the first category
|
||||
categoryMap = categoryMap || buildCategoryMap();
|
||||
const categoryNameKey = Object.keys(categoryMap)[0];
|
||||
const emojisInCategory = categoryMap[categoryNameKey];
|
||||
const firstCategory = renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory);
|
||||
|
||||
// Render the frequently used
|
||||
const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
||||
let frequentlyUsedCatgegory = '';
|
||||
if (frequentlyUsedEmojis.length > 0) {
|
||||
frequentlyUsedCatgegory = renderCategory('Frequently used', frequentlyUsedEmojis, {
|
||||
menuListClass: 'frequent-emojis',
|
||||
});
|
||||
}
|
||||
|
||||
const emojiMenuMarkup = `
|
||||
<div class="emoji-menu">
|
||||
<input type="text" name="emoji-menu-search" value="" class="js-emoji-menu-search emoji-search search-input form-control" placeholder="Search emoji" />
|
||||
|
||||
<div class="emoji-menu-content">
|
||||
${frequentlyUsedCatgegory}
|
||||
${firstCategory}
|
||||
<div class="emoji-menu-content">
|
||||
${frequentlyUsedCatgegory}
|
||||
${firstCategory}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
`;
|
||||
|
||||
document.body.insertAdjacentHTML('beforeend', emojiMenuMarkup);
|
||||
document.body.insertAdjacentHTML('beforeend', emojiMenuMarkup);
|
||||
|
||||
this.addRemainingEmojiMenuCategories();
|
||||
this.setupSearch();
|
||||
if (callback) {
|
||||
callback();
|
||||
this.addRemainingEmojiMenuCategories();
|
||||
this.setupSearch();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler
|
||||
.prototype
|
||||
.addRemainingEmojiMenuCategories = function addRemainingEmojiMenuCategories() {
|
||||
addRemainingEmojiMenuCategories() {
|
||||
if (this.isAddingRemainingEmojiMenuCategories) {
|
||||
return;
|
||||
}
|
||||
|
@ -243,176 +243,174 @@ AwardsHandler
|
|||
emojiContentElement.insertAdjacentHTML('beforeend', '<p>We encountered an error while adding the remaining categories</p>');
|
||||
throw new Error(`Error occurred in addRemainingEmojiMenuCategories: ${err.message}`);
|
||||
});
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.positionMenu = function positionMenu($menu, $addBtn) {
|
||||
const 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
|
||||
const 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 addAward(
|
||||
votesBlock,
|
||||
awardUrl,
|
||||
emoji,
|
||||
checkMutuality,
|
||||
callback,
|
||||
) {
|
||||
const normalizedEmoji = this.normalizeEmojiName(emoji);
|
||||
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent();
|
||||
this.postEmoji($emojiButton, awardUrl, normalizedEmoji, () => {
|
||||
this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality);
|
||||
return typeof callback === 'function' ? callback() : undefined;
|
||||
});
|
||||
$('.emoji-menu').removeClass('is-visible');
|
||||
$('.js-add-award.is-active').removeClass('is-active');
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.addAwardToEmojiBar = function addAwardToEmojiBar(
|
||||
votesBlock,
|
||||
emoji,
|
||||
checkForMutuality,
|
||||
) {
|
||||
if (checkForMutuality || checkForMutuality === null) {
|
||||
this.checkMutuality(votesBlock, emoji);
|
||||
}
|
||||
this.addEmojiToFrequentlyUsedList(emoji);
|
||||
const normalizedEmoji = this.normalizeEmojiName(emoji);
|
||||
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent();
|
||||
if ($emojiButton.length > 0) {
|
||||
if (this.isActive($emojiButton)) {
|
||||
this.decrementCounter($emojiButton, normalizedEmoji);
|
||||
positionMenu($menu, $addBtn) {
|
||||
const 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
|
||||
const 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 {
|
||||
const counter = $emojiButton.find('.js-counter');
|
||||
counter.text(parseInt(counter.text(), 10) + 1);
|
||||
$emojiButton.addClass('active');
|
||||
this.addYouToUserList(votesBlock, normalizedEmoji);
|
||||
this.animateEmoji($emojiButton);
|
||||
css.left = `${$addBtn.offset().left}px`;
|
||||
$menu.removeClass('is-aligned-right');
|
||||
}
|
||||
} else {
|
||||
votesBlock.removeClass('hidden');
|
||||
this.createEmoji(votesBlock, normalizedEmoji);
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.getVotesBlock = function getVotesBlock() {
|
||||
const currentBlock = $('.js-awards-block.current');
|
||||
let resultantVotesBlock = currentBlock;
|
||||
if (currentBlock.length === 0) {
|
||||
resultantVotesBlock = $('.js-awards-block').eq(0);
|
||||
return $menu.css(css);
|
||||
}
|
||||
|
||||
return resultantVotesBlock;
|
||||
};
|
||||
addAward(
|
||||
votesBlock,
|
||||
awardUrl,
|
||||
emoji,
|
||||
checkMutuality,
|
||||
callback,
|
||||
) {
|
||||
const normalizedEmoji = this.normalizeEmojiName(emoji);
|
||||
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent();
|
||||
this.postEmoji($emojiButton, awardUrl, normalizedEmoji, () => {
|
||||
this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality);
|
||||
return typeof callback === 'function' ? callback() : undefined;
|
||||
});
|
||||
$('.emoji-menu').removeClass('is-visible');
|
||||
$('.js-add-award.is-active').removeClass('is-active');
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.getAwardUrl = function getAwardUrl() {
|
||||
return this.getVotesBlock().data('award-url');
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.checkMutuality = function checkMutuality(votesBlock, emoji) {
|
||||
const awardUrl = this.getAwardUrl();
|
||||
if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
||||
const mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup';
|
||||
const $emojiButton = votesBlock.find(`[data-name="${mutualVote}"]`).parent();
|
||||
const isAlreadyVoted = $emojiButton.hasClass('active');
|
||||
if (isAlreadyVoted) {
|
||||
this.addAward(votesBlock, awardUrl, mutualVote, false);
|
||||
addAwardToEmojiBar(
|
||||
votesBlock,
|
||||
emoji,
|
||||
checkForMutuality,
|
||||
) {
|
||||
if (checkForMutuality || checkForMutuality === null) {
|
||||
this.checkMutuality(votesBlock, emoji);
|
||||
}
|
||||
this.addEmojiToFrequentlyUsedList(emoji);
|
||||
const normalizedEmoji = this.normalizeEmojiName(emoji);
|
||||
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent();
|
||||
if ($emojiButton.length > 0) {
|
||||
if (this.isActive($emojiButton)) {
|
||||
this.decrementCounter($emojiButton, normalizedEmoji);
|
||||
} else {
|
||||
const counter = $emojiButton.find('.js-counter');
|
||||
counter.text(parseInt(counter.text(), 10) + 1);
|
||||
$emojiButton.addClass('active');
|
||||
this.addYouToUserList(votesBlock, normalizedEmoji);
|
||||
this.animateEmoji($emojiButton);
|
||||
}
|
||||
} else {
|
||||
votesBlock.removeClass('hidden');
|
||||
this.createEmoji(votesBlock, normalizedEmoji);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.isActive = function isActive($emojiButton) {
|
||||
return $emojiButton.hasClass('active');
|
||||
};
|
||||
getVotesBlock() {
|
||||
const currentBlock = $('.js-awards-block.current');
|
||||
let resultantVotesBlock = currentBlock;
|
||||
if (currentBlock.length === 0) {
|
||||
resultantVotesBlock = $('.js-awards-block').eq(0);
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.isUserAuthored = function isUserAuthored($button) {
|
||||
return $button.hasClass('js-user-authored');
|
||||
};
|
||||
return resultantVotesBlock;
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.decrementCounter = function decrementCounter($emojiButton, emoji) {
|
||||
const counter = $('.js-counter', $emojiButton);
|
||||
const counterNumber = parseInt(counter.text(), 10);
|
||||
if (counterNumber > 1) {
|
||||
counter.text(counterNumber - 1);
|
||||
this.removeYouFromUserList($emojiButton);
|
||||
} else if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
||||
$emojiButton.tooltip('destroy');
|
||||
counter.text('0');
|
||||
this.removeYouFromUserList($emojiButton);
|
||||
if ($emojiButton.parents('.note').length) {
|
||||
getAwardUrl() {
|
||||
return this.getVotesBlock().data('award-url');
|
||||
}
|
||||
|
||||
checkMutuality(votesBlock, emoji) {
|
||||
const awardUrl = this.getAwardUrl();
|
||||
if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
||||
const mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup';
|
||||
const $emojiButton = votesBlock.find(`[data-name="${mutualVote}"]`).parent();
|
||||
const isAlreadyVoted = $emojiButton.hasClass('active');
|
||||
if (isAlreadyVoted) {
|
||||
this.addAward(votesBlock, awardUrl, mutualVote, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isActive($emojiButton) {
|
||||
return $emojiButton.hasClass('active');
|
||||
}
|
||||
|
||||
isUserAuthored($button) {
|
||||
return $button.hasClass('js-user-authored');
|
||||
}
|
||||
|
||||
decrementCounter($emojiButton, emoji) {
|
||||
const counter = $('.js-counter', $emojiButton);
|
||||
const counterNumber = parseInt(counter.text(), 10);
|
||||
if (counterNumber > 1) {
|
||||
counter.text(counterNumber - 1);
|
||||
this.removeYouFromUserList($emojiButton);
|
||||
} else if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
||||
$emojiButton.tooltip('destroy');
|
||||
counter.text('0');
|
||||
this.removeYouFromUserList($emojiButton);
|
||||
if ($emojiButton.parents('.note').length) {
|
||||
this.removeEmoji($emojiButton);
|
||||
}
|
||||
} else {
|
||||
this.removeEmoji($emojiButton);
|
||||
}
|
||||
} else {
|
||||
this.removeEmoji($emojiButton);
|
||||
}
|
||||
return $emojiButton.removeClass('active');
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.removeEmoji = function removeEmoji($emojiButton) {
|
||||
$emojiButton.tooltip('destroy');
|
||||
$emojiButton.remove();
|
||||
const $votesBlock = this.getVotesBlock();
|
||||
if ($votesBlock.find('.js-emoji-btn').length === 0) {
|
||||
$votesBlock.addClass('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.getAwardTooltip = function getAwardTooltip($awardBlock) {
|
||||
return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || '';
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.toSentence = function toSentence(list) {
|
||||
let sentence;
|
||||
if (list.length <= 2) {
|
||||
sentence = list.join(' and ');
|
||||
} else {
|
||||
sentence = `${list.slice(0, -1).join(', ')}, and ${list[list.length - 1]}`;
|
||||
return $emojiButton.removeClass('active');
|
||||
}
|
||||
|
||||
return sentence;
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.removeYouFromUserList = function removeYouFromUserList($emojiButton) {
|
||||
const awardBlock = $emojiButton;
|
||||
const originalTitle = this.getAwardTooltip(awardBlock);
|
||||
const 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 addYouToUserList(votesBlock, emoji) {
|
||||
const awardBlock = this.findEmojiIcon(votesBlock, emoji).parent();
|
||||
const origTitle = this.getAwardTooltip(awardBlock);
|
||||
let users = [];
|
||||
if (origTitle) {
|
||||
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
||||
removeEmoji($emojiButton) {
|
||||
$emojiButton.tooltip('destroy');
|
||||
$emojiButton.remove();
|
||||
const $votesBlock = this.getVotesBlock();
|
||||
if ($votesBlock.find('.js-emoji-btn').length === 0) {
|
||||
$votesBlock.addClass('hidden');
|
||||
}
|
||||
}
|
||||
users.unshift('You');
|
||||
return awardBlock
|
||||
.attr('title', this.toSentence(users))
|
||||
.tooltip('fixTitle');
|
||||
};
|
||||
|
||||
AwardsHandler
|
||||
.prototype
|
||||
.createAwardButtonForVotesBlock = function createAwardButtonForVotesBlock(votesBlock, emojiName) {
|
||||
getAwardTooltip($awardBlock) {
|
||||
return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || '';
|
||||
}
|
||||
|
||||
toSentence(list) {
|
||||
let sentence;
|
||||
if (list.length <= 2) {
|
||||
sentence = list.join(' and ');
|
||||
} else {
|
||||
sentence = `${list.slice(0, -1).join(', ')}, and ${list[list.length - 1]}`;
|
||||
}
|
||||
|
||||
return sentence;
|
||||
}
|
||||
|
||||
removeYouFromUserList($emojiButton) {
|
||||
const awardBlock = $emojiButton;
|
||||
const originalTitle = this.getAwardTooltip(awardBlock);
|
||||
const 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');
|
||||
}
|
||||
|
||||
addYouToUserList(votesBlock, emoji) {
|
||||
const awardBlock = this.findEmojiIcon(votesBlock, emoji).parent();
|
||||
const origTitle = this.getAwardTooltip(awardBlock);
|
||||
let users = [];
|
||||
if (origTitle) {
|
||||
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
||||
}
|
||||
users.unshift('You');
|
||||
return awardBlock
|
||||
.attr('title', this.toSentence(users))
|
||||
.tooltip('fixTitle');
|
||||
}
|
||||
|
||||
createAwardButtonForVotesBlock(votesBlock, emojiName) {
|
||||
const buttonHtml = `
|
||||
<button class="btn award-control js-emoji-btn has-tooltip active" title="You" data-placement="bottom">
|
||||
${glEmojiTag(emojiName)}
|
||||
|
@ -424,144 +422,141 @@ AwardsHandler
|
|||
this.animateEmoji($emojiButton);
|
||||
$('.award-control').tooltip();
|
||||
votesBlock.removeClass('current');
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.animateEmoji = function animateEmoji($emoji) {
|
||||
const className = 'pulse animated once short';
|
||||
$emoji.addClass(className);
|
||||
|
||||
this.registerEventListener('on', $emoji, animationEndEventString, (e) => {
|
||||
$(e.currentTarget).removeClass(className);
|
||||
});
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.createEmoji = function createEmoji(votesBlock, emoji) {
|
||||
if ($('.emoji-menu').length) {
|
||||
this.createAwardButtonForVotesBlock(votesBlock, emoji);
|
||||
}
|
||||
this.createEmojiMenu(() => {
|
||||
this.createAwardButtonForVotesBlock(votesBlock, emoji);
|
||||
});
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.postEmoji = function postEmoji($emojiButton, awardUrl, emoji, callback) {
|
||||
if (this.isUserAuthored($emojiButton)) {
|
||||
this.userAuthored($emojiButton);
|
||||
} else {
|
||||
$.post(awardUrl, {
|
||||
name: emoji,
|
||||
}, (data) => {
|
||||
if (data.ok) {
|
||||
callback();
|
||||
}
|
||||
}).fail(() => new Flash('Something went wrong on our end.'));
|
||||
animateEmoji($emoji) {
|
||||
const className = 'pulse animated once short';
|
||||
$emoji.addClass(className);
|
||||
|
||||
this.registerEventListener('on', $emoji, animationEndEventString, (e) => {
|
||||
$(e.currentTarget).removeClass(className);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.findEmojiIcon = function findEmojiIcon(votesBlock, emoji) {
|
||||
return votesBlock.find(`.js-emoji-btn [data-name="${emoji}"]`);
|
||||
};
|
||||
createEmoji(votesBlock, emoji) {
|
||||
if ($('.emoji-menu').length) {
|
||||
this.createAwardButtonForVotesBlock(votesBlock, emoji);
|
||||
}
|
||||
this.createEmojiMenu(() => {
|
||||
this.createAwardButtonForVotesBlock(votesBlock, emoji);
|
||||
});
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.userAuthored = function userAuthored($emojiButton) {
|
||||
const oldTitle = this.getAwardTooltip($emojiButton);
|
||||
const newTitle = 'You cannot vote on your own issue, MR and note';
|
||||
gl.utils.updateTooltipTitle($emojiButton, newTitle).tooltip('show');
|
||||
// Restore tooltip back to award list
|
||||
return setTimeout(() => {
|
||||
$emojiButton.tooltip('hide');
|
||||
gl.utils.updateTooltipTitle($emojiButton, oldTitle);
|
||||
}, 2800);
|
||||
};
|
||||
postEmoji($emojiButton, awardUrl, emoji, callback) {
|
||||
if (this.isUserAuthored($emojiButton)) {
|
||||
this.userAuthored($emojiButton);
|
||||
} else {
|
||||
$.post(awardUrl, {
|
||||
name: emoji,
|
||||
}, (data) => {
|
||||
if (data.ok) {
|
||||
callback();
|
||||
}
|
||||
}).fail(() => new Flash('Something went wrong on our end.'));
|
||||
}
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.scrollToAwards = function scrollToAwards() {
|
||||
const options = {
|
||||
scrollTop: $('.awards').offset().top - 110,
|
||||
};
|
||||
return $('body, html').animate(options, 200);
|
||||
};
|
||||
findEmojiIcon(votesBlock, emoji) {
|
||||
return votesBlock.find(`.js-emoji-btn [data-name="${emoji}"]`);
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.normalizeEmojiName = function normalizeEmojiName(emoji) {
|
||||
return Object.prototype.hasOwnProperty.call(this.aliases, emoji) ? this.aliases[emoji] : emoji;
|
||||
};
|
||||
userAuthored($emojiButton) {
|
||||
const oldTitle = this.getAwardTooltip($emojiButton);
|
||||
const newTitle = 'You cannot vote on your own issue, MR and note';
|
||||
gl.utils.updateTooltipTitle($emojiButton, newTitle).tooltip('show');
|
||||
// Restore tooltip back to award list
|
||||
return setTimeout(() => {
|
||||
$emojiButton.tooltip('hide');
|
||||
gl.utils.updateTooltipTitle($emojiButton, oldTitle);
|
||||
}, 2800);
|
||||
}
|
||||
|
||||
AwardsHandler
|
||||
.prototype
|
||||
.addEmojiToFrequentlyUsedList = function addEmojiToFrequentlyUsedList(emoji) {
|
||||
scrollToAwards() {
|
||||
const options = {
|
||||
scrollTop: $('.awards').offset().top - 110,
|
||||
};
|
||||
return $('body, html').animate(options, 200);
|
||||
}
|
||||
|
||||
normalizeEmojiName(emoji) {
|
||||
return Object.prototype.hasOwnProperty.call(this.aliases, emoji) ? this.aliases[emoji] : emoji;
|
||||
}
|
||||
|
||||
addEmojiToFrequentlyUsedList(emoji) {
|
||||
if (isEmojiNameValid(emoji)) {
|
||||
this.frequentlyUsedEmojis = _.uniq(this.getFrequentlyUsedEmojis().concat(emoji));
|
||||
Cookies.set('frequently_used_emojis', this.frequentlyUsedEmojis.join(','), { expires: 365 });
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.getFrequentlyUsedEmojis = function getFrequentlyUsedEmojis() {
|
||||
return this.frequentlyUsedEmojis || (() => {
|
||||
const frequentlyUsedEmojis = _.uniq((Cookies.get('frequently_used_emojis') || '').split(','));
|
||||
this.frequentlyUsedEmojis = frequentlyUsedEmojis.filter(
|
||||
inputName => isEmojiNameValid(inputName),
|
||||
);
|
||||
|
||||
return this.frequentlyUsedEmojis;
|
||||
})();
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.setupSearch = function setupSearch() {
|
||||
const $search = $('.js-emoji-menu-search');
|
||||
|
||||
this.registerEventListener('on', $search, 'input', (e) => {
|
||||
const term = $(e.target).val().trim();
|
||||
this.searchEmojis(term);
|
||||
});
|
||||
|
||||
const $menu = $('.emoji-menu');
|
||||
this.registerEventListener('on', $menu, transitionEndEventString, (e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
// Clear the search
|
||||
this.searchEmojis('');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.searchEmojis = function searchEmojis(term) {
|
||||
const $search = $('.js-emoji-menu-search');
|
||||
$search.val(term);
|
||||
|
||||
// Clean previous search results
|
||||
$('ul.emoji-menu-search, h5.emoji-search-title').remove();
|
||||
if (term.length > 0) {
|
||||
// Generate a search result block
|
||||
const h5 = $('<h5 class="emoji-search-title"/>').text('Search results');
|
||||
const foundEmojis = this.findMatchingEmojiElements(term).show();
|
||||
const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis);
|
||||
$('.emoji-menu-content ul, .emoji-menu-content h5').hide();
|
||||
$('.emoji-menu-content').append(h5).append(ul);
|
||||
} else {
|
||||
$('.emoji-menu-content').children().show();
|
||||
}
|
||||
};
|
||||
|
||||
AwardsHandler.prototype.findMatchingEmojiElements = function findMatchingEmojiElements(term) {
|
||||
const safeTerm = term.toLowerCase();
|
||||
getFrequentlyUsedEmojis() {
|
||||
return this.frequentlyUsedEmojis || (() => {
|
||||
const frequentlyUsedEmojis = _.uniq((Cookies.get('frequently_used_emojis') || '').split(','));
|
||||
this.frequentlyUsedEmojis = frequentlyUsedEmojis.filter(
|
||||
inputName => isEmojiNameValid(inputName),
|
||||
);
|
||||
|
||||
const namesMatchingAlias = [];
|
||||
Object.keys(emojiAliases).forEach((alias) => {
|
||||
if (alias.indexOf(safeTerm) >= 0) {
|
||||
namesMatchingAlias.push(emojiAliases[alias]);
|
||||
return this.frequentlyUsedEmojis;
|
||||
})();
|
||||
}
|
||||
|
||||
setupSearch() {
|
||||
const $search = $('.js-emoji-menu-search');
|
||||
|
||||
this.registerEventListener('on', $search, 'input', (e) => {
|
||||
const term = $(e.target).val().trim();
|
||||
this.searchEmojis(term);
|
||||
});
|
||||
|
||||
const $menu = $('.emoji-menu');
|
||||
this.registerEventListener('on', $menu, transitionEndEventString, (e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
// Clear the search
|
||||
this.searchEmojis('');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
searchEmojis(term) {
|
||||
const $search = $('.js-emoji-menu-search');
|
||||
$search.val(term);
|
||||
|
||||
// Clean previous search results
|
||||
$('ul.emoji-menu-search, h5.emoji-search-title').remove();
|
||||
if (term.length > 0) {
|
||||
// Generate a search result block
|
||||
const h5 = $('<h5 class="emoji-search-title"/>').text('Search results');
|
||||
const foundEmojis = this.findMatchingEmojiElements(term).show();
|
||||
const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis);
|
||||
$('.emoji-menu-content ul, .emoji-menu-content h5').hide();
|
||||
$('.emoji-menu-content').append(h5).append(ul);
|
||||
} else {
|
||||
$('.emoji-menu-content').children().show();
|
||||
}
|
||||
});
|
||||
const $matchingElements = namesMatchingAlias.concat(safeTerm)
|
||||
.reduce(
|
||||
($result, searchTerm) =>
|
||||
$result.add($(`.emoji-menu-list:not(.frequent-emojis) [data-name*="${searchTerm}"]`)),
|
||||
$([]),
|
||||
);
|
||||
return $matchingElements.closest('li').clone();
|
||||
};
|
||||
}
|
||||
|
||||
AwardsHandler.prototype.destroy = function destroy() {
|
||||
this.eventListeners.forEach((entry) => {
|
||||
entry.element.off.call(entry.element, ...entry.args);
|
||||
});
|
||||
$('.emoji-menu').remove();
|
||||
};
|
||||
findMatchingEmojiElements(term) {
|
||||
const safeTerm = term.toLowerCase();
|
||||
|
||||
export default AwardsHandler;
|
||||
const namesMatchingAlias = [];
|
||||
Object.keys(emojiAliases).forEach((alias) => {
|
||||
if (alias.indexOf(safeTerm) >= 0) {
|
||||
namesMatchingAlias.push(emojiAliases[alias]);
|
||||
}
|
||||
});
|
||||
const $matchingElements = namesMatchingAlias.concat(safeTerm)
|
||||
.reduce(
|
||||
($result, searchTerm) =>
|
||||
$result.add($(`.emoji-menu-list:not(.frequent-emojis) [data-name*="${searchTerm}"]`)),
|
||||
$([]),
|
||||
);
|
||||
return $matchingElements.closest('li').clone();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.eventListeners.forEach((entry) => {
|
||||
entry.element.off.call(entry.element, ...entry.args);
|
||||
});
|
||||
$('.emoji-menu').remove();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue