* Remove extraneous comment (see 9361d2 and 5c18f8) * Flexible, multiple reaction types * Fix reaction counts * Re-use svg for active state for now * Update yml, update spec * Possible temp fix for failing tests * Colorize reaction icon svgs * Reaction engagement above post title * Index reactions engagements (for logged-out) * Maybe readinglist is special * Try using crayons' dropdown as a drawer? * readinglist isn't really public now * feat: update the styles for the reaction drawer * Grey background highlight, turn off border/shadow * Read our feature flag docs, saw this was recommended * Missed fifth emoji: party/tada * Fix JS test errors * Update test with tada * Suppress flashing engagements when no public reactions * Liberate jump-to-comments from unicorn replacement * 'Add reaction' on tooltip * Don't show reaction emoji on index unless it's been used * rubocop * Update heart+ total count when toggling * Do not include 'readinglist' in drawer/public counts * Fix semi-public readinglist so that icon is badged for current user * Tweak heart-plus svg * Style tweak: border on active reaction * Show reacted icon on drawer trigger for 1.5 sec * Tweak styles for engagements bar * Style tweaks for multiple engagements (#index) * Trying to get size working through crayons/inline_svg * Sparkle hearts * Restore unicorn * Make heart-plus-active work when user has an active reaction * Try 'hoverdown' a dropdown that activates with hover * Long touch? * Tap *outside* the drawer to close * Mobile reaction drawer is also supposed to be columns * More reaction count cleanup * Final emoticons maybe? * Fix reaction bug when feature disabled * Remove readinglist from public reaction counts * Update specs for new reaction categories * Shuffle makes specs flaky * Order does not matter * rubocop * Update to preserve readinglist analytics * Shuffle makes specs flaky * Fix flickering images, remove icon highlight for now * Don't update total for readinglist * reactions_by_user_id * Try renaming this observer function * Try unid ids for SVGs * Remove local test file * Simplistic test for the unique svg transform * Fix javascript for current SVG * Signifcant string literals in this case, rubocop * Use the right expected output Co-authored-by: Ridhwana <ridhwana.khan16@gmail.com>
178 lines
5.5 KiB
JavaScript
178 lines
5.5 KiB
JavaScript
import { h, render } from 'preact';
|
|
import ahoy from 'ahoy.js';
|
|
import { Snackbar, addSnackbarItem } from '../Snackbar';
|
|
import { addFullScreenModeControl } from '../utilities/codeFullscreenModeSwitcher';
|
|
import { initializeDropdown } from '../utilities/dropdownUtils';
|
|
import { embedGists } from '../utilities/gist';
|
|
import { initializeUserSubscriptionLiquidTagContent } from '../liquidTags/userSubscriptionLiquidTag';
|
|
import { trackCommentClicks } from '@utilities/ahoy/trackEvents';
|
|
import { isNativeAndroid, copyToClipboard } from '@utilities/runtime';
|
|
|
|
const animatedImages = document.querySelectorAll('[data-animated="true"]');
|
|
if (animatedImages.length > 0) {
|
|
import('@utilities/animatedImageUtils').then(
|
|
({ initializePausableAnimatedImages }) => {
|
|
initializePausableAnimatedImages(animatedImages);
|
|
},
|
|
);
|
|
}
|
|
|
|
const fullscreenActionElements = document.getElementsByClassName(
|
|
'js-fullscreen-code-action',
|
|
);
|
|
|
|
if (fullscreenActionElements) {
|
|
addFullScreenModeControl(fullscreenActionElements);
|
|
}
|
|
|
|
// The Snackbar for the article page
|
|
const snackZone = document.getElementById('snack-zone');
|
|
if (snackZone) {
|
|
render(<Snackbar lifespan={3} />, snackZone);
|
|
}
|
|
|
|
// eslint-disable-next-line no-restricted-globals
|
|
top.addSnackbarItem = addSnackbarItem;
|
|
|
|
const multiReactionDrawerTrigger = document.getElementById(
|
|
'reaction-drawer-trigger',
|
|
);
|
|
|
|
if (
|
|
multiReactionDrawerTrigger &&
|
|
multiReactionDrawerTrigger.dataset.initialized !== 'true'
|
|
) {
|
|
initializeDropdown({
|
|
triggerElementId: 'reaction-drawer-trigger',
|
|
dropdownContentId: 'reaction-drawer',
|
|
});
|
|
}
|
|
|
|
// Dropdown accessibility
|
|
function hideCopyLinkAnnouncerIfVisible() {
|
|
document.getElementById('article-copy-link-announcer').hidden = true;
|
|
}
|
|
|
|
// Initialize the share options
|
|
const shareDropdownButton = document.getElementById('article-show-more-button');
|
|
|
|
if (shareDropdownButton.dataset.initialized !== 'true') {
|
|
if (isNativeAndroid('shareText')) {
|
|
// Android native apps have enhanced sharing capabilities for Articles and don't use our standard dropdown
|
|
shareDropdownButton.addEventListener('click', () =>
|
|
AndroidBridge.shareText(location.href),
|
|
);
|
|
} else {
|
|
const { closeDropdown } = initializeDropdown({
|
|
triggerElementId: 'article-show-more-button',
|
|
dropdownContentId: 'article-show-more-dropdown',
|
|
onClose: hideCopyLinkAnnouncerIfVisible,
|
|
});
|
|
|
|
// We want to close the dropdown on link select (since they open in a new tab)
|
|
document
|
|
.querySelectorAll('#article-show-more-dropdown [href]')
|
|
.forEach((link) => {
|
|
link.addEventListener('click', (event) => {
|
|
closeDropdown(event);
|
|
});
|
|
});
|
|
}
|
|
|
|
shareDropdownButton.dataset.initialized = 'true';
|
|
}
|
|
|
|
// Initialize the copy to clipboard functionality
|
|
function showAnnouncer() {
|
|
document.getElementById('article-copy-link-announcer').hidden = false;
|
|
}
|
|
|
|
// Temporary Ahoy Stats for displaying comments section either on page load or after scrolling
|
|
function trackCommentsSectionDisplayed() {
|
|
const callback = (entries, observer) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
ahoy.track('Comment section viewable', { page: location.href });
|
|
observer.disconnect();
|
|
}
|
|
if (location.hash === '#comments') {
|
|
//handle focus event on text area
|
|
const element = document.getElementById('text-area');
|
|
const event = new FocusEvent('focus');
|
|
element.dispatchEvent(event);
|
|
}
|
|
});
|
|
};
|
|
|
|
const target = document.getElementById('comments');
|
|
const observer = new IntersectionObserver(callback, {});
|
|
observer.observe(target);
|
|
}
|
|
|
|
function copyArticleLink() {
|
|
const postUrlValue = document
|
|
.getElementById('copy-post-url-button')
|
|
.getAttribute('data-postUrl');
|
|
copyToClipboard(postUrlValue).then(() => {
|
|
showAnnouncer();
|
|
});
|
|
}
|
|
document
|
|
.getElementById('copy-post-url-button')
|
|
?.addEventListener('click', copyArticleLink);
|
|
|
|
// Comment Subscription
|
|
getCsrfToken().then(async () => {
|
|
const { user = null, userStatus } = document.body.dataset;
|
|
const root = document.getElementById('comment-subscription');
|
|
const isLoggedIn = userStatus === 'logged-in';
|
|
|
|
if (!root) {
|
|
return;
|
|
}
|
|
try {
|
|
const {
|
|
getCommentSubscriptionStatus,
|
|
setCommentSubscriptionStatus,
|
|
CommentSubscription,
|
|
} = await import('../CommentSubscription');
|
|
|
|
const { articleId } = document.getElementById('article-body').dataset;
|
|
|
|
let subscriptionType = 'not_subscribed';
|
|
|
|
if (isLoggedIn && user !== null) {
|
|
({ config: subscriptionType } = await getCommentSubscriptionStatus(
|
|
articleId,
|
|
));
|
|
}
|
|
|
|
const subscriptionRequestHandler = async (type) => {
|
|
const message = await setCommentSubscriptionStatus(articleId, type);
|
|
|
|
addSnackbarItem({ message, addCloseButton: true });
|
|
};
|
|
|
|
render(
|
|
<CommentSubscription
|
|
subscriptionType={subscriptionType}
|
|
positionType="static"
|
|
onSubscribe={subscriptionRequestHandler}
|
|
onUnsubscribe={subscriptionRequestHandler}
|
|
isLoggedIn={isLoggedIn}
|
|
/>,
|
|
root,
|
|
);
|
|
} catch (e) {
|
|
root.innerHTML =
|
|
'<p className="color-accent-danger">Unable to load Comment Subscription component.<br />Try refreshing the page.</p>';
|
|
}
|
|
});
|
|
|
|
const targetNode = document.querySelector('#comments');
|
|
targetNode && embedGists(targetNode);
|
|
|
|
initializeUserSubscriptionLiquidTagContent();
|
|
// Temporary Ahoy Stats for comment section clicks on controls
|
|
trackCommentClicks('comments');
|
|
trackCommentsSectionDisplayed();
|