144 lines
4.6 KiB
JavaScript
144 lines
4.6 KiB
JavaScript
import $ from 'jquery';
|
|
import { isImageLoaded } from '../lib/utils/image_utility';
|
|
import imageDiffHelper from './helpers/index';
|
|
import ImageBadge from './image_badge';
|
|
|
|
export default class ImageDiff {
|
|
constructor(el, options) {
|
|
this.el = el;
|
|
this.canCreateNote = Boolean(options && options.canCreateNote);
|
|
this.renderCommentBadge = Boolean(options && options.renderCommentBadge);
|
|
this.$noteContainer = $('.note-container', this.el);
|
|
this.imageBadges = [];
|
|
}
|
|
|
|
init() {
|
|
this.imageFrameEl = this.el.querySelector('.diff-file .js-image-frame');
|
|
this.imageEl = this.imageFrameEl.querySelector('img');
|
|
|
|
this.bindEvents();
|
|
}
|
|
|
|
bindEvents() {
|
|
this.imageClickedWrapper = this.imageClicked.bind(this);
|
|
this.imageBlurredWrapper = imageDiffHelper.removeCommentIndicator.bind(null, this.imageFrameEl);
|
|
this.addBadgeWrapper = this.addBadge.bind(this);
|
|
this.removeBadgeWrapper = this.removeBadge.bind(this);
|
|
this.renderBadgesWrapper = this.renderBadges.bind(this);
|
|
|
|
// Render badges
|
|
if (isImageLoaded(this.imageEl)) {
|
|
this.renderBadges();
|
|
} else {
|
|
this.imageEl.addEventListener('load', this.renderBadgesWrapper);
|
|
}
|
|
|
|
// jquery makes the event delegation here much simpler
|
|
this.$noteContainer.on('click', '.js-diff-notes-toggle', imageDiffHelper.toggleCollapsed);
|
|
$(this.el).on('click', '.comment-indicator', imageDiffHelper.commentIndicatorOnClick);
|
|
|
|
if (this.canCreateNote) {
|
|
this.el.addEventListener('click.imageDiff', this.imageClickedWrapper);
|
|
this.el.addEventListener('blur.imageDiff', this.imageBlurredWrapper);
|
|
this.el.addEventListener('addBadge.imageDiff', this.addBadgeWrapper);
|
|
this.el.addEventListener('removeBadge.imageDiff', this.removeBadgeWrapper);
|
|
}
|
|
}
|
|
|
|
imageClicked(event) {
|
|
const customEvent = event.detail;
|
|
const selection = imageDiffHelper.getTargetSelection(customEvent);
|
|
const el = customEvent.currentTarget;
|
|
|
|
imageDiffHelper.setPositionDataAttribute(el, selection.actual);
|
|
imageDiffHelper.showCommentIndicator(this.imageFrameEl, selection.browser);
|
|
}
|
|
|
|
renderBadges() {
|
|
const discussionsEls = this.el.querySelectorAll('.note-container .discussion-notes .notes');
|
|
[...discussionsEls].forEach(this.renderBadge.bind(this));
|
|
}
|
|
|
|
renderBadge(discussionEl, index) {
|
|
const imageBadge = imageDiffHelper.generateBadgeFromDiscussionDOM(
|
|
this.imageFrameEl,
|
|
discussionEl,
|
|
);
|
|
|
|
this.imageBadges.push(imageBadge);
|
|
|
|
const options = {
|
|
coordinate: imageBadge.browser,
|
|
noteId: imageBadge.noteId,
|
|
};
|
|
|
|
if (this.renderCommentBadge) {
|
|
imageDiffHelper.addImageCommentBadge(this.imageFrameEl, options);
|
|
} else {
|
|
const numberBadgeOptions = { ...options, badgeText: index + 1 };
|
|
|
|
imageDiffHelper.addImageBadge(this.imageFrameEl, numberBadgeOptions);
|
|
}
|
|
}
|
|
|
|
addBadge(event) {
|
|
const { x, y, width, height, noteId, discussionId } = event.detail;
|
|
const badgeText = this.imageBadges.length + 1;
|
|
const imageBadge = new ImageBadge({
|
|
actual: {
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
},
|
|
imageEl: this.imageFrameEl.querySelector('img'),
|
|
noteId,
|
|
discussionId,
|
|
});
|
|
|
|
this.imageBadges.push(imageBadge);
|
|
|
|
imageDiffHelper.addImageBadge(this.imageFrameEl, {
|
|
coordinate: imageBadge.browser,
|
|
badgeText,
|
|
noteId,
|
|
});
|
|
|
|
imageDiffHelper.addAvatarBadge(this.el, {
|
|
detail: {
|
|
noteId,
|
|
badgeNumber: badgeText,
|
|
},
|
|
});
|
|
|
|
const discussionEl = this.el.querySelector(`#discussion_${discussionId}`);
|
|
imageDiffHelper.updateDiscussionBadgeNumber(discussionEl, badgeText);
|
|
}
|
|
|
|
removeBadge(event) {
|
|
const { badgeNumber } = event.detail;
|
|
const indexToRemove = badgeNumber - 1;
|
|
const imageBadgeEls = this.imageFrameEl.querySelectorAll('.badge');
|
|
|
|
if (this.imageBadges.length !== badgeNumber) {
|
|
// Cascade badges count numbers for (avatar badges + image badges)
|
|
this.imageBadges.forEach((badge, index) => {
|
|
if (index > indexToRemove) {
|
|
const { discussionId } = badge;
|
|
const updatedBadgeNumber = index;
|
|
const discussionEl = this.el.querySelector(`#discussion_${discussionId}`);
|
|
|
|
imageBadgeEls[index].textContent = updatedBadgeNumber;
|
|
|
|
imageDiffHelper.updateDiscussionBadgeNumber(discussionEl, updatedBadgeNumber);
|
|
imageDiffHelper.updateDiscussionAvatarBadgeNumber(discussionEl, updatedBadgeNumber);
|
|
}
|
|
});
|
|
}
|
|
|
|
this.imageBadges.splice(indexToRemove, 1);
|
|
|
|
const imageBadgeEl = imageBadgeEls[indexToRemove];
|
|
imageBadgeEl.remove();
|
|
}
|
|
}
|