diff options
Diffstat (limited to 'app/assets/javascripts/files_comment_button.js')
-rw-r--r-- | app/assets/javascripts/files_comment_button.js | 193 |
1 files changed, 58 insertions, 135 deletions
diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js index 534e651b030..d02e4cd5876 100644 --- a/app/assets/javascripts/files_comment_button.js +++ b/app/assets/javascripts/files_comment_button.js @@ -1,150 +1,73 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, max-len, one-var, one-var-declaration-per-line, quotes, prefer-template, newline-per-chained-call, comma-dangle, new-cap, no-else-return, consistent-return */ -/* global FilesCommentButton */ /* global notes */ -let $commentButtonTemplate; - -window.FilesCommentButton = (function() { - var COMMENT_BUTTON_CLASS, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS; - - COMMENT_BUTTON_CLASS = '.add-diff-note'; - - LINE_HOLDER_CLASS = '.line_holder'; - - LINE_NUMBER_CLASS = 'diff-line-num'; - - LINE_CONTENT_CLASS = 'line_content'; - - UNFOLDABLE_LINE_CLASS = 'js-unfold'; - - EMPTY_CELL_CLASS = 'empty-cell'; - - OLD_LINE_CLASS = 'old_line'; - - LINE_COLUMN_CLASSES = "." + LINE_NUMBER_CLASS + ", .line_content"; - - TEXT_FILE_SELECTOR = '.text-file'; - - function FilesCommentButton(filesContainerElement) { - this.render = this.render.bind(this); - this.hideButton = this.hideButton.bind(this); - this.isParallelView = notes.isParallelView(); - filesContainerElement.on('mouseover', LINE_COLUMN_CLASSES, this.render) - .on('mouseleave', LINE_COLUMN_CLASSES, this.hideButton); - } - - FilesCommentButton.prototype.render = function(e) { - var $currentTarget, buttonParentElement, lineContentElement, textFileElement, $button; - $currentTarget = $(e.currentTarget); - - if ($currentTarget.hasClass('js-no-comment-btn')) return; - - lineContentElement = this.getLineContent($currentTarget); - buttonParentElement = this.getButtonParent($currentTarget); - - if (!this.validateButtonParent(buttonParentElement) || !this.validateLineContent(lineContentElement)) return; - - $button = $(COMMENT_BUTTON_CLASS, buttonParentElement); - buttonParentElement.addClass('is-over') - .nextUntil(`.${LINE_CONTENT_CLASS}`).addClass('is-over'); - - if ($button.length) { - return; +/* Developer beware! Do not add logic to showButton or hideButton + * that will force a reflow. Doing so will create a signficant performance + * bottleneck for pages with large diffs. For a comprehensive list of what + * causes reflows, visit https://gist.github.com/paulirish/5d52fb081b3570c81e3a + */ + +const LINE_NUMBER_CLASS = 'diff-line-num'; +const UNFOLDABLE_LINE_CLASS = 'js-unfold'; +const NO_COMMENT_CLASS = 'no-comment-btn'; +const EMPTY_CELL_CLASS = 'empty-cell'; +const OLD_LINE_CLASS = 'old_line'; +const LINE_COLUMN_CLASSES = `.${LINE_NUMBER_CLASS}, .line_content`; +const DIFF_CONTAINER_SELECTOR = '.files'; +const DIFF_EXPANDED_CLASS = 'diff-expanded'; + +export default { + init($diffFile) { + /* Caching is used only when the following members are *true*. This is because there are likely to be + * differently configured versions of diffs in the same session. However if these values are true, they + * will be true in all cases */ + + if (!this.userCanCreateNote) { + // data-can-create-note is an empty string when true, otherwise undefined + this.userCanCreateNote = $diffFile.closest(DIFF_CONTAINER_SELECTOR).data('can-create-note') === ''; } - textFileElement = this.getTextFileElement($currentTarget); - buttonParentElement.append(this.buildButton({ - discussionID: lineContentElement.attr('data-discussion-id'), - lineType: lineContentElement.attr('data-line-type'), - - noteableType: textFileElement.attr('data-noteable-type'), - noteableID: textFileElement.attr('data-noteable-id'), - commitID: textFileElement.attr('data-commit-id'), - noteType: lineContentElement.attr('data-note-type'), - - // LegacyDiffNote - lineCode: lineContentElement.attr('data-line-code'), - - // DiffNote - position: lineContentElement.attr('data-position') - })); - }; - - FilesCommentButton.prototype.hideButton = function(e) { - var $currentTarget = $(e.currentTarget); - var buttonParentElement = this.getButtonParent($currentTarget); - - buttonParentElement.removeClass('is-over') - .nextUntil(`.${LINE_CONTENT_CLASS}`).removeClass('is-over'); - }; - - FilesCommentButton.prototype.buildButton = function(buttonAttributes) { - return $commentButtonTemplate.clone().attr({ - 'data-discussion-id': buttonAttributes.discussionID, - 'data-line-type': buttonAttributes.lineType, - - 'data-noteable-type': buttonAttributes.noteableType, - 'data-noteable-id': buttonAttributes.noteableID, - 'data-commit-id': buttonAttributes.commitID, - 'data-note-type': buttonAttributes.noteType, - - // LegacyDiffNote - 'data-line-code': buttonAttributes.lineCode, - - // DiffNote - 'data-position': buttonAttributes.position - }); - }; - - FilesCommentButton.prototype.getTextFileElement = function(hoveredElement) { - return hoveredElement.closest(TEXT_FILE_SELECTOR); - }; - - FilesCommentButton.prototype.getLineContent = function(hoveredElement) { - if (hoveredElement.hasClass(LINE_CONTENT_CLASS)) { - return hoveredElement; - } - if (!this.isParallelView) { - return $(hoveredElement).closest(LINE_HOLDER_CLASS).find("." + LINE_CONTENT_CLASS); - } else { - return $(hoveredElement).next("." + LINE_CONTENT_CLASS); + if (typeof notes !== 'undefined' && !this.isParallelView) { + this.isParallelView = notes.isParallelView && notes.isParallelView(); } - }; - FilesCommentButton.prototype.getButtonParent = function(hoveredElement) { - if (!this.isParallelView) { - if (hoveredElement.hasClass(OLD_LINE_CLASS)) { - return hoveredElement; - } - return hoveredElement.parent().find("." + OLD_LINE_CLASS); - } else { - if (hoveredElement.hasClass(LINE_NUMBER_CLASS)) { - return hoveredElement; - } - return $(hoveredElement).prev("." + LINE_NUMBER_CLASS); + if (this.userCanCreateNote) { + $diffFile.on('mouseover', LINE_COLUMN_CLASSES, e => this.showButton(this.isParallelView, e)) + .on('mouseleave', LINE_COLUMN_CLASSES, e => this.hideButton(this.isParallelView, e)); } - }; + }, - FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) { - return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS); - }; + showButton(isParallelView, e) { + const buttonParentElement = this.getButtonParent(e.currentTarget, isParallelView); - FilesCommentButton.prototype.validateLineContent = function(lineContentElement) { - return lineContentElement.attr('data-note-type') && lineContentElement.attr('data-note-type') !== ''; - }; + if (!this.validateButtonParent(buttonParentElement)) return; - return FilesCommentButton; -})(); + buttonParentElement.classList.add('is-over'); + buttonParentElement.nextElementSibling.classList.add('is-over'); + }, -$.fn.filesCommentButton = function() { - $commentButtonTemplate = $('<button name="button" type="submit" class="add-diff-note js-add-diff-note-button" title="Add a comment to this line"><i class="fa fa-comment-o"></i></button>'); + hideButton(isParallelView, e) { + const buttonParentElement = this.getButtonParent(e.currentTarget, isParallelView); - if (!(this && (this.parent().data('can-create-note') != null))) { - return; - } - return this.each(function() { - if (!$.data(this, 'filesCommentButton')) { - return $.data(this, 'filesCommentButton', new FilesCommentButton($(this))); + buttonParentElement.classList.remove('is-over'); + buttonParentElement.nextElementSibling.classList.remove('is-over'); + }, + + getButtonParent(hoveredElement, isParallelView) { + if (isParallelView) { + if (!hoveredElement.classList.contains(LINE_NUMBER_CLASS)) { + return hoveredElement.previousElementSibling; + } + } else if (!hoveredElement.classList.contains(OLD_LINE_CLASS)) { + return hoveredElement.parentNode.querySelector(`.${OLD_LINE_CLASS}`); } - }); + return hoveredElement; + }, + + validateButtonParent(buttonParentElement) { + return !buttonParentElement.classList.contains(EMPTY_CELL_CLASS) && + !buttonParentElement.classList.contains(UNFOLDABLE_LINE_CLASS) && + !buttonParentElement.classList.contains(NO_COMMENT_CLASS) && + !buttonParentElement.parentNode.classList.contains(DIFF_EXPANDED_CLASS); + }, }; |