diff options
-rw-r--r-- | app/assets/javascripts/diff_notes/diff_notes_bundle.js | 27 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/common_utils.js | 141 | ||||
-rw-r--r-- | app/assets/javascripts/merge_request_tabs.js | 82 | ||||
-rw-r--r-- | app/assets/javascripts/notes.js | 21 | ||||
-rw-r--r-- | app/assets/javascripts/pages/projects/merge_requests/show/index.js | 6 | ||||
-rw-r--r-- | app/helpers/notes_helper.rb | 2 |
6 files changed, 153 insertions, 126 deletions
diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js b/app/assets/javascripts/diff_notes/diff_notes_bundle.js index e17daec6a92..406091820e9 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js @@ -15,12 +15,14 @@ import './components/resolve_count'; import './components/resolve_discussion_btn'; import './components/diff_note_avatars'; import './components/new_issue_for_discussion'; -import { hasVueMRDiscussionsCookie } from '../lib/utils/common_utils'; export default () => { - const projectPathHolder = document.querySelector('.merge-request') || document.querySelector('.commit-box'); + const projectPathHolder = + document.querySelector('.merge-request') || + document.querySelector('.commit-box'); const projectPath = projectPathHolder.dataset.projectPath; - const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn, new-issue-for-discussion-btn'; + const COMPONENT_SELECTOR = + 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn, new-issue-for-discussion-btn'; window.gl = window.gl || {}; window.gl.diffNoteApps = {}; @@ -28,9 +30,9 @@ export default () => { window.ResolveService = new gl.DiffNotesResolveServiceClass(projectPath); gl.diffNotesCompileComponents = () => { - $('diff-note-avatars').each(function () { + $('diff-note-avatars').each(function() { const tmp = Vue.extend({ - template: $(this).get(0).outerHTML + template: $(this).get(0).outerHTML, }); const tmpApp = new tmp().$mount(); @@ -41,12 +43,12 @@ export default () => { }); }); - const $components = $(COMPONENT_SELECTOR).filter(function () { + const $components = $(COMPONENT_SELECTOR).filter(function() { return $(this).closest('resolve-count').length !== 1; }); if ($components) { - $components.each(function () { + $components.each(function() { const $this = $(this); const noteId = $this.attr(':note-id'); const discussionId = $this.attr(':discussion-id'); @@ -54,7 +56,7 @@ export default () => { if ($this.is('comment-and-resolve-btn') && !discussionId) return; const tmp = Vue.extend({ - template: $this.get(0).outerHTML + template: $this.get(0).outerHTML, }); const tmpApp = new tmp().$mount(); @@ -69,14 +71,5 @@ export default () => { gl.diffNotesCompileComponents(); - if (!hasVueMRDiscussionsCookie()) { - new Vue({ - el: '#resolve-count-app', - components: { - 'resolve-count': ResolveCount - }, - }); - } - $(window).trigger('resize.nav'); }; diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 081c8c48365..606c836acee 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -5,7 +5,10 @@ import { getLocationHash } from './url_utility'; import { convertToCamelCase } from './text_utility'; import { isObject } from './type_utility'; -export const getPagePath = (index = 0) => $('body').attr('data-page').split(':')[index]; +export const getPagePath = (index = 0) => + $('body') + .attr('data-page') + .split(':')[index]; export const isInGroupsPage = () => getPagePath() === 'groups'; @@ -35,32 +38,39 @@ export const checkPageAndAction = (page, action) => { export const isInIssuePage = () => checkPageAndAction('issues', 'show'); export const isInMRPage = () => checkPageAndAction('merge_requests', 'show'); export const isInNoteablePage = () => isInIssuePage() || isInMRPage(); -export const hasVueMRDiscussionsCookie = () => Cookies.get('vue_mr_discussions'); -export const ajaxGet = url => axios.get(url, { - params: { format: 'js' }, - responseType: 'text', -}).then(({ data }) => { - $.globalEval(data); -}); +export const ajaxGet = url => + axios + .get(url, { + params: { format: 'js' }, + responseType: 'text', + }) + .then(({ data }) => { + $.globalEval(data); + }); -export const rstrip = (val) => { +export const rstrip = val => { if (val) { return val.replace(/\s+$/, ''); } return val; }; -export const updateTooltipTitle = ($tooltipEl, newTitle) => $tooltipEl.attr('title', newTitle).tooltip('fixTitle'); +export const updateTooltipTitle = ($tooltipEl, newTitle) => + $tooltipEl.attr('title', newTitle).tooltip('fixTitle'); -export const disableButtonIfEmptyField = (fieldSelector, buttonSelector, eventName = 'input') => { +export const disableButtonIfEmptyField = ( + fieldSelector, + buttonSelector, + eventName = 'input', +) => { const field = $(fieldSelector); const closestSubmit = field.closest('form').find(buttonSelector); if (rstrip(field.val()) === '') { closestSubmit.disable(); } // eslint-disable-next-line func-names - return field.on(eventName, function () { + return field.on(eventName, function() { if (rstrip($(this).val()) === '') { return closestSubmit.disable(); } @@ -77,7 +87,9 @@ export const handleLocationHash = () => { // This is required to handle non-unicode characters in hash hash = decodeURIComponent(hash); - const target = document.getElementById(hash) || document.getElementById(`user-content-${hash}`); + const target = + document.getElementById(hash) || + document.getElementById(`user-content-${hash}`); const fixedTabs = document.querySelector('.js-tabs-affix'); const fixedDiffStats = document.querySelector('.js-diff-files-changed'); const fixedNav = document.querySelector('.navbar-gitlab'); @@ -102,7 +114,7 @@ export const handleLocationHash = () => { // Check if element scrolled into viewport from above or below // Courtesy http://stackoverflow.com/a/7557433/414749 -export const isInViewport = (el) => { +export const isInViewport = el => { const rect = el.getBoundingClientRect(); return ( @@ -113,25 +125,31 @@ export const isInViewport = (el) => { ); }; -export const parseUrl = (url) => { +export const parseUrl = url => { const parser = document.createElement('a'); parser.href = url; return parser; }; -export const parseUrlPathname = (url) => { +export const parseUrlPathname = url => { const parsedUrl = parseUrl(url); // parsedUrl.pathname will return an absolute path for Firefox and a relative path for IE11 // We have to make sure we always have an absolute path. - return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : `/${parsedUrl.pathname}`; + return parsedUrl.pathname.charAt(0) === '/' + ? parsedUrl.pathname + : `/${parsedUrl.pathname}`; }; // We can trust that each param has one & since values containing & will be encoded // Remove the first character of search as it is always ? -export const getUrlParamsArray = () => window.location.search.slice(1).split('&').map((param) => { - const split = param.split('='); - return [decodeURI(split[0]), split[1]].join('='); -}); +export const getUrlParamsArray = () => + window.location.search + .slice(1) + .split('&') + .map(param => { + const split = param.split('='); + return [decodeURI(split[0]), split[1]].join('='); + }); export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey; @@ -141,7 +159,7 @@ export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey; // 3) Middle-click or Mouse Wheel Click (e.which is 2) export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2; -export const scrollToElement = (element) => { +export const scrollToElement = element => { let $el = element; if (!(element instanceof $)) { $el = $(element); @@ -150,9 +168,12 @@ export const scrollToElement = (element) => { const mrTabsHeight = $('.merge-request-tabs').height() || 0; const headerHeight = $('.navbar-gitlab').height() || 0; - return $('body, html').animate({ - scrollTop: top - mrTabsHeight - headerHeight, - }, 200); + return $('body, html').animate( + { + scrollTop: top - mrTabsHeight - headerHeight, + }, + 200, + ); }; /** @@ -191,13 +212,15 @@ export const insertText = (target, text) => { const textBefore = value.substring(0, selectionStart); const textAfter = value.substring(selectionEnd, value.length); - const insertedText = text instanceof Function ? text(textBefore, textAfter) : text; + const insertedText = + text instanceof Function ? text(textBefore, textAfter) : text; const newText = textBefore + insertedText + textAfter; // eslint-disable-next-line no-param-reassign target.value = newText; // eslint-disable-next-line no-param-reassign - target.selectionStart = target.selectionEnd = selectionStart + insertedText.length; + target.selectionStart = target.selectionEnd = + selectionStart + insertedText.length; // Trigger autosave target.dispatchEvent(new Event('input')); @@ -209,7 +232,8 @@ export const insertText = (target, text) => { }; export const nodeMatchesSelector = (node, selector) => { - const matches = Element.prototype.matches || + const matches = + Element.prototype.matches || Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || @@ -238,10 +262,10 @@ export const nodeMatchesSelector = (node, selector) => { this will take in the headers from an API response and normalize them this way we don't run into production issues when nginx gives us lowercased header keys */ -export const normalizeHeaders = (headers) => { +export const normalizeHeaders = headers => { const upperCaseHeaders = {}; - Object.keys(headers || {}).forEach((e) => { + Object.keys(headers || {}).forEach(e => { upperCaseHeaders[e.toUpperCase()] = headers[e]; }); @@ -252,11 +276,11 @@ export const normalizeHeaders = (headers) => { this will take in the getAllResponseHeaders result and normalize them this way we don't run into production issues when nginx gives us lowercased header keys */ -export const normalizeCRLFHeaders = (headers) => { +export const normalizeCRLFHeaders = headers => { const headersObject = {}; const headersArray = headers.split('\n'); - headersArray.forEach((header) => { + headersArray.forEach(header => { const keyValue = header.split(': '); headersObject[keyValue[0]] = keyValue[1]; }); @@ -292,15 +316,13 @@ export const parseIntPagination = paginationInformation => ({ export const parseQueryStringIntoObject = (query = '') => { if (query === '') return {}; - return query - .split('&') - .reduce((acc, element) => { - const val = element.split('='); - Object.assign(acc, { - [val[0]]: decodeURIComponent(val[1]), - }); - return acc; - }, {}); + return query.split('&').reduce((acc, element) => { + const val = element.split('='); + Object.assign(acc, { + [val[0]]: decodeURIComponent(val[1]), + }); + return acc; + }, {}); }; /** @@ -309,9 +331,13 @@ export const parseQueryStringIntoObject = (query = '') => { * * @param {Object} params */ -export const objectToQueryString = (params = {}) => Object.keys(params).map(param => `${param}=${params[param]}`).join('&'); +export const objectToQueryString = (params = {}) => + Object.keys(params) + .map(param => `${param}=${params[param]}`) + .join('&'); -export const buildUrlWithCurrentLocation = param => (param ? `${window.location.pathname}${param}` : window.location.pathname); +export const buildUrlWithCurrentLocation = param => + param ? `${window.location.pathname}${param}` : window.location.pathname; /** * Based on the current location and the string parameters provided @@ -319,7 +345,7 @@ export const buildUrlWithCurrentLocation = param => (param ? `${window.location. * * @param {String} param */ -export const historyPushState = (newUrl) => { +export const historyPushState = newUrl => { window.history.pushState({}, document.title, newUrl); }; @@ -368,7 +394,7 @@ export const backOff = (fn, timeout = 60000) => { let timeElapsed = 0; return new Promise((resolve, reject) => { - const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg)); + const stop = arg => (arg instanceof Error ? reject(arg) : resolve(arg)); const next = () => { if (timeElapsed < timeout) { @@ -384,7 +410,7 @@ export const backOff = (fn, timeout = 60000) => { }); }; -export const setFavicon = (faviconPath) => { +export const setFavicon = faviconPath => { const faviconEl = document.getElementById('favicon'); if (faviconEl && faviconPath) { faviconEl.setAttribute('href', faviconPath); @@ -400,7 +426,8 @@ export const resetFavicon = () => { }; export const setCiStatusFavicon = pageUrl => - axios.get(pageUrl) + axios + .get(pageUrl) .then(({ data }) => { if (data && data.favicon) { setFavicon(data.favicon); @@ -413,7 +440,9 @@ export const setCiStatusFavicon = pageUrl => export const spriteIcon = (icon, className = '') => { const classAttribute = className.length > 0 ? `class="${className}"` : ''; - return `<svg ${classAttribute}><use xlink:href="${gon.sprite_icons}#${icon}" /></svg>`; + return `<svg ${classAttribute}><use xlink:href="${ + gon.sprite_icons + }#${icon}" /></svg>`; }; /** @@ -435,7 +464,10 @@ export const convertObjectPropsToCamelCase = (obj = {}, options = {}) => { const val = obj[prop]; if (options.deep && (isObject(val) || Array.isArray(val))) { - result[convertToCamelCase(prop)] = convertObjectPropsToCamelCase(val, options); + result[convertToCamelCase(prop)] = convertObjectPropsToCamelCase( + val, + options, + ); } else { result[convertToCamelCase(prop)] = obj[prop]; } @@ -443,15 +475,18 @@ export const convertObjectPropsToCamelCase = (obj = {}, options = {}) => { }, initial); }; -export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`; +export const imagePath = imgUrl => + `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`; export const addSelectOnFocusBehaviour = (selector = '.js-select-on-focus') => { // Click a .js-select-on-focus field, select the contents // Prevent a mouseup event from deselecting the input $(selector).on('focusin', function selectOnFocusCallback() { - $(this).select().one('mouseup', (e) => { - e.preventDefault(); - }); + $(this) + .select() + .one('mouseup', e => { + e.preventDefault(); + }); }); }; diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index a98b0b1c0b1..2f2dc233f4c 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -12,7 +12,6 @@ import { parseUrlPathname, handleLocationHash, isMetaClick, - hasVueMRDiscussionsCookie, } from './lib/utils/common_utils'; import { getLocationHash } from './lib/utils/url_utility'; import initDiscussionTab from './image_diff/init_discussion_tab'; @@ -71,7 +70,6 @@ import Notes from './notes'; let location = window.location; export default class MergeRequestTabs { - constructor({ action, setUrl, stubLocation } = {}) { const mergeRequestTabs = document.querySelector('.js-tabs-affix'); const navbar = document.querySelector('.navbar-gitlab'); @@ -109,21 +107,27 @@ export default class MergeRequestTabs { bindEvents() { $(document) - .on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) + .on( + 'shown.bs.tab', + '.merge-request-tabs a[data-toggle="tab"]', + this.tabShown, + ) .on('click', '.js-show-tab', this.showTab); - $('.merge-request-tabs a[data-toggle="tab"]') - .on('click', this.clickTab); + $('.merge-request-tabs a[data-toggle="tab"]').on('click', this.clickTab); } // Used in tests unbindEvents() { $(document) - .off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) + .off( + 'shown.bs.tab', + '.merge-request-tabs a[data-toggle="tab"]', + this.tabShown, + ) .off('click', '.js-show-tab', this.showTab); - $('.merge-request-tabs a[data-toggle="tab"]') - .off('click', this.clickTab); + $('.merge-request-tabs a[data-toggle="tab"]').off('click', this.clickTab); } destroyPipelinesView() { @@ -159,9 +163,7 @@ export default class MergeRequestTabs { this.resetViewContainer(); this.destroyPipelinesView(); } else if (this.isDiffAction(action)) { - if (!hasVueMRDiscussionsCookie()) { - this.loadDiff($target.attr('href')); - } + debugger; if (bp.getBreakpointSize() !== 'lg') { this.shrinkView(); @@ -192,10 +194,9 @@ export default class MergeRequestTabs { scrollToElement(container) { if (location.hash) { - const offset = 0 - ( - $('.navbar-gitlab').outerHeight() + - $('.js-tabs-affix').outerHeight() - ); + const offset = + 0 - + ($('.navbar-gitlab').outerHeight() + $('.js-tabs-affix').outerHeight()); const $el = $(`${container} ${location.hash}:not(.match)`); if ($el.length) { $.scrollTo($el[0], { offset }); @@ -233,7 +234,10 @@ export default class MergeRequestTabs { this.currentAction = action; // Remove a trailing '/commits' '/diffs' '/pipelines' - let newState = location.pathname.replace(/\/(commits|diffs|pipelines)(\.html)?\/?$/, ''); + let newState = location.pathname.replace( + /\/(commits|diffs|pipelines)(\.html)?\/?$/, + '', + ); // Append the new action if we're on a tab other than 'notes' if (this.currentAction !== 'show' && this.currentAction !== 'new') { @@ -249,9 +253,13 @@ export default class MergeRequestTabs { // Turbolinks' history. // // See https://github.com/rails/turbolinks/issues/363 - window.history.replaceState({ - url: newState, - }, document.title, newState); + window.history.replaceState( + { + url: newState, + }, + document.title, + newState, + ); return newState; } @@ -267,7 +275,8 @@ export default class MergeRequestTabs { this.toggleLoading(true); - axios.get(`${source}.json`) + axios + .get(`${source}.json`) .then(({ data }) => { document.querySelector('div#commits').innerHTML = data.html; localTimeAgo($('.js-timeago', 'div#commits')); @@ -283,7 +292,9 @@ export default class MergeRequestTabs { } mountPipelinesView() { - const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); + const pipelineTableViewEl = document.querySelector( + '#commit-pipeline-table-view', + ); const CommitPipelinesTable = gl.CommitPipelinesTable; this.commitPipelinesTable = new CommitPipelinesTable({ propsData: { @@ -314,7 +325,8 @@ export default class MergeRequestTabs { this.toggleLoading(true); - axios.get(`${urlPathname}.json${location.search}`) + axios + .get(`${urlPathname}.json${location.search}`) .then(({ data }) => { const $container = $('#diffs'); $container.html(data.html); @@ -328,7 +340,10 @@ export default class MergeRequestTabs { localTimeAgo($('.js-timeago', 'div#diffs')); syntaxHighlight($('#diffs .js-syntax-highlight')); - if (this.diffViewType() === 'parallel' && this.isDiffAction(this.currentAction)) { + if ( + this.diffViewType() === 'parallel' && + this.isDiffAction(this.currentAction) + ) { this.expandViewContainer(); } this.diffsLoaded = true; @@ -342,9 +357,10 @@ export default class MergeRequestTabs { forkButtons: $(el).find('.js-fork-suggestion-button'), cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'), suggestionSections: $(el).find('.js-file-fork-suggestion-section'), - actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'), - }) - .init(); + actionTextPieces: $(el).find( + '.js-file-fork-suggestion-section-action', + ), + }).init(); }); // Scroll any linked note into view @@ -399,8 +415,10 @@ export default class MergeRequestTabs { resetViewContainer() { if (this.fixedLayoutPref !== null) { - $('.content-wrapper .container-fluid') - .toggleClass('container-limited', this.fixedLayoutPref); + $('.content-wrapper .container-fluid').toggleClass( + 'container-limited', + this.fixedLayoutPref, + ); } } @@ -449,12 +467,12 @@ export default class MergeRequestTabs { const $diffTabs = $('#diff-notes-app'); - $tabs.off('affix.bs.affix affix-top.bs.affix') + $tabs + .off('affix.bs.affix affix-top.bs.affix') .affix({ offset: { - top: () => ( - $diffTabs.offset().top - $tabs.height() - $fixedNav.height() - ), + top: () => + $diffTabs.offset().top - $tabs.height() - $fixedNav.height(), }, }) .on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() })) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 7ca0245234d..4bcf4540f0d 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -33,7 +33,7 @@ import { getPagePath, scrollToElement, isMetaKey, - hasVueMRDiscussionsCookie, + isInMRPage, } from './lib/utils/common_utils'; import imageDiffHelper from './image_diff/helpers/index'; import { localTimeAgo } from './lib/utils/datetime_utility'; @@ -138,9 +138,7 @@ export default class Notes { } addBinding() { - this.$wrapperEl = hasVueMRDiscussionsCookie() - ? $(document).find('.diffs') - : $(document); + this.$wrapperEl = isInMRPage() ? $(document).find('.diffs') : $(document); // Edit note link this.$wrapperEl.on('click', '.js-note-edit', this.showEditForm.bind(this)); @@ -493,7 +491,7 @@ export default class Notes { const $note = $notesList.find(`#note_${noteEntity.id}`); if (Notes.isNewNote(noteEntity, this.note_ids)) { - if (hasVueMRDiscussionsCookie()) { + if (isInMRPage()) { return; } @@ -609,19 +607,6 @@ export default class Notes { .append($notes.closest('.content').children()); } } - // Init discussion on 'Discussion' page if it is merge request page - const page = $('body').attr('data-page'); - if ( - (page && page.indexOf('projects:merge_request') !== -1) || - !noteEntity.diff_discussion_html - ) { - if (!hasVueMRDiscussionsCookie()) { - Notes.animateAppendNote( - noteEntity.discussion_html, - $('.main-notes-list'), - ); - } - } } else { // append new note to all matching discussions Notes.animateAppendNote(noteEntity.html, discussionContainer); diff --git a/app/assets/javascripts/pages/projects/merge_requests/show/index.js b/app/assets/javascripts/pages/projects/merge_requests/show/index.js index e5b2827b50c..f61f4db78d5 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/show/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/show/index.js @@ -1,4 +1,3 @@ -import { hasVueMRDiscussionsCookie } from '~/lib/utils/common_utils'; import initMrNotes from '~/mr_notes'; import initSidebarBundle from '~/sidebar/sidebar_bundle'; import initShow from '../init_merge_request_show'; @@ -6,8 +5,5 @@ import initShow from '../init_merge_request_show'; document.addEventListener('DOMContentLoaded', () => { initShow(); initSidebarBundle(); - - if (hasVueMRDiscussionsCookie()) { - initMrNotes(); - } + initMrNotes(); }); diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 20aed60cb7a..a30ba37c568 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -179,7 +179,7 @@ module NotesHelper end def has_vue_discussions_cookie? - cookies[:vue_mr_discussions] == 'true' + true end def serialize_notes? |