From 43e08b1a38abdb552e4f3d4feee9a898b90d8db2 Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 29 May 2018 16:36:11 -0500 Subject: Backport scroll utilities for the job log component --- app/assets/javascripts/job.js | 82 +++------------------- .../javascripts/lib/utils/logoutput_behaviours.js | 46 ++++++++++++ app/assets/javascripts/lib/utils/scroll_utils.js | 26 +++++++ 3 files changed, 81 insertions(+), 73 deletions(-) create mode 100644 app/assets/javascripts/lib/utils/logoutput_behaviours.js create mode 100644 app/assets/javascripts/lib/utils/scroll_utils.js diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index 8dfe8aae5b5..83c38173a1c 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -6,9 +6,12 @@ import { visitUrl } from './lib/utils/url_utility'; import bp from './breakpoints'; import { numberToHumanSize } from './lib/utils/number_utils'; import { setCiStatusFavicon } from './lib/utils/common_utils'; +import { isScrolledToBottom, scrollDown } from './lib/utils/scroll_utils'; +import LogOutputBehaviours from './lib/utils/logoutput_behaviours'; -export default class Job { +export default class Job extends LogOutputBehaviours { constructor(options) { + super(); this.timeout = null; this.state = null; this.fetchingStatusFavicon = false; @@ -48,23 +51,14 @@ export default class Job { .off('click', '.stage-item') .on('click', '.stage-item', this.updateDropdown); - // add event listeners to the scroll buttons - this.$scrollTopBtn - .off('click') - .on('click', this.scrollToTop.bind(this)); - - this.$scrollBottomBtn - .off('click') - .on('click', this.scrollToBottom.bind(this)); - this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); this.$window .off('scroll') .on('scroll', () => { - if (!this.isScrolledToBottom()) { + if (!isScrolledToBottom()) { this.toggleScrollAnimation(false); - } else if (this.isScrolledToBottom() && !this.isLogComplete) { + } else if (isScrolledToBottom() && !this.isLogComplete) { this.toggleScrollAnimation(true); } this.scrollThrottled(); @@ -83,60 +77,8 @@ export default class Job { StickyFill.add(this.$topBar); } - // eslint-disable-next-line class-methods-use-this - canScroll() { - return $(document).height() > $(window).height(); - } - - toggleScroll() { - const $document = $(document); - const currentPosition = $document.scrollTop(); - const scrollHeight = $document.height(); - - const windowHeight = $(window).height(); - if (this.canScroll()) { - if (currentPosition > 0 && - (scrollHeight - currentPosition !== windowHeight)) { - // User is in the middle of the log - - this.toggleDisableButton(this.$scrollTopBtn, false); - this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (currentPosition === 0) { - // User is at Top of Log - - this.toggleDisableButton(this.$scrollTopBtn, true); - this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (this.isScrolledToBottom()) { - // User is at the bottom of the build log. - - this.toggleDisableButton(this.$scrollTopBtn, false); - this.toggleDisableButton(this.$scrollBottomBtn, true); - } - } else { - this.toggleDisableButton(this.$scrollTopBtn, true); - this.toggleDisableButton(this.$scrollBottomBtn, true); - } - } - // eslint-disable-next-line class-methods-use-this - isScrolledToBottom() { - const $document = $(document); - - const currentPosition = $document.scrollTop(); - const scrollHeight = $document.height(); - - const windowHeight = $(window).height(); - - return scrollHeight - currentPosition === windowHeight; - } - - // eslint-disable-next-line class-methods-use-this - scrollDown() { - const $document = $(document); - $document.scrollTop($document.height()); - } - scrollToBottom() { - this.scrollDown(); + scrollDown(); this.hasBeenScrolled = true; this.toggleScroll(); } @@ -147,12 +89,6 @@ export default class Job { this.toggleScroll(); } - // eslint-disable-next-line class-methods-use-this - toggleDisableButton($button, disable) { - if (disable && $button.prop('disabled')) return; - $button.prop('disabled', disable); - } - toggleScrollAnimation(toggle) { this.$scrollBottomBtn.toggleClass('animate', toggle); } @@ -184,7 +120,7 @@ export default class Job { this.state = log.state; } - this.isScrollInBottom = this.isScrolledToBottom(); + this.isScrollInBottom = isScrolledToBottom(); if (log.append) { this.$buildTraceOutput.append(log.html); @@ -224,7 +160,7 @@ export default class Job { }) .then(() => { if (this.isScrollInBottom) { - this.scrollDown(); + scrollDown(); } }) .then(() => this.toggleScroll()); diff --git a/app/assets/javascripts/lib/utils/logoutput_behaviours.js b/app/assets/javascripts/lib/utils/logoutput_behaviours.js new file mode 100644 index 00000000000..1bf99d935ef --- /dev/null +++ b/app/assets/javascripts/lib/utils/logoutput_behaviours.js @@ -0,0 +1,46 @@ +import $ from 'jquery'; +import { canScroll, isScrolledToBottom, toggleDisableButton } from './scroll_utils'; + +export default class LogOutputBehaviours { + constructor() { + // Scroll buttons + this.$scrollTopBtn = $('.js-scroll-up'); + this.$scrollBottomBtn = $('.js-scroll-down'); + + this.$scrollTopBtn.off('click').on('click', this.scrollToTop.bind(this)); + this.$scrollBottomBtn.off('click').on('click', this.scrollToBottom.bind(this)); + } + + toggleScroll() { + const $document = $(document); + const currentPosition = $document.scrollTop(); + const scrollHeight = $document.height(); + + const windowHeight = $(window).height(); + if (canScroll()) { + if (currentPosition > 0 && scrollHeight - currentPosition !== windowHeight) { + // User is in the middle of the log + + toggleDisableButton(this.$scrollTopBtn, false); + toggleDisableButton(this.$scrollBottomBtn, false); + } else if (currentPosition === 0) { + // User is at Top of Log + + toggleDisableButton(this.$scrollTopBtn, true); + toggleDisableButton(this.$scrollBottomBtn, false); + } else if (isScrolledToBottom()) { + // User is at the bottom of the build log. + + toggleDisableButton(this.$scrollTopBtn, false); + toggleDisableButton(this.$scrollBottomBtn, true); + } + } else { + toggleDisableButton(this.$scrollTopBtn, true); + toggleDisableButton(this.$scrollBottomBtn, true); + } + } + + toggleScrollAnimation(toggle) { + this.$scrollBottomBtn.toggleClass('animate', toggle); + } +} diff --git a/app/assets/javascripts/lib/utils/scroll_utils.js b/app/assets/javascripts/lib/utils/scroll_utils.js new file mode 100644 index 00000000000..b31a8c38550 --- /dev/null +++ b/app/assets/javascripts/lib/utils/scroll_utils.js @@ -0,0 +1,26 @@ +import $ from 'jquery'; + +export const canScroll = () => $(document).height() > $(window).height(); + +export const isScrolledToBottom = () => { + const $document = $(document); + + const currentPosition = $document.scrollTop(); + const scrollHeight = $document.height(); + + const windowHeight = $(window).height(); + + return scrollHeight - currentPosition === windowHeight; +}; + +export const scrollDown = () => { + const $document = $(document); + $document.scrollTop($document.height()); +}; + +export const toggleDisableButton = ($button, disable) => { + if (disable && $button.prop('disabled')) return; + $button.prop('disabled', disable); +}; + +export default {}; -- cgit v1.2.3 From 7644edd8aae6d2959790f35302d3f0ec5767097d Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 30 May 2018 10:18:18 -0500 Subject: Add partial for the build outputs --- app/assets/javascripts/job.js | 4 ---- app/assets/javascripts/lib/utils/scroll_utils.js | 3 +++ app/views/projects/jobs/show.html.haml | 4 +--- app/views/shared/builds/_build_output.html.haml | 3 +++ qa/qa/page/project/job/show.rb | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 app/views/shared/builds/_build_output.html.haml diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index 83c38173a1c..295162a9ad5 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -32,10 +32,6 @@ export default class Job extends LogOutputBehaviours { this.$buildTraceOutput = $('.js-build-output'); this.$topBar = $('.js-top-bar'); - // Scroll controllers - this.$scrollTopBtn = $('.js-scroll-up'); - this.$scrollBottomBtn = $('.js-scroll-down'); - clearTimeout(this.timeout); this.initSidebar(); diff --git a/app/assets/javascripts/lib/utils/scroll_utils.js b/app/assets/javascripts/lib/utils/scroll_utils.js index b31a8c38550..9313b570863 100644 --- a/app/assets/javascripts/lib/utils/scroll_utils.js +++ b/app/assets/javascripts/lib/utils/scroll_utils.js @@ -2,6 +2,9 @@ import $ from 'jquery'; export const canScroll = () => $(document).height() > $(window).height(); +/** + * Checks if the entire page is scrolled down all the way to the bottom + */ export const isScrolledToBottom = () => { const $document = $(document); diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index ec9a04c0eab..1f33bb3a129 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -86,9 +86,7 @@ %button.js-scroll-down.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } = custom_icon('scroll_down') - %pre.build-trace#build-trace - %code.bash.js-build-output - .build-loader-animation.js-build-refresh + = render 'shared/builds/build_output' - else = render "empty_states" diff --git a/app/views/shared/builds/_build_output.html.haml b/app/views/shared/builds/_build_output.html.haml new file mode 100644 index 00000000000..07f1501fadd --- /dev/null +++ b/app/views/shared/builds/_build_output.html.haml @@ -0,0 +1,3 @@ +%pre.build-trace#build-trace + %code.bash.js-build-output + .build-loader-animation.js-build-refresh diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb index 83bb224b5c3..f1a859fd8ee 100644 --- a/qa/qa/page/project/job/show.rb +++ b/qa/qa/page/project/job/show.rb @@ -4,7 +4,7 @@ module QA::Page COMPLETED_STATUSES = %w[passed failed canceled blocked skipped manual].freeze # excludes created, pending, running PASSED_STATUS = 'passed'.freeze - view 'app/views/projects/jobs/show.html.haml' do + view 'app/views/shared/builds/_build_output.html.haml' do element :build_output, '.js-build-output' end -- cgit v1.2.3