Commit 051daa03 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'ee-37220-es-modules' into 'master'

Port of 37220-es-modules to EE

See merge request gitlab-org/gitlab-ee!2914
parents 7c627ac8 2328e10a
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* global Flash */ /* global Flash */
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'; const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';
...@@ -237,7 +238,7 @@ class AwardsHandler { ...@@ -237,7 +238,7 @@ class AwardsHandler {
addAward(votesBlock, awardUrl, emoji, checkMutuality, callback) { addAward(votesBlock, awardUrl, emoji, checkMutuality, callback) {
const isMainAwardsBlock = votesBlock.closest('.js-issue-note-awards').length; const isMainAwardsBlock = votesBlock.closest('.js-issue-note-awards').length;
if (gl.utils.isInIssuePage() && !isMainAwardsBlock) { if (isInIssuePage() && !isMainAwardsBlock) {
const id = votesBlock.attr('id').replace('note_', ''); const id = votesBlock.attr('id').replace('note_', '');
$('.emoji-menu').removeClass('is-visible'); $('.emoji-menu').removeClass('is-visible');
...@@ -288,7 +289,7 @@ class AwardsHandler { ...@@ -288,7 +289,7 @@ class AwardsHandler {
} }
getVotesBlock() { getVotesBlock() {
if (gl.utils.isInIssuePage()) { if (isInIssuePage()) {
const $el = $('.js-add-award.is-active').closest('.note.timeline-entry'); const $el = $('.js-add-award.is-active').closest('.note.timeline-entry');
if ($el.length) { if ($el.length) {
...@@ -452,11 +453,11 @@ class AwardsHandler { ...@@ -452,11 +453,11 @@ class AwardsHandler {
userAuthored($emojiButton) { userAuthored($emojiButton) {
const oldTitle = this.getAwardTooltip($emojiButton); const oldTitle = this.getAwardTooltip($emojiButton);
const newTitle = 'You cannot vote on your own issue, MR and note'; const newTitle = 'You cannot vote on your own issue, MR and note';
gl.utils.updateTooltipTitle($emojiButton, newTitle).tooltip('show'); updateTooltipTitle($emojiButton, newTitle).tooltip('show');
// Restore tooltip back to award list // Restore tooltip back to award list
return setTimeout(() => { return setTimeout(() => {
$emojiButton.tooltip('hide'); $emojiButton.tooltip('hide');
gl.utils.updateTooltipTitle($emojiButton, oldTitle); updateTooltipTitle($emojiButton, oldTitle);
}, 2800); }, 2800);
} }
......
import '../commons/bootstrap'; import '../commons/bootstrap';
import { isInIssuePage } from '../lib/utils/common_utils';
// Quick Submit behavior // Quick Submit behavior
// //
...@@ -45,7 +46,7 @@ $(document).on('keydown.quick_submit', '.js-quick-submit', (e) => { ...@@ -45,7 +46,7 @@ $(document).on('keydown.quick_submit', '.js-quick-submit', (e) => {
if (!$submitButton.attr('disabled')) { if (!$submitButton.attr('disabled')) {
$submitButton.trigger('click', [e]); $submitButton.trigger('click', [e]);
if (!gl.utils.isInIssuePage()) { if (!isInIssuePage()) {
$submitButton.disable(); $submitButton.disable();
} }
} }
......
/* global Flash */ /* global Flash */
import { handleLocationHash } from '../../lib/utils/common_utils';
export default class BlobViewer { export default class BlobViewer {
constructor() { constructor() {
BlobViewer.initAuxiliaryViewer(); BlobViewer.initAuxiliaryViewer();
...@@ -114,7 +116,7 @@ export default class BlobViewer { ...@@ -114,7 +116,7 @@ export default class BlobViewer {
$(viewer).renderGFM(); $(viewer).renderGFM();
this.$fileHolder.trigger('highlight:line'); this.$fileHolder.trigger('highlight:line');
gl.utils.handleLocationHash(); handleLocationHash();
this.toggleCopyButtonState(); this.toggleCopyButtonState();
}) })
......
...@@ -24,6 +24,7 @@ import './components/board_sidebar'; ...@@ -24,6 +24,7 @@ import './components/board_sidebar';
import './components/new_list_dropdown'; import './components/new_list_dropdown';
import './components/modal/index'; import './components/modal/index';
import '../vue_shared/vue_resource_interceptor'; import '../vue_shared/vue_resource_interceptor';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
import './components/boards_selector'; import './components/boards_selector';
import collapseIcon from './icons/fullscreen_collapse.svg'; import collapseIcon from './icons/fullscreen_collapse.svg';
...@@ -153,10 +154,10 @@ $(() => { ...@@ -153,10 +154,10 @@ $(() => {
modal: ModalStore.store, modal: ModalStore.store,
store: Store.state, store: Store.state,
isFullscreen: false, isFullscreen: false,
focusModeAvailable: gl.utils.convertPermissionToBoolean( focusModeAvailable: convertPermissionToBoolean(
$boardApp.dataset.focusModeAvailable, $boardApp.dataset.focusModeAvailable,
), ),
canAdminList: this.$options.el && gl.utils.convertPermissionToBoolean( canAdminList: this.$options.el && convertPermissionToBoolean(
this.$options.el.dataset.canAdminList, this.$options.el.dataset.canAdminList,
), ),
}; };
...@@ -226,7 +227,7 @@ $(() => { ...@@ -226,7 +227,7 @@ $(() => {
modal: ModalStore.store, modal: ModalStore.store,
store: Store.state, store: Store.state,
isFullscreen: false, isFullscreen: false,
focusModeAvailable: gl.utils.convertPermissionToBoolean($boardApp.dataset.focusModeAvailable), focusModeAvailable: convertPermissionToBoolean($boardApp.dataset.focusModeAvailable),
}, },
methods: { methods: {
toggleFocusMode() { toggleFocusMode() {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import boardsStoreEE from 'ee/boards/stores/boards_store_ee'; import boardsStoreEE from 'ee/boards/stores/boards_store_ee';
import { getUrlParamsArray } from '../../lib/utils/common_utils';
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {}; window.gl.issueBoards = window.gl.issueBoards || {};
...@@ -22,7 +23,7 @@ gl.issueBoards.BoardsStore = { ...@@ -22,7 +23,7 @@ gl.issueBoards.BoardsStore = {
}, },
create () { create () {
this.state.lists = []; this.state.lists = [];
this.filter.path = gl.utils.getUrlParamsArray().join('&'); this.filter.path = getUrlParamsArray().join('&');
this.detail = { issue: {} }; this.detail = { issue: {} };
}, },
createNewListDropdownData() { createNewListDropdownData() {
......
...@@ -3,6 +3,7 @@ consistent-return, prefer-rest-params */ ...@@ -3,6 +3,7 @@ consistent-return, prefer-rest-params */
import _ from 'underscore'; import _ from 'underscore';
import bp from './breakpoints'; import bp from './breakpoints';
import { bytesToKiB } from './lib/utils/number_utils'; import { bytesToKiB } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils';
window.Build = (function () { window.Build = (function () {
Build.timeout = null; Build.timeout = null;
...@@ -169,7 +170,7 @@ window.Build = (function () { ...@@ -169,7 +170,7 @@ window.Build = (function () {
data: this.state, data: this.state,
}) })
.done((log) => { .done((log) => {
gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`); setCiStatusFavicon(`${this.pageUrl}/status.json`);
if (log.state) { if (log.state) {
this.state = log.state; this.state = log.state;
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, camelcase, one-var-declaration-per-line, no-else-return, max-len */ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, camelcase, one-var-declaration-per-line, no-else-return, max-len */
import { rstrip } from './lib/utils/common_utils';
window.ConfirmDangerModal = (function() { window.ConfirmDangerModal = (function() {
function ConfirmDangerModal(form, text, arg) { function ConfirmDangerModal(form, text, arg) {
...@@ -16,7 +17,7 @@ window.ConfirmDangerModal = (function() { ...@@ -16,7 +17,7 @@ window.ConfirmDangerModal = (function() {
submit.disable(); submit.disable();
$('.js-confirm-danger-input').off('input'); $('.js-confirm-danger-input').off('input');
$('.js-confirm-danger-input').on('input', function() { $('.js-confirm-danger-input').on('input', function() {
if (gl.utils.rstrip($(this).val()) === project_path) { if (rstrip($(this).val()) === project_path) {
return submit.enable(); return submit.enable();
} else { } else {
return submit.disable(); return submit.disable();
......
/* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */
import _ from 'underscore'; import _ from 'underscore';
import './lib/utils/common_utils'; import { insertText, getSelectedFragment, nodeMatchesSelector } from './lib/utils/common_utils';
import { placeholderImage } from './lazy_loader'; import { placeholderImage } from './lazy_loader';
const gfmRules = { const gfmRules = {
...@@ -295,7 +295,7 @@ class CopyAsGFM { ...@@ -295,7 +295,7 @@ class CopyAsGFM {
const clipboardData = e.originalEvent.clipboardData; const clipboardData = e.originalEvent.clipboardData;
if (!clipboardData) return; if (!clipboardData) return;
const documentFragment = window.gl.utils.getSelectedFragment(); const documentFragment = getSelectedFragment();
if (!documentFragment) return; if (!documentFragment) return;
const el = transformer(documentFragment.cloneNode(true)); const el = transformer(documentFragment.cloneNode(true));
...@@ -412,7 +412,7 @@ class CopyAsGFM { ...@@ -412,7 +412,7 @@ class CopyAsGFM {
for (const selector in rules) { for (const selector in rules) {
const func = rules[selector]; const func = rules[selector];
if (!window.gl.utils.nodeMatchesSelector(node, selector)) continue; if (!nodeMatchesSelector(node, selector)) continue;
let result; let result;
if (func.length === 2) { if (func.length === 2) {
......
...@@ -83,6 +83,7 @@ import initProjectVisibilitySelector from './project_visibility'; ...@@ -83,6 +83,7 @@ import initProjectVisibilitySelector from './project_visibility';
import GpgBadges from './gpg_badges'; import GpgBadges from './gpg_badges';
import UserFeatureHelper from './helpers/user_feature_helper'; import UserFeatureHelper from './helpers/user_feature_helper';
import initChangesDropdown from './init_changes_dropdown'; import initChangesDropdown from './init_changes_dropdown';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
// EE-only // EE-only
import ApproversSelect from './approvers_select'; import ApproversSelect from './approvers_select';
...@@ -112,7 +113,7 @@ import initGroupAnalytics from './init_group_analytics'; ...@@ -112,7 +113,7 @@ import initGroupAnalytics from './init_group_analytics';
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => { $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources); const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
const enableGFM = gl.utils.convertPermissionToBoolean(el.dataset.supportsAutocomplete); const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), { gfm.setup($(el), {
emojis: true, emojis: true,
members: enableGFM, members: enableGFM,
...@@ -385,7 +386,7 @@ import initGroupAnalytics from './init_group_analytics'; ...@@ -385,7 +386,7 @@ import initGroupAnalytics from './init_group_analytics';
if ($('.project-show-activity').length) new gl.Activities(); if ($('.project-show-activity').length) new gl.Activities();
$('#tree-slider').waitForImages(function() { $('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
}); });
initGeoInfoModal(); initGeoInfoModal();
...@@ -475,7 +476,7 @@ import initGroupAnalytics from './init_group_analytics'; ...@@ -475,7 +476,7 @@ import initGroupAnalytics from './init_group_analytics';
new UserCallout({ setCalloutPerProject: true }); new UserCallout({ setCalloutPerProject: true });
$('#tree-slider').waitForImages(function() { $('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
}); });
break; break;
case 'projects:find_file:show': case 'projects:find_file:show':
......
...@@ -6,7 +6,7 @@ import environmentTable from './environments_table.vue'; ...@@ -6,7 +6,7 @@ import environmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store'; import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue'; import tablePagination from '../../vue_shared/components/table_pagination.vue';
import '../../lib/utils/common_utils'; import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import Poll from '../../lib/utils/poll'; import Poll from '../../lib/utils/poll';
import environmentsMixin from '../mixins/environments_mixin'; import environmentsMixin from '../mixins/environments_mixin';
...@@ -52,19 +52,19 @@ export default { ...@@ -52,19 +52,19 @@ export default {
computed: { computed: {
scope() { scope() {
return gl.utils.getParameterByName('scope'); return getParameterByName('scope');
}, },
canReadEnvironmentParsed() { canReadEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canReadEnvironment); return convertPermissionToBoolean(this.canReadEnvironment);
}, },
canCreateDeploymentParsed() { canCreateDeploymentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateDeployment); return convertPermissionToBoolean(this.canCreateDeployment);
}, },
canCreateEnvironmentParsed() { canCreateEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateEnvironment); return convertPermissionToBoolean(this.canCreateEnvironment);
}, },
/** /**
...@@ -83,8 +83,8 @@ export default { ...@@ -83,8 +83,8 @@ export default {
* Toggles loading property. * Toggles loading property.
*/ */
created() { created() {
const scope = gl.utils.getParameterByName('scope') || this.visibility; const scope = getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber; const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint); this.service = new EnvironmentsService(this.endpoint);
...@@ -154,15 +154,15 @@ export default { ...@@ -154,15 +154,15 @@ export default {
* @return {String} * @return {String}
*/ */
changePage(pageNumber) { changePage(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber); const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param); gl.utils.visitUrl(param);
return param; return param;
}, },
fetchEnvironments() { fetchEnvironments() {
const scope = gl.utils.getParameterByName('scope') || this.visibility; const scope = getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber; const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true; this.isLoading = true;
......
...@@ -9,7 +9,7 @@ import tablePagination from '../../vue_shared/components/table_pagination.vue'; ...@@ -9,7 +9,7 @@ import tablePagination from '../../vue_shared/components/table_pagination.vue';
import Poll from '../../lib/utils/poll'; import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin'; import environmentsMixin from '../mixins/environments_mixin';
import '../../lib/utils/common_utils'; import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default { export default {
components: { components: {
...@@ -48,15 +48,15 @@ export default { ...@@ -48,15 +48,15 @@ export default {
computed: { computed: {
scope() { scope() {
return gl.utils.getParameterByName('scope'); return getParameterByName('scope');
}, },
canReadEnvironmentParsed() { canReadEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canReadEnvironment); return convertPermissionToBoolean(this.canReadEnvironment);
}, },
canCreateDeploymentParsed() { canCreateDeploymentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateDeployment); return convertPermissionToBoolean(this.canCreateDeployment);
}, },
/** /**
...@@ -83,8 +83,8 @@ export default { ...@@ -83,8 +83,8 @@ export default {
* Toggles loading property. * Toggles loading property.
*/ */
created() { created() {
const scope = gl.utils.getParameterByName('scope') || this.visibility; const scope = getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber; const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint); this.service = new EnvironmentsService(this.endpoint);
...@@ -137,15 +137,15 @@ export default { ...@@ -137,15 +137,15 @@ export default {
* @param {Number} pageNumber desired page to go to. * @param {Number} pageNumber desired page to go to.
*/ */
changePage(pageNumber) { changePage(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber); const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param); gl.utils.visitUrl(param);
return param; return param;
}, },
fetchEnvironments() { fetchEnvironments() {
const scope = gl.utils.getParameterByName('scope') || this.visibility; const scope = getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber; const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true; this.isLoading = true;
......
import '~/lib/utils/common_utils'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
/** /**
* Environments Store. * Environments Store.
* *
...@@ -97,8 +97,8 @@ export default class EnvironmentsStore { ...@@ -97,8 +97,8 @@ export default class EnvironmentsStore {
* @return {Object} * @return {Object}
*/ */
setPagination(pagination = {}) { setPagination(pagination = {}) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination); const normalizedHeaders = normalizeHeaders(pagination);
const paginationInformation = gl.utils.parseIntPagination(normalizedHeaders); const paginationInformation = parseIntPagination(normalizedHeaders);
this.state.paginationInformation = paginationInformation; this.state.paginationInformation = paginationInformation;
return paginationInformation; return paginationInformation;
......
<script> <script>
import tablePagination from '~/vue_shared/components/table_pagination.vue'; import tablePagination from '~/vue_shared/components/table_pagination.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { getParameterByName } from '../../lib/utils/common_utils';
export default { export default {
props: { props: {
...@@ -18,8 +19,8 @@ export default { ...@@ -18,8 +19,8 @@ export default {
}, },
methods: { methods: {
change(page) { change(page) {
const filterGroupsParam = gl.utils.getParameterByName('filter_groups'); const filterGroupsParam = getParameterByName('filter_groups');
const sortParam = gl.utils.getParameterByName('sort'); const sortParam = getParameterByName('sort');
eventHub.$emit('fetchPage', page, filterGroupsParam, sortParam); eventHub.$emit('fetchPage', page, filterGroupsParam, sortParam);
}, },
}, },
......
import FilterableList from '~/filterable_list'; import FilterableList from '~/filterable_list';
import eventHub from './event_hub'; import eventHub from './event_hub';
import { getParameterByName } from '../lib/utils/common_utils';
export default class GroupFilterableList extends FilterableList { export default class GroupFilterableList extends FilterableList {
constructor({ form, filter, holder, filterEndpoint, pagePath }) { constructor({ form, filter, holder, filterEndpoint, pagePath }) {
...@@ -54,7 +55,7 @@ export default class GroupFilterableList extends FilterableList { ...@@ -54,7 +55,7 @@ export default class GroupFilterableList extends FilterableList {
e.preventDefault(); e.preventDefault();
const queryData = {}; const queryData = {};
const sortParam = gl.utils.getParameterByName('sort', e.currentTarget.href); const sortParam = getParameterByName('sort', e.currentTarget.href);
if (sortParam) { if (sortParam) {
queryData.sort = sortParam; queryData.sort = sortParam;
......
...@@ -8,6 +8,7 @@ import GroupItem from './components/group_item.vue'; ...@@ -8,6 +8,7 @@ import GroupItem from './components/group_item.vue';
import GroupsStore from './stores/groups_store'; import GroupsStore from './stores/groups_store';
import GroupsService from './services/groups_service'; import GroupsService from './services/groups_service';
import eventHub from './event_hub'; import eventHub from './event_hub';
import { getParameterByName } from '../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('dashboard-group-app'); const el = document.getElementById('dashboard-group-app');
...@@ -58,17 +59,17 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -58,17 +59,17 @@ document.addEventListener('DOMContentLoaded', () => {
this.isLoading = true; this.isLoading = true;
} }
pageParam = gl.utils.getParameterByName('page'); pageParam = getParameterByName('page');
if (pageParam) { if (pageParam) {
page = pageParam; page = pageParam;
} }
filterGroupsParam = gl.utils.getParameterByName('filter_groups'); filterGroupsParam = getParameterByName('filter_groups');
if (filterGroupsParam) { if (filterGroupsParam) {
filterGroups = filterGroupsParam; filterGroups = filterGroupsParam;
} }
sortParam = gl.utils.getParameterByName('sort'); sortParam = getParameterByName('sort');
if (sortParam) { if (sortParam) {
sort = sortParam; sort = sortParam;
} }
......
import Vue from 'vue'; import Vue from 'vue';
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default class GroupsStore { export default class GroupsStore {
constructor() { constructor() {
...@@ -30,8 +31,8 @@ export default class GroupsStore { ...@@ -30,8 +31,8 @@ export default class GroupsStore {
let paginationInfo; let paginationInfo;
if (Object.keys(pagination).length) { if (Object.keys(pagination).length) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination); const normalizedHeaders = normalizeHeaders(pagination);
paginationInfo = gl.utils.parseIntPagination(normalizedHeaders); paginationInfo = parseIntPagination(normalizedHeaders);
} else { } else {
paginationInfo = pagination; paginationInfo = pagination;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, prefer-rest-params, prefer-spread, no-unused-vars, prefer-template,
promise/catch-or-return */ promise/catch-or-return */
import Api from './api'; import Api from './api';
import { normalizeCRLFHeaders } from './lib/utils/common_utils';
var slice = [].slice; var slice = [].slice;
...@@ -30,7 +31,7 @@ window.GroupsSelect = (function() { ...@@ -30,7 +31,7 @@ window.GroupsSelect = (function() {
$.ajax(params).then((data, status, xhr) => { $.ajax(params).then((data, status, xhr) => {
const results = data || []; const results = data || [];
const headers = gl.utils.normalizeCRLFHeaders(xhr.getAllResponseHeaders()); const headers = normalizeCRLFHeaders(xhr.getAllResponseHeaders());
const currentPage = parseInt(headers['X-PAGE'], 10) || 0; const currentPage = parseInt(headers['X-PAGE'], 10) || 0;
const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0; const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0;
const more = currentPage < totalPages; const more = currentPage < totalPages;
......
import Vue from 'vue'; import Vue from 'vue';
import RelatedIssuesRoot from './related_issues/components/related_issues_root.vue'; import RelatedIssuesRoot from './related_issues/components/related_issues_root.vue';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const relatedIssuesRootElement = document.querySelector('.js-related-issues-root'); const relatedIssuesRootElement = document.querySelector('.js-related-issues-root');
...@@ -13,7 +14,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -13,7 +14,7 @@ document.addEventListener('DOMContentLoaded', () => {
render: createElement => createElement('related-issues-root', { render: createElement => createElement('related-issues-root', {
props: { props: {
endpoint: relatedIssuesRootElement.dataset.endpoint, endpoint: relatedIssuesRootElement.dataset.endpoint,
canAddRelatedIssues: gl.utils.convertPermissionToBoolean( canAddRelatedIssues: convertPermissionToBoolean(
relatedIssuesRootElement.dataset.canAddRelatedIssues, relatedIssuesRootElement.dataset.canAddRelatedIssues,
), ),
helpPath: relatedIssuesRootElement.dataset.helpPath, helpPath: relatedIssuesRootElement.dataset.helpPath,
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-param-reassign, no-else-return, quotes, object-shorthand, comma-dangle, camelcase, one-var, vars-on-top, one-var-declaration-per-line, no-return-assign, consistent-return, max-len, prefer-template */
(function() { export const getPagePath = (index = 0) => $('body').data('page').split(':')[index];
(function(w) {
var base; export const isInGroupsPage = () => getPagePath() === 'groups';
const faviconEl = document.getElementById('favicon');
const originalFavicon = faviconEl ? faviconEl.getAttribute('href') : null; export const isInProjectPage = () => getPagePath() === 'projects';
w.gl || (w.gl = {});
(base = w.gl).utils || (base.utils = {}); export const getProjectSlug = () => {
w.gl.utils.isInGroupsPage = function() { if (isInProjectPage()) {
return gl.utils.getPagePath() === 'groups';
};
w.gl.utils.isInProjectPage = function() {
return gl.utils.getPagePath() === 'projects';
};
w.gl.utils.getProjectSlug = function() {
if (this.isInProjectPage()) {
return $('body').data('project'); return $('body').data('project');
} else {
return null;
} }
};
w.gl.utils.getGroupSlug = function() {
if (this.isInGroupsPage()) {
return $('body').data('group');
} else {
return null; return null;
};
export const getGroupSlug = () => {
if (isInGroupsPage()) {
return $('body').data('group');
} }
}; return null;
};
w.gl.utils.isInIssuePage = () => { export const isInIssuePage = () => {
const page = gl.utils.getPagePath(1); const page = getPagePath(1);
const action = gl.utils.getPagePath(2); const action = getPagePath(2);
return page === 'issues' && action === 'show'; return page === 'issues' && action === 'show';
}; };
w.gl.utils.ajaxGet = function(url) { export const ajaxGet = url => $.ajax({
return $.ajax({ type: 'GET',
type: "GET", url,
url: url, dataType: 'script',
dataType: "script" });
});
};
w.gl.utils.ajaxPost = function(url, data) { export const ajaxPost = (url, data) => $.ajax({
return $.ajax({
type: 'POST', type: 'POST',
url: url, url,
data: data, data,
}); });
};
w.gl.utils.extractLast = function(term) {
return this.split(term).pop();
};
w.gl.utils.rstrip = function rstrip(val) { export const rstrip = (val) => {
if (val) { if (val) {
return val.replace(/\s+$/, ''); return val.replace(/\s+$/, '');
} else {
return val;
} }
}; return val;
};
gl.utils.updateTooltipTitle = function($tooltipEl, newTitle) { export const updateTooltipTitle = ($tooltipEl, newTitle) => $tooltipEl.attr('title', newTitle).tooltip('fixTitle');
return $tooltipEl.attr('title', newTitle).tooltip('fixTitle');
};
w.gl.utils.disableButtonIfEmptyField = function(field_selector, button_selector, event_name) { export const disableButtonIfEmptyField = (fieldSelector, buttonSelector, eventName = 'input') => {
event_name = event_name || 'input'; const field = $(fieldSelector);
var closest_submit, field, that; const closestSubmit = field.closest('form').find(buttonSelector);
that = this; if (rstrip(field.val()) === '') {
field = $(field_selector); closestSubmit.disable();
closest_submit = field.closest('form').find(button_selector);
if (this.rstrip(field.val()) === "") {
closest_submit.disable();
} }
return field.on(event_name, function() { // eslint-disable-next-line func-names
if (that.rstrip($(this).val()) === "") { return field.on(eventName, function () {
return closest_submit.disable(); if (rstrip($(this).val()) === '') {
} else { return closestSubmit.disable();
return closest_submit.enable();
} }
return closestSubmit.enable();
}); });
}; };
// automatically adjust scroll position for hash urls taking the height of the navbar into account // automatically adjust scroll position for hash urls taking the height of the navbar into account
// https://github.com/twitter/bootstrap/issues/1768 // https://github.com/twitter/bootstrap/issues/1768
w.gl.utils.handleLocationHash = function() { export const handleLocationHash = () => {
var hash = w.gl.utils.getLocationHash(); let hash = window.gl.utils.getLocationHash();
if (!hash) return; if (!hash) return;
// This is required to handle non-unicode characters in hash // This is required to handle non-unicode characters in hash
...@@ -97,12 +75,12 @@ ...@@ -97,12 +75,12 @@
const fixedDiffStats = document.querySelector('.js-diff-files-changed.is-stuck'); const fixedDiffStats = document.querySelector('.js-diff-files-changed.is-stuck');
const fixedNav = document.querySelector('.navbar-gitlab'); const fixedNav = document.querySelector('.navbar-gitlab');
var adjustment = 0; let adjustment = 0;
if (fixedNav) adjustment -= fixedNav.offsetHeight; if (fixedNav) adjustment -= fixedNav.offsetHeight;
// scroll to user-generated markdown anchor if we cannot find a match // scroll to user-generated markdown anchor if we cannot find a match
if (document.getElementById(hash) === null) { if (document.getElementById(hash) === null) {
var target = document.getElementById('user-content-' + hash); const target = document.getElementById(`user-content-${hash}`);
if (target && target.scrollIntoView) { if (target && target.scrollIntoView) {
target.scrollIntoView(true); target.scrollIntoView(true);
window.scrollBy(0, adjustment); window.scrollBy(0, adjustment);
...@@ -119,12 +97,12 @@ ...@@ -119,12 +97,12 @@
window.scrollBy(0, adjustment); window.scrollBy(0, adjustment);
} }
}; };
// Check if element scrolled into viewport from above or below // Check if element scrolled into viewport from above or below
// Courtesy http://stackoverflow.com/a/7557433/414749 // Courtesy http://stackoverflow.com/a/7557433/414749
w.gl.utils.isInViewport = function(el) { export const isInViewport = (el) => {
var rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
return ( return (
rect.top >= 0 && rect.top >= 0 &&
...@@ -132,48 +110,37 @@ ...@@ -132,48 +110,37 @@
rect.bottom <= window.innerHeight && rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth rect.right <= window.innerWidth
); );
}; };
gl.utils.getPagePath = function(index) {
index = index || 0;
return $('body').data('page').split(':')[index];
};
gl.utils.parseUrl = function (url) { export const parseUrl = (url) => {
var parser = document.createElement('a'); const parser = document.createElement('a');
parser.href = url; parser.href = url;
return parser; return parser;
}; };
gl.utils.parseUrlPathname = function (url) { export const parseUrlPathname = (url) => {
var parsedUrl = gl.utils.parseUrl(url); const parsedUrl = parseUrl(url);
// parsedUrl.pathname will return an absolute path for Firefox and a relative path for IE11 // 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. // 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}`;
}; };
gl.utils.getUrlParamsArray = function () { // We can trust that each param has one & since values containing & will be encoded
// We can trust that each param has one & since values containing & will be encoded // Remove the first character of search as it is always ?
// Remove the first character of search as it is always ? export const getUrlParamsArray = () => window.location.search.slice(1).split('&').map((param) => {
return window.location.search.slice(1).split('&').map((param) => {
const split = param.split('='); const split = param.split('=');
return [decodeURI(split[0]), split[1]].join('='); return [decodeURI(split[0]), split[1]].join('=');
}); });
};
gl.utils.isMetaKey = function(e) { export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
return e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
};
gl.utils.isMetaClick = function(e) { // Identify following special clicks
// Identify following special clicks // 1) Cmd + Click on Mac (e.metaKey)
// 1) Cmd + Click on Mac (e.metaKey) // 2) Ctrl + Click on PC (e.ctrlKey)
// 2) Ctrl + Click on PC (e.ctrlKey) // 3) Middle-click or Mouse Wheel Click (e.which is 2)
// 3) Middle-click or Mouse Wheel Click (e.which is 2) export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2;
return e.metaKey || e.ctrlKey || e.which === 2;
};
gl.utils.scrollToElement = function($el) { export const scrollToElement = ($el) => {
const top = $el.offset().top; const top = $el.offset().top;
const mrTabsHeight = $('.merge-request-tabs').height() || 0; const mrTabsHeight = $('.merge-request-tabs').height() || 0;
const headerHeight = $('.navbar-gitlab').height() || 0; const headerHeight = $('.navbar-gitlab').height() || 0;
...@@ -181,24 +148,24 @@ ...@@ -181,24 +148,24 @@
return $('body, html').animate({ return $('body, html').animate({
scrollTop: top - mrTabsHeight - headerHeight, scrollTop: top - mrTabsHeight - headerHeight,
}, 200); }, 200);
}; };
/** /**
this will take in the `name` of the param you want to parse in the url this will take in the `name` of the param you want to parse in the url
if the name does not exist this function will return `null` if the name does not exist this function will return `null`
otherwise it will return the value of the param key provided otherwise it will return the value of the param key provided
*/ */
w.gl.utils.getParameterByName = (name, parseUrl) => { export const getParameterByName = (name, urlToParse) => {
const url = parseUrl || window.location.href; const url = urlToParse || window.location.href;
name = name.replace(/[[\]]/g, '\\$&'); const parsedName = name.replace(/[[\]]/g, '\\$&');
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`); const regex = new RegExp(`[?&]${parsedName}(=([^&#]*)|&|#|$)`);
const results = regex.exec(url); const results = regex.exec(url);
if (!results) return null; if (!results) return null;
if (!results[2]) return ''; if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' ')); return decodeURIComponent(results[2].replace(/\+/g, ' '));
}; };
w.gl.utils.getSelectedFragment = () => { export const getSelectedFragment = () => {
const selection = window.getSelection(); const selection = window.getSelection();
if (selection.rangeCount === 0) return null; if (selection.rangeCount === 0) return null;
const documentFragment = document.createDocumentFragment(); const documentFragment = document.createDocumentFragment();
...@@ -208,11 +175,11 @@ ...@@ -208,11 +175,11 @@
if (documentFragment.textContent.length === 0) return null; if (documentFragment.textContent.length === 0) return null;
return documentFragment; return documentFragment;
}; };
w.gl.utils.insertText = (target, text) => { // TODO: Update this name, there is a gl.text.insertText function.
export const insertText = (target, text) => {
// Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas // Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas
const selectionStart = target.selectionStart; const selectionStart = target.selectionStart;
const selectionEnd = target.selectionEnd; const selectionEnd = target.selectionEnd;
const value = target.value; const value = target.value;
...@@ -223,19 +190,21 @@ ...@@ -223,19 +190,21 @@
const insertedText = text instanceof Function ? text(textBefore, textAfter) : text; const insertedText = text instanceof Function ? text(textBefore, textAfter) : text;
const newText = textBefore + insertedText + textAfter; const newText = textBefore + insertedText + textAfter;
// eslint-disable-next-line no-param-reassign
target.value = newText; 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 // Trigger autosave
$(target).trigger('input'); $(target).trigger('input');
// Trigger autosize // Trigger autosize
var event = document.createEvent('Event'); const event = document.createEvent('Event');
event.initEvent('autosize:update', true, false); event.initEvent('autosize:update', true, false);
target.dispatchEvent(event); target.dispatchEvent(event);
}; };
w.gl.utils.nodeMatchesSelector = (node, selector) => { export const nodeMatchesSelector = (node, selector) => {
const matches = Element.prototype.matches || const matches = Element.prototype.matches ||
Element.prototype.matchesSelector || Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector || Element.prototype.mozMatchesSelector ||
...@@ -252,19 +221,20 @@ ...@@ -252,19 +221,20 @@
let parentNode = node.parentNode; let parentNode = node.parentNode;
if (!parentNode) { if (!parentNode) {
parentNode = document.createElement('div'); parentNode = document.createElement('div');
// eslint-disable-next-line no-param-reassign
node = node.cloneNode(true); node = node.cloneNode(true);
parentNode.appendChild(node); parentNode.appendChild(node);
} }
const matchingNodes = parentNode.querySelectorAll(selector); const matchingNodes = parentNode.querySelectorAll(selector);
return Array.prototype.indexOf.call(matchingNodes, node) !== -1; return Array.prototype.indexOf.call(matchingNodes, node) !== -1;
}; };
/** /**
this will take in the headers from an API response and normalize them 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 this way we don't run into production issues when nginx gives us lowercased header keys
*/ */
w.gl.utils.normalizeHeaders = (headers) => { export const normalizeHeaders = (headers) => {
const upperCaseHeaders = {}; const upperCaseHeaders = {};
Object.keys(headers).forEach((e) => { Object.keys(headers).forEach((e) => {
...@@ -272,13 +242,13 @@ ...@@ -272,13 +242,13 @@
}); });
return upperCaseHeaders; return upperCaseHeaders;
}; };
/** /**
this will take in the getAllResponseHeaders result and normalize them 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 this way we don't run into production issues when nginx gives us lowercased header keys
*/ */
w.gl.utils.normalizeCRLFHeaders = (headers) => { export const normalizeCRLFHeaders = (headers) => {
const headersObject = {}; const headersObject = {};
const headersArray = headers.split('\n'); const headersArray = headers.split('\n');
...@@ -287,25 +257,25 @@ ...@@ -287,25 +257,25 @@
headersObject[keyValue[0]] = keyValue[1]; headersObject[keyValue[0]] = keyValue[1];
}); });
return w.gl.utils.normalizeHeaders(headersObject); return normalizeHeaders(headersObject);
}; };
/** /**
* Parses pagination object string values into numbers. * Parses pagination object string values into numbers.
* *
* @param {Object} paginationInformation * @param {Object} paginationInformation
* @returns {Object} * @returns {Object}
*/ */
w.gl.utils.parseIntPagination = paginationInformation => ({ export const parseIntPagination = paginationInformation => ({
perPage: parseInt(paginationInformation['X-PER-PAGE'], 10), perPage: parseInt(paginationInformation['X-PER-PAGE'], 10),
page: parseInt(paginationInformation['X-PAGE'], 10), page: parseInt(paginationInformation['X-PAGE'], 10),
total: parseInt(paginationInformation['X-TOTAL'], 10), total: parseInt(paginationInformation['X-TOTAL'], 10),
totalPages: parseInt(paginationInformation['X-TOTAL-PAGES'], 10), totalPages: parseInt(paginationInformation['X-TOTAL-PAGES'], 10),
nextPage: parseInt(paginationInformation['X-NEXT-PAGE'], 10), nextPage: parseInt(paginationInformation['X-NEXT-PAGE'], 10),
previousPage: parseInt(paginationInformation['X-PREV-PAGE'], 10), previousPage: parseInt(paginationInformation['X-PREV-PAGE'], 10),
}); });
/** /**
* Updates the search parameter of a URL given the parameter and value provided. * Updates the search parameter of a URL given the parameter and value provided.
* *
* If no search params are present we'll add it. * If no search params are present we'll add it.
...@@ -317,7 +287,7 @@ ...@@ -317,7 +287,7 @@
* @param {Number|String|Undefined|Null} value * @param {Number|String|Undefined|Null} value
* @return {String} * @return {String}
*/ */
w.gl.utils.setParamInURL = (param, value) => { export const setParamInURL = (param, value) => {
let search; let search;
const locationSearch = window.location.search; const locationSearch = window.location.search;
...@@ -326,6 +296,7 @@ ...@@ -326,6 +296,7 @@
.split('&') .split('&')
.reduce((acc, element) => { .reduce((acc, element) => {
const val = element.split('='); const val = element.split('=');
// eslint-disable-next-line no-param-reassign
acc[val[0]] = decodeURIComponent(val[1]); acc[val[0]] = decodeURIComponent(val[1]);
return acc; return acc;
}, {}); }, {});
...@@ -342,17 +313,17 @@ ...@@ -342,17 +313,17 @@
} }
return search; return search;
}; };
/** /**
* Converts permission provided as strings to booleans. * Converts permission provided as strings to booleans.
* *
* @param {String} string * @param {String} string
* @returns {Boolean} * @returns {Boolean}
*/ */
w.gl.utils.convertPermissionToBoolean = permission => permission === 'true'; export const convertPermissionToBoolean = permission => permission === 'true';
/** /**
* Back Off exponential algorithm * Back Off exponential algorithm
* backOff :: (Function<next, stop>, Number) -> Promise<Any, Error> * backOff :: (Function<next, stop>, Number) -> Promise<Any, Error>
* *
...@@ -383,7 +354,7 @@ ...@@ -383,7 +354,7 @@
* }) * })
* ``` * ```
*/ */
w.gl.utils.backOff = (fn, timeout = 60000) => { export const backOff = (fn, timeout = 60000) => {
const maxInterval = 32000; const maxInterval = 32000;
let nextInterval = 2000; let nextInterval = 2000;
let timeElapsed = 0; let timeElapsed = 0;
...@@ -403,35 +374,64 @@ ...@@ -403,35 +374,64 @@
fn(next, stop); fn(next, stop);
}); });
}; };
w.gl.utils.setFavicon = (faviconPath) => { export const setFavicon = (faviconPath) => {
const faviconEl = document.getElementById('favicon');
if (faviconEl && faviconPath) { if (faviconEl && faviconPath) {
faviconEl.setAttribute('href', faviconPath); faviconEl.setAttribute('href', faviconPath);
} }
}; };
w.gl.utils.resetFavicon = () => { export const resetFavicon = () => {
const faviconEl = document.getElementById('favicon');
const originalFavicon = faviconEl ? faviconEl.getAttribute('href') : null;
if (faviconEl) { if (faviconEl) {
faviconEl.setAttribute('href', originalFavicon); faviconEl.setAttribute('href', originalFavicon);
} }
}; };
w.gl.utils.setCiStatusFavicon = (pageUrl) => { export const setCiStatusFavicon = (pageUrl) => {
$.ajax({ $.ajax({
url: pageUrl, url: pageUrl,
dataType: 'json', dataType: 'json',
success: function(data) { success: (data) => {
if (data && data.favicon) { if (data && data.favicon) {
gl.utils.setFavicon(data.favicon); setFavicon(data.favicon);
} else { } else {
gl.utils.resetFavicon(); resetFavicon();
} }
}, },
error: function() { error: () => {
gl.utils.resetFavicon(); resetFavicon();
} },
}); });
}; };
})(window);
}).call(window); window.gl = window.gl || {};
window.gl.utils = {
...(window.gl.utils || {}),
getPagePath,
isInGroupsPage,
isInProjectPage,
getProjectSlug,
getGroupSlug,
isInIssuePage,
ajaxGet,
ajaxPost,
rstrip,
updateTooltipTitle,
disableButtonIfEmptyField,
handleLocationHash,
isInViewport,
parseUrl,
parseUrlPathname,
getUrlParamsArray,
isMetaKey,
isMetaClick,
scrollToElement,
getParameterByName,
getSelectedFragment,
insertText,
nodeMatchesSelector,
};
import httpStatusCodes from './http_status'; import httpStatusCodes from './http_status';
import { normalizeHeaders } from './common_utils';
/** /**
* Polling utility for handling realtime updates. * Polling utility for handling realtime updates.
...@@ -57,7 +58,7 @@ export default class Poll { ...@@ -57,7 +58,7 @@ export default class Poll {
} }
checkConditions(response) { checkConditions(response) {
const headers = gl.utils.normalizeHeaders(response.headers); const headers = normalizeHeaders(response.headers);
const pollInterval = parseInt(headers[this.intervalHeader], 10); const pollInterval = parseInt(headers[this.intervalHeader], 10);
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) { if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
......
...@@ -40,7 +40,7 @@ import './commit/image_file'; ...@@ -40,7 +40,7 @@ import './commit/image_file';
// lib/utils // lib/utils
import './lib/utils/bootstrap_linked_tabs'; import './lib/utils/bootstrap_linked_tabs';
import './lib/utils/common_utils'; import { handleLocationHash } from './lib/utils/common_utils';
import './lib/utils/datetime_utility'; import './lib/utils/datetime_utility';
import './lib/utils/pretty_time'; import './lib/utils/pretty_time';
import './lib/utils/text_utility'; import './lib/utils/text_utility';
...@@ -169,10 +169,10 @@ document.addEventListener('beforeunload', function () { ...@@ -169,10 +169,10 @@ document.addEventListener('beforeunload', function () {
$('[data-toggle="popover"]').popover('destroy'); $('[data-toggle="popover"]').popover('destroy');
}); });
window.addEventListener('hashchange', gl.utils.handleLocationHash); window.addEventListener('hashchange', handleLocationHash);
window.addEventListener('load', function onLoad() { window.addEventListener('load', function onLoad() {
window.removeEventListener('load', onLoad, false); window.removeEventListener('load', onLoad, false);
gl.utils.handleLocationHash(); handleLocationHash();
}, false); }, false);
gl.lazyLoader = new LazyLoader({ gl.lazyLoader = new LazyLoader({
...@@ -198,7 +198,7 @@ $(function () { ...@@ -198,7 +198,7 @@ $(function () {
$body.on('click', 'a[href^="#"]', function() { $body.on('click', 'a[href^="#"]', function() {
var href = this.getAttribute('href'); var href = this.getAttribute('href');
if (href.substr(1) === gl.utils.getLocationHash()) { if (href.substr(1) === gl.utils.getLocationHash()) {
setTimeout(gl.utils.handleLocationHash, 1); setTimeout(handleLocationHash, 1);
} }
}); });
......
...@@ -7,6 +7,11 @@ import './flash'; ...@@ -7,6 +7,11 @@ import './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion'; import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown'; import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints'; import bp from './breakpoints';
import {
parseUrlPathname,
handleLocationHash,
isMetaClick,
} from './lib/utils/common_utils';
/* eslint-disable max-len */ /* eslint-disable max-len */
// MergeRequestTabs // MergeRequestTabs
...@@ -114,7 +119,7 @@ import bp from './breakpoints'; ...@@ -114,7 +119,7 @@ import bp from './breakpoints';
} }
clickTab(e) { clickTab(e) {
if (e.currentTarget && gl.utils.isMetaClick(e)) { if (e.currentTarget && isMetaClick(e)) {
const targetLink = e.currentTarget.getAttribute('href'); const targetLink = e.currentTarget.getAttribute('href');
e.stopImmediatePropagation(); e.stopImmediatePropagation();
e.preventDefault(); e.preventDefault();
...@@ -260,7 +265,7 @@ import bp from './breakpoints'; ...@@ -260,7 +265,7 @@ import bp from './breakpoints';
// We extract pathname for the current Changes tab anchor href // We extract pathname for the current Changes tab anchor href
// some pages like MergeRequestsController#new has query parameters on that anchor // some pages like MergeRequestsController#new has query parameters on that anchor
const urlPathname = gl.utils.parseUrlPathname(source); const urlPathname = parseUrlPathname(source);
this.ajaxGet({ this.ajaxGet({
url: `${urlPathname}.json${location.search}`, url: `${urlPathname}.json${location.search}`,
...@@ -309,7 +314,7 @@ import bp from './breakpoints'; ...@@ -309,7 +314,7 @@ import bp from './breakpoints';
forceShow: true, forceShow: true,
}); });
anchor[0].scrollIntoView(); anchor[0].scrollIntoView();
window.gl.utils.handleLocationHash(); handleLocationHash();
// We have multiple elements on the page with `#note_xxx` // We have multiple elements on the page with `#note_xxx`
// (discussion and diff tabs) and `:target` only applies to the first // (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target'); anchor.addClass('target');
......
/* global Flash */ /* global Flash */
import AUTH_METHOD from './constants'; import AUTH_METHOD from './constants';
import { backOff } from '../lib/utils/common_utils';
export default class MirrorPull { export default class MirrorPull {
constructor(formSelector) { constructor(formSelector) {
...@@ -65,7 +66,7 @@ export default class MirrorPull { ...@@ -65,7 +66,7 @@ export default class MirrorPull {
$btnLoadSpinner.removeClass('hidden'); $btnLoadSpinner.removeClass('hidden');
// Make backOff polling to get data // Make backOff polling to get data
gl.utils.backOff((next, stop) => { backOff((next, stop) => {
$.getJSON(`${projectMirrorSSHEndpoint}?ssh_url=${repositoryUrl}`) $.getJSON(`${projectMirrorSSHEndpoint}?ssh_url=${repositoryUrl}`)
.done((res, statusText, header) => { .done((res, statusText, header) => {
if (header.status === 204) { if (header.status === 204) {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import EmptyState from './empty_state.vue'; import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store'; import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
export default { export default {
...@@ -17,7 +18,7 @@ ...@@ -17,7 +18,7 @@
return { return {
store, store,
state: 'gettingStarted', state: 'gettingStarted',
hasMetrics: gl.utils.convertPermissionToBoolean(metricsData.hasMetrics), hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics),
documentationPath: metricsData.documentationPath, documentationPath: metricsData.documentationPath,
settingsPath: metricsData.settingsPath, settingsPath: metricsData.settingsPath,
metricsEndpoint: metricsData.additionalMetrics, metricsEndpoint: metricsData.additionalMetrics,
......
import Vue from 'vue'; import Vue from 'vue';
import VueResource from 'vue-resource'; import VueResource from 'vue-resource';
import statusCodes from '../../lib/utils/http_status'; import statusCodes from '../../lib/utils/http_status';
import { backOff } from '../../lib/utils/common_utils';
Vue.use(VueResource); Vue.use(VueResource);
...@@ -8,7 +9,7 @@ const MAX_REQUESTS = 3; ...@@ -8,7 +9,7 @@ const MAX_REQUESTS = 3;
function backOffRequest(makeRequestCallback) { function backOffRequest(makeRequestCallback) {
let requestCounter = 0; let requestCounter = 0;
return gl.utils.backOff((next, stop) => { return backOff((next, stop) => {
makeRequestCallback().then((resp) => { makeRequestCallback().then((resp) => {
if (resp.status === statusCodes.NO_CONTENT) { if (resp.status === statusCodes.NO_CONTENT) {
requestCounter += 1; requestCounter += 1;
......
...@@ -23,6 +23,7 @@ import loadAwardsHandler from './awards_handler'; ...@@ -23,6 +23,7 @@ import loadAwardsHandler from './awards_handler';
import './autosave'; import './autosave';
import './dropzone_input'; import './dropzone_input';
import TaskList from './task_list'; import TaskList from './task_list';
import { ajaxPost, isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils';
window.autosize = autosize; window.autosize = autosize;
window.Dropzone = Dropzone; window.Dropzone = Dropzone;
...@@ -81,7 +82,7 @@ export default class Notes { ...@@ -81,7 +82,7 @@ export default class Notes {
this.setViewType(view); this.setViewType(view);
// We are in the Merge Requests page so we need another edit form for Changes tab // We are in the Merge Requests page so we need another edit form for Changes tab
if (gl.utils.getPagePath(1) === 'merge_requests') { if (getPagePath(1) === 'merge_requests') {
$('.note-edit-form').clone() $('.note-edit-form').clone()
.addClass('mr-note-edit-form').insertAfter('.note-edit-form'); .addClass('mr-note-edit-form').insertAfter('.note-edit-form');
} }
...@@ -175,7 +176,7 @@ export default class Notes { ...@@ -175,7 +176,7 @@ export default class Notes {
keydownNoteText(e) { keydownNoteText(e) {
var $textarea, discussionNoteForm, editNote, myLastNote, myLastNoteEditBtn, newText, originalText; var $textarea, discussionNoteForm, editNote, myLastNote, myLastNoteEditBtn, newText, originalText;
if (gl.utils.isMetaKey(e)) { if (isMetaKey(e)) {
return; return;
} }
...@@ -644,10 +645,10 @@ export default class Notes { ...@@ -644,10 +645,10 @@ export default class Notes {
} }
else { else {
var $buttons = $el.find('.note-form-actions'); var $buttons = $el.find('.note-form-actions');
var isWidgetVisible = gl.utils.isInViewport($el.get(0)); var isWidgetVisible = isInViewport($el.get(0));
if (!isWidgetVisible) { if (!isWidgetVisible) {
gl.utils.scrollToElement($el); scrollToElement($el);
} }
$el.find('.js-finish-edit-warning').show(); $el.find('.js-finish-edit-warning').show();
...@@ -1188,7 +1189,7 @@ export default class Notes { ...@@ -1188,7 +1189,7 @@ export default class Notes {
} }
static checkMergeRequestStatus() { static checkMergeRequestStatus() {
if (gl.utils.getPagePath(1) === 'merge_requests') { if (getPagePath(1) === 'merge_requests') {
gl.mrWidget.checkStatus(); gl.mrWidget.checkStatus();
} }
} }
...@@ -1326,7 +1327,7 @@ export default class Notes { ...@@ -1326,7 +1327,7 @@ export default class Notes {
* 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve * 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve
* 3) Build temporary placeholder element (using `createPlaceholderNote`) * 3) Build temporary placeholder element (using `createPlaceholderNote`)
* 4) Show placeholder note on UI * 4) Show placeholder note on UI
* 5) Perform network request to submit the note using `gl.utils.ajaxPost` * 5) Perform network request to submit the note using `ajaxPost`
* a) If request is successfully completed * a) If request is successfully completed
* 1. Remove placeholder element * 1. Remove placeholder element
* 2. Show submitted Note element * 2. Show submitted Note element
...@@ -1408,7 +1409,7 @@ export default class Notes { ...@@ -1408,7 +1409,7 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */ /* eslint-disable promise/catch-or-return */
// Make request to submit comment on server // Make request to submit comment on server
gl.utils.ajaxPost(formAction, formData) ajaxPost(formAction, formData)
.then((note) => { .then((note) => {
// Submission successful! remove placeholder // Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
...@@ -1481,7 +1482,7 @@ export default class Notes { ...@@ -1481,7 +1482,7 @@ export default class Notes {
* *
* 1) Get Form metadata * 1) Get Form metadata
* 2) Update note element with new content * 2) Update note element with new content
* 3) Perform network request to submit the updated note using `gl.utils.ajaxPost` * 3) Perform network request to submit the updated note using `ajaxPost`
* a) If request is successfully completed * a) If request is successfully completed
* 1. Show submitted Note element * 1. Show submitted Note element
* b) If request failed * b) If request failed
...@@ -1510,7 +1511,7 @@ export default class Notes { ...@@ -1510,7 +1511,7 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */ /* eslint-disable promise/catch-or-return */
// Make request to update comment on server // Make request to update comment on server
gl.utils.ajaxPost(formAction, formData) ajaxPost(formAction, formData)
.then((note) => { .then((note) => {
// Submission successful! render final note element // Submission successful! render final note element
this.updateNote(note, $editingNote); this.updateNote(note, $editingNote);
......
...@@ -7,6 +7,7 @@ import * as constants from '../constants'; ...@@ -7,6 +7,7 @@ import * as constants from '../constants';
import service from '../services/issue_notes_service'; import service from '../services/issue_notes_service';
import loadAwardsHandler from '../../awards_handler'; import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub'; import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement } from '../../lib/utils/common_utils';
let eTagPoll; let eTagPoll;
...@@ -211,7 +212,7 @@ export const toggleAwardRequest = ({ commit, getters, dispatch }, data) => { ...@@ -211,7 +212,7 @@ export const toggleAwardRequest = ({ commit, getters, dispatch }, data) => {
}; };
export const scrollToNoteIfNeeded = (context, el) => { export const scrollToNoteIfNeeded = (context, el) => {
if (!gl.utils.isInViewport(el[0])) { if (!isInViewport(el[0])) {
gl.utils.scrollToElement(el); scrollToElement(el);
} }
}; };
import '~/lib/utils/common_utils'; import { getParameterByName } from '~/lib/utils/common_utils';
import '~/lib/utils/url_utility'; import '~/lib/utils/url_utility';
(() => { (() => {
...@@ -9,7 +9,7 @@ import '~/lib/utils/url_utility'; ...@@ -9,7 +9,7 @@ import '~/lib/utils/url_utility';
init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) { init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) {
this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']); this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']);
this.limit = limit; this.limit = limit;
this.offset = parseInt(gl.utils.getParameterByName('offset'), 10) || this.limit; this.offset = parseInt(getParameterByName('offset'), 10) || this.limit;
this.disable = disable; this.disable = disable;
this.prepareData = prepareData; this.prepareData = prepareData;
this.callback = callback; this.callback = callback;
......
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
function insertRow($row) { function insertRow($row) {
const $rowClone = $row.clone(); const $rowClone = $row.clone();
$rowClone.removeAttr('data-is-persisted'); $rowClone.removeAttr('data-is-persisted');
...@@ -6,7 +8,7 @@ function insertRow($row) { ...@@ -6,7 +8,7 @@ function insertRow($row) {
} }
function removeRow($row) { function removeRow($row) {
const isPersisted = gl.utils.convertPermissionToBoolean($row.attr('data-is-persisted')); const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
if (isPersisted) { if (isPersisted) {
$row.hide(); $row.hide();
......
import LinkedTabs from './lib/utils/bootstrap_linked_tabs'; import LinkedTabs from './lib/utils/bootstrap_linked_tabs';
import { setCiStatusFavicon } from './lib/utils/common_utils';
export default class Pipelines { export default class Pipelines {
constructor(options = {}) { constructor(options = {}) {
...@@ -8,7 +9,7 @@ export default class Pipelines { ...@@ -8,7 +9,7 @@ export default class Pipelines {
} }
if (options.pipelineStatusUrl) { if (options.pipelineStatusUrl) {
gl.utils.setCiStatusFavicon(options.pipelineStatusUrl); setCiStatusFavicon(options.pipelineStatusUrl);
} }
} }
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import tablePagination from '../../vue_shared/components/table_pagination.vue'; import tablePagination from '../../vue_shared/components/table_pagination.vue';
import navigationTabs from './navigation_tabs.vue'; import navigationTabs from './navigation_tabs.vue';
import navigationControls from './nav_controls.vue'; import navigationControls from './nav_controls.vue';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default { export default {
props: { props: {
...@@ -44,10 +45,10 @@ ...@@ -44,10 +45,10 @@
}, },
computed: { computed: {
canCreatePipelineParsed() { canCreatePipelineParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreatePipeline); return convertPermissionToBoolean(this.canCreatePipeline);
}, },
scope() { scope() {
const scope = gl.utils.getParameterByName('scope'); const scope = getParameterByName('scope');
return scope === null ? 'all' : scope; return scope === null ? 'all' : scope;
}, },
...@@ -105,10 +106,10 @@ ...@@ -105,10 +106,10 @@
}; };
}, },
pageParameter() { pageParameter() {
return gl.utils.getParameterByName('page') || this.pagenum; return getParameterByName('page') || this.pagenum;
}, },
scopeParameter() { scopeParameter() {
return gl.utils.getParameterByName('scope') || this.apiScope; return getParameterByName('scope') || this.apiScope;
}, },
}, },
created() { created() {
...@@ -122,7 +123,7 @@ ...@@ -122,7 +123,7 @@
* @param {Number} pageNumber desired page to go to. * @param {Number} pageNumber desired page to go to.
*/ */
change(pageNumber) { change(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber); const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param); gl.utils.visitUrl(param);
return param; return param;
......
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default class PipelinesStore { export default class PipelinesStore {
constructor() { constructor() {
this.state = {}; this.state = {};
...@@ -19,8 +21,8 @@ export default class PipelinesStore { ...@@ -19,8 +21,8 @@ export default class PipelinesStore {
let paginationInfo; let paginationInfo;
if (Object.keys(pagination).length) { if (Object.keys(pagination).length) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination); const normalizedHeaders = normalizeHeaders(pagination);
paginationInfo = gl.utils.parseIntPagination(normalizedHeaders); paginationInfo = parseIntPagination(normalizedHeaders);
} else { } else {
paginationInfo = pagination; paginationInfo = pagination;
} }
......
/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */ /* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */
/* global Flash */ /* global Flash */
import { getPagePath } from '../lib/utils/common_utils';
((global) => { ((global) => {
class Profile { class Profile {
...@@ -93,7 +94,7 @@ ...@@ -93,7 +94,7 @@
return $title.val(comment[1]).change(); return $title.val(comment[1]).change();
} }
}); });
if (global.utils.getPagePath() === 'profiles') { if (getPagePath() === 'profiles') {
return new Profile(); return new Profile();
} }
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import serviceDeskRoot from './components/service_desk_root.vue'; import serviceDeskRoot from './components/service_desk_root.vue';
import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const serviceDeskRootElement = document.querySelector('.js-service-desk-setting-root'); const serviceDeskRootElement = document.querySelector('.js-service-desk-setting-root');
...@@ -10,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -10,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => {
data() { data() {
const dataset = serviceDeskRootElement.dataset; const dataset = serviceDeskRootElement.dataset;
return { return {
initialIsEnabled: gl.utils.convertPermissionToBoolean( initialIsEnabled: convertPermissionToBoolean(
dataset.enabled, dataset.enabled,
), ),
endpoint: dataset.endpoint, endpoint: dataset.endpoint,
......
import PANEL_STATE from './constants'; import PANEL_STATE from './constants';
import { backOff } from '../lib/utils/common_utils';
export default class PrometheusMetrics { export default class PrometheusMetrics {
constructor(wrapperSelector) { constructor(wrapperSelector) {
...@@ -79,7 +80,7 @@ export default class PrometheusMetrics { ...@@ -79,7 +80,7 @@ export default class PrometheusMetrics {
loadActiveMetrics() { loadActiveMetrics() {
this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING); this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
gl.utils.backOff((next, stop) => { backOff((next, stop) => {
$.getJSON(this.activeMetricsEndpoint) $.getJSON(this.activeMetricsEndpoint)
.done((res) => { .done((res) => {
if (res && res.success) { if (res && res.success) {
......
/* eslint-disable comma-dangle, no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-unused-expressions, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */ /* eslint-disable comma-dangle, no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-unused-expressions, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */
import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from './lib/utils/common_utils';
((global) => { ((global) => {
const KEYCODE = { const KEYCODE = {
...@@ -146,14 +147,14 @@ ...@@ -146,14 +147,14 @@
} }
getCategoryContents() { getCategoryContents() {
var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName, utils; var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName;
userId = gon.current_user_id; userId = gon.current_user_id;
userName = gon.current_username; userName = gon.current_username;
utils = gl.utils, projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions; projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions;
if (utils.isInGroupsPage() && groupOptions) { if (isInGroupsPage() && groupOptions) {
options = groupOptions[utils.getGroupSlug()]; options = groupOptions[getGroupSlug()];
} else if (utils.isInProjectPage() && projectOptions) { } else if (isInProjectPage() && projectOptions) {
options = projectOptions[utils.getProjectSlug()]; options = projectOptions[getProjectSlug()];
} else if (dashboardOptions) { } else if (dashboardOptions) {
options = dashboardOptions; options = dashboardOptions;
} }
......
/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */ /* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
import UsersSelect from './users_select'; import UsersSelect from './users_select';
import { isMetaClick } from './lib/utils/common_utils';
export default class Todos { export default class Todos {
constructor() { constructor() {
...@@ -137,22 +138,17 @@ export default class Todos { ...@@ -137,22 +138,17 @@ export default class Todos {
goToTodoUrl(e) { goToTodoUrl(e) {
const todoLink = this.dataset.url; const todoLink = this.dataset.url;
if (!todoLink) { if (!todoLink || e.target.tagName === 'A' || e.target.tagName === 'IMG') {
return; return;
} }
if (gl.utils.isMetaClick(e)) {
const windowTarget = '_blank';
const selected = e.target;
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
if (selected.tagName === 'IMG') { if (isMetaClick(e)) {
const avatarUrl = selected.parentElement.getAttribute('href'); const windowTarget = '_blank';
window.open(avatarUrl, windowTarget);
} else {
window.open(todoLink, windowTarget); window.open(todoLink, windowTarget);
}
} else { } else {
gl.utils.visitUrl(todoLink); gl.utils.visitUrl(todoLink);
} }
......
import statusCodes from '../../lib/utils/http_status'; import statusCodes from '../../lib/utils/http_status';
import { bytesToMiB } from '../../lib/utils/number_utils'; import { bytesToMiB } from '../../lib/utils/number_utils';
import { backOff } from '../../lib/utils/common_utils';
import MemoryGraph from '../../vue_shared/components/memory_graph'; import MemoryGraph from '../../vue_shared/components/memory_graph';
import MRWidgetService from '../services/mr_widget_service'; import MRWidgetService from '../services/mr_widget_service';
...@@ -84,7 +84,7 @@ export default { ...@@ -84,7 +84,7 @@ export default {
} }
}, },
loadMetrics() { loadMetrics() {
gl.utils.backOff((next, stop) => { backOff((next, stop) => {
MRWidgetService.fetchMetrics(this.metricsUrl) MRWidgetService.fetchMetrics(this.metricsUrl)
.then((res) => { .then((res) => {
if (res.status === statusCodes.NO_CONTENT) { if (res.status === statusCodes.NO_CONTENT) {
......
...@@ -31,6 +31,7 @@ import { ...@@ -31,6 +31,7 @@ import {
SquashBeforeMerge, SquashBeforeMerge,
notify, notify,
} from './dependencies'; } from './dependencies';
import { setFavicon } from '../lib/utils/common_utils';
export default { export default {
el: '#js-vue-mr-widget', el: '#js-vue-mr-widget',
...@@ -88,7 +89,7 @@ export default { ...@@ -88,7 +89,7 @@ export default {
.then((res) => { .then((res) => {
this.handleNotification(res); this.handleNotification(res);
this.mr.setData(res); this.mr.setData(res);
this.setFavicon(); this.setFaviconHelper();
if (cb) { if (cb) {
cb.call(null, res); cb.call(null, res);
...@@ -115,9 +116,9 @@ export default { ...@@ -115,9 +116,9 @@ export default {
immediateExecution: true, immediateExecution: true,
}); });
}, },
setFavicon() { setFaviconHelper() {
if (this.mr.ciStatusFaviconPath) { if (this.mr.ciStatusFaviconPath) {
gl.utils.setFavicon(this.mr.ciStatusFaviconPath); setFavicon(this.mr.ciStatusFaviconPath);
} }
}, },
fetchDeployments() { fetchDeployments() {
...@@ -191,7 +192,7 @@ export default { ...@@ -191,7 +192,7 @@ export default {
}); });
}, },
handleMounted() { handleMounted() {
this.setFavicon(); this.setFaviconHelper();
this.initDeploymentsPolling(); this.initDeploymentsPolling();
}, },
}, },
......
---
title: Exports common_utils utility functions as modules
merge_request:
author:
type: other
...@@ -14,6 +14,10 @@ describe('Environments Folder View', () => { ...@@ -14,6 +14,10 @@ describe('Environments Folder View', () => {
window.history.pushState({}, null, 'environments/folders/build'); window.history.pushState({}, null, 'environments/folders/build');
}); });
afterEach(() => {
window.history.pushState({}, null, '/');
});
let component; let component;
describe('successfull request', () => { describe('successfull request', () => {
......
/* eslint-disable promise/catch-or-return */ /* eslint-disable promise/catch-or-return */
import '~/lib/utils/common_utils'; import * as commonUtils from '~/lib/utils/common_utils';
(() => { describe('common_utils', () => {
describe('common_utils', () => { describe('parseUrl', () => {
describe('gl.utils.parseUrl', () => {
it('returns an anchor tag with url', () => { it('returns an anchor tag with url', () => {
expect(gl.utils.parseUrl('/some/absolute/url').pathname).toContain('some/absolute/url'); expect(commonUtils.parseUrl('/some/absolute/url').pathname).toContain('some/absolute/url');
}); });
it('url is escaped', () => { it('url is escaped', () => {
// IE11 will return a relative pathname while other browsers will return a full pathname. // IE11 will return a relative pathname while other browsers will return a full pathname.
...@@ -14,31 +13,27 @@ import '~/lib/utils/common_utils'; ...@@ -14,31 +13,27 @@ import '~/lib/utils/common_utils';
// element will create an absolute url relative to the current execution context. // element will create an absolute url relative to the current execution context.
// The JavaScript test suite is executed at '/' which will lead to an absolute url // The JavaScript test suite is executed at '/' which will lead to an absolute url
// starting with '/'. // starting with '/'.
expect(gl.utils.parseUrl('" test="asf"').pathname).toContain('/%22%20test=%22asf%22'); expect(commonUtils.parseUrl('" test="asf"').pathname).toContain('/%22%20test=%22asf%22');
}); });
}); });
describe('gl.utils.parseUrlPathname', () => { describe('parseUrlPathname', () => {
beforeEach(() => {
spyOn(gl.utils, 'parseUrl').and.callFake(url => ({
pathname: url,
}));
});
it('returns an absolute url when given an absolute url', () => { it('returns an absolute url when given an absolute url', () => {
expect(gl.utils.parseUrlPathname('/some/absolute/url')).toEqual('/some/absolute/url'); expect(commonUtils.parseUrlPathname('/some/absolute/url')).toEqual('/some/absolute/url');
}); });
it('returns an absolute url when given a relative url', () => { it('returns an absolute url when given a relative url', () => {
expect(gl.utils.parseUrlPathname('some/relative/url')).toEqual('/some/relative/url'); expect(commonUtils.parseUrlPathname('some/relative/url')).toEqual('/some/relative/url');
}); });
}); });
describe('gl.utils.getUrlParamsArray', () => { describe('getUrlParamsArray', () => {
it('should return params array', () => { it('should return params array', () => {
expect(gl.utils.getUrlParamsArray() instanceof Array).toBe(true); expect(commonUtils.getUrlParamsArray() instanceof Array).toBe(true);
}); });
it('should remove the question mark from the search params', () => { it('should remove the question mark from the search params', () => {
const paramsArray = gl.utils.getUrlParamsArray(); const paramsArray = commonUtils.getUrlParamsArray();
expect(paramsArray[0][0] !== '?').toBe(true); expect(paramsArray[0][0] !== '?').toBe(true);
}); });
...@@ -46,14 +41,14 @@ import '~/lib/utils/common_utils'; ...@@ -46,14 +41,14 @@ import '~/lib/utils/common_utils';
history.pushState('', '', '?label_name%5B%5D=test'); history.pushState('', '', '?label_name%5B%5D=test');
expect( expect(
gl.utils.getUrlParamsArray()[0], commonUtils.getUrlParamsArray()[0],
).toBe('label_name[]=test'); ).toBe('label_name[]=test');
history.pushState('', '', '?'); history.pushState('', '', '?');
}); });
}); });
describe('gl.utils.handleLocationHash', () => { describe('handleLocationHash', () => {
beforeEach(() => { beforeEach(() => {
spyOn(window.document, 'getElementById').and.callThrough(); spyOn(window.document, 'getElementById').and.callThrough();
}); });
...@@ -68,7 +63,7 @@ import '~/lib/utils/common_utils'; ...@@ -68,7 +63,7 @@ import '~/lib/utils/common_utils';
it('decodes hash parameter', () => { it('decodes hash parameter', () => {
window.history.pushState({}, null, '#random-hash'); window.history.pushState({}, null, '#random-hash');
gl.utils.handleLocationHash(); commonUtils.handleLocationHash();
expectGetElementIdToHaveBeenCalledWith('random-hash'); expectGetElementIdToHaveBeenCalledWith('random-hash');
expectGetElementIdToHaveBeenCalledWith('user-content-random-hash'); expectGetElementIdToHaveBeenCalledWith('user-content-random-hash');
...@@ -76,7 +71,7 @@ import '~/lib/utils/common_utils'; ...@@ -76,7 +71,7 @@ import '~/lib/utils/common_utils';
it('decodes cyrillic hash parameter', () => { it('decodes cyrillic hash parameter', () => {
window.history.pushState({}, null, '#definição'); window.history.pushState({}, null, '#definição');
gl.utils.handleLocationHash(); commonUtils.handleLocationHash();
expectGetElementIdToHaveBeenCalledWith('definição'); expectGetElementIdToHaveBeenCalledWith('definição');
expectGetElementIdToHaveBeenCalledWith('user-content-definição'); expectGetElementIdToHaveBeenCalledWith('user-content-definição');
...@@ -84,14 +79,14 @@ import '~/lib/utils/common_utils'; ...@@ -84,14 +79,14 @@ import '~/lib/utils/common_utils';
it('decodes encoded cyrillic hash parameter', () => { it('decodes encoded cyrillic hash parameter', () => {
window.history.pushState({}, null, '#defini%C3%A7%C3%A3o'); window.history.pushState({}, null, '#defini%C3%A7%C3%A3o');
gl.utils.handleLocationHash(); commonUtils.handleLocationHash();
expectGetElementIdToHaveBeenCalledWith('definição'); expectGetElementIdToHaveBeenCalledWith('definição');
expectGetElementIdToHaveBeenCalledWith('user-content-definição'); expectGetElementIdToHaveBeenCalledWith('user-content-definição');
}); });
}); });
describe('gl.utils.setParamInURL', () => { describe('setParamInURL', () => {
afterEach(() => { afterEach(() => {
window.history.pushState({}, null, ''); window.history.pushState({}, null, '');
}); });
...@@ -99,40 +94,40 @@ import '~/lib/utils/common_utils'; ...@@ -99,40 +94,40 @@ import '~/lib/utils/common_utils';
it('should return the parameter', () => { it('should return the parameter', () => {
window.history.replaceState({}, null, ''); window.history.replaceState({}, null, '');
expect(gl.utils.setParamInURL('page', 156)).toBe('?page=156'); expect(commonUtils.setParamInURL('page', 156)).toBe('?page=156');
expect(gl.utils.setParamInURL('page', '156')).toBe('?page=156'); expect(commonUtils.setParamInURL('page', '156')).toBe('?page=156');
}); });
it('should update the existing parameter when its a number', () => { it('should update the existing parameter when its a number', () => {
window.history.pushState({}, null, '?page=15'); window.history.pushState({}, null, '?page=15');
expect(gl.utils.setParamInURL('page', 16)).toBe('?page=16'); expect(commonUtils.setParamInURL('page', 16)).toBe('?page=16');
expect(gl.utils.setParamInURL('page', '16')).toBe('?page=16'); expect(commonUtils.setParamInURL('page', '16')).toBe('?page=16');
expect(gl.utils.setParamInURL('page', true)).toBe('?page=true'); expect(commonUtils.setParamInURL('page', true)).toBe('?page=true');
}); });
it('should update the existing parameter when its a string', () => { it('should update the existing parameter when its a string', () => {
window.history.pushState({}, null, '?scope=all'); window.history.pushState({}, null, '?scope=all');
expect(gl.utils.setParamInURL('scope', 'finished')).toBe('?scope=finished'); expect(commonUtils.setParamInURL('scope', 'finished')).toBe('?scope=finished');
}); });
it('should update the existing parameter when more than one parameter exists', () => { it('should update the existing parameter when more than one parameter exists', () => {
window.history.pushState({}, null, '?scope=all&page=15'); window.history.pushState({}, null, '?scope=all&page=15');
expect(gl.utils.setParamInURL('scope', 'finished')).toBe('?scope=finished&page=15'); expect(commonUtils.setParamInURL('scope', 'finished')).toBe('?scope=finished&page=15');
}); });
it('should add a new parameter to the end of the existing ones', () => { it('should add a new parameter to the end of the existing ones', () => {
window.history.pushState({}, null, '?scope=all'); window.history.pushState({}, null, '?scope=all');
expect(gl.utils.setParamInURL('page', 16)).toBe('?scope=all&page=16'); expect(commonUtils.setParamInURL('page', 16)).toBe('?scope=all&page=16');
expect(gl.utils.setParamInURL('page', '16')).toBe('?scope=all&page=16'); expect(commonUtils.setParamInURL('page', '16')).toBe('?scope=all&page=16');
expect(gl.utils.setParamInURL('page', true)).toBe('?scope=all&page=true'); expect(commonUtils.setParamInURL('page', true)).toBe('?scope=all&page=true');
}); });
}); });
describe('gl.utils.getParameterByName', () => { describe('getParameterByName', () => {
beforeEach(() => { beforeEach(() => {
window.history.pushState({}, null, '?scope=all&p=2'); window.history.pushState({}, null, '?scope=all&p=2');
}); });
...@@ -142,33 +137,33 @@ import '~/lib/utils/common_utils'; ...@@ -142,33 +137,33 @@ import '~/lib/utils/common_utils';
}); });
it('should return valid parameter', () => { it('should return valid parameter', () => {
const value = gl.utils.getParameterByName('scope'); const value = commonUtils.getParameterByName('scope');
expect(gl.utils.getParameterByName('p')).toEqual('2'); expect(commonUtils.getParameterByName('p')).toEqual('2');
expect(value).toBe('all'); expect(value).toBe('all');
}); });
it('should return invalid parameter', () => { it('should return invalid parameter', () => {
const value = gl.utils.getParameterByName('fakeParameter'); const value = commonUtils.getParameterByName('fakeParameter');
expect(value).toBe(null); expect(value).toBe(null);
}); });
it('should return valid paramentes if URL is provided', () => { it('should return valid paramentes if URL is provided', () => {
let value = gl.utils.getParameterByName('foo', 'http://cocteau.twins/?foo=bar'); let value = commonUtils.getParameterByName('foo', 'http://cocteau.twins/?foo=bar');
expect(value).toBe('bar'); expect(value).toBe('bar');
value = gl.utils.getParameterByName('manan', 'http://cocteau.twins/?foo=bar&manan=canchu'); value = commonUtils.getParameterByName('manan', 'http://cocteau.twins/?foo=bar&manan=canchu');
expect(value).toBe('canchu'); expect(value).toBe('canchu');
}); });
}); });
describe('gl.utils.normalizedHeaders', () => { describe('normalizedHeaders', () => {
it('should upperCase all the header keys to keep them consistent', () => { it('should upperCase all the header keys to keep them consistent', () => {
const apiHeaders = { const apiHeaders = {
'X-Something-Workhorse': { workhorse: 'ok' }, 'X-Something-Workhorse': { workhorse: 'ok' },
'x-something-nginx': { nginx: 'ok' }, 'x-something-nginx': { nginx: 'ok' },
}; };
const normalized = gl.utils.normalizeHeaders(apiHeaders); const normalized = commonUtils.normalizeHeaders(apiHeaders);
const WORKHORSE = 'X-SOMETHING-WORKHORSE'; const WORKHORSE = 'X-SOMETHING-WORKHORSE';
const NGINX = 'X-SOMETHING-NGINX'; const NGINX = 'X-SOMETHING-NGINX';
...@@ -178,14 +173,11 @@ import '~/lib/utils/common_utils'; ...@@ -178,14 +173,11 @@ import '~/lib/utils/common_utils';
}); });
}); });
describe('gl.utils.normalizeCRLFHeaders', () => { describe('normalizeCRLFHeaders', () => {
beforeEach(function () { beforeEach(function () {
this.CLRFHeaders = 'a-header: a-value\nAnother-Header: ANOTHER-VALUE\nLaSt-HeAdEr: last-VALUE'; this.CLRFHeaders = 'a-header: a-value\nAnother-Header: ANOTHER-VALUE\nLaSt-HeAdEr: last-VALUE';
spyOn(String.prototype, 'split').and.callThrough(); spyOn(String.prototype, 'split').and.callThrough();
spyOn(gl.utils, 'normalizeHeaders').and.callThrough(); this.normalizeCRLFHeaders = commonUtils.normalizeCRLFHeaders(this.CLRFHeaders);
this.normalizeCRLFHeaders = gl.utils.normalizeCRLFHeaders(this.CLRFHeaders);
}); });
it('should split by newline', function () { it('should split by newline', function () {
...@@ -196,10 +188,6 @@ import '~/lib/utils/common_utils'; ...@@ -196,10 +188,6 @@ import '~/lib/utils/common_utils';
expect(String.prototype.split.calls.allArgs().filter(args => args[0] === ': ').length).toBe(3); expect(String.prototype.split.calls.allArgs().filter(args => args[0] === ': ').length).toBe(3);
}); });
it('should call gl.utils.normalizeHeaders with a parsed headers object', function () {
expect(gl.utils.normalizeHeaders).toHaveBeenCalledWith(jasmine.any(Object));
});
it('should return a normalized headers object', function () { it('should return a normalized headers object', function () {
expect(this.normalizeCRLFHeaders).toEqual({ expect(this.normalizeCRLFHeaders).toEqual({
'A-HEADER': 'a-value', 'A-HEADER': 'a-value',
...@@ -209,7 +197,7 @@ import '~/lib/utils/common_utils'; ...@@ -209,7 +197,7 @@ import '~/lib/utils/common_utils';
}); });
}); });
describe('gl.utils.parseIntPagination', () => { describe('parseIntPagination', () => {
it('should parse to integers all string values and return pagination object', () => { it('should parse to integers all string values and return pagination object', () => {
const pagination = { const pagination = {
'X-PER-PAGE': 10, 'X-PER-PAGE': 10,
...@@ -229,11 +217,11 @@ import '~/lib/utils/common_utils'; ...@@ -229,11 +217,11 @@ import '~/lib/utils/common_utils';
previousPage: 1, previousPage: 1,
}; };
expect(gl.utils.parseIntPagination(pagination)).toEqual(expectedPagination); expect(commonUtils.parseIntPagination(pagination)).toEqual(expectedPagination);
}); });
}); });
describe('gl.utils.isMetaClick', () => { describe('isMetaClick', () => {
it('should identify meta click on Windows/Linux', () => { it('should identify meta click on Windows/Linux', () => {
const e = { const e = {
metaKey: false, metaKey: false,
...@@ -241,7 +229,7 @@ import '~/lib/utils/common_utils'; ...@@ -241,7 +229,7 @@ import '~/lib/utils/common_utils';
which: 1, which: 1,
}; };
expect(gl.utils.isMetaClick(e)).toBe(true); expect(commonUtils.isMetaClick(e)).toBe(true);
}); });
it('should identify meta click on macOS', () => { it('should identify meta click on macOS', () => {
...@@ -251,7 +239,7 @@ import '~/lib/utils/common_utils'; ...@@ -251,7 +239,7 @@ import '~/lib/utils/common_utils';
which: 1, which: 1,
}; };
expect(gl.utils.isMetaClick(e)).toBe(true); expect(commonUtils.isMetaClick(e)).toBe(true);
}); });
it('should identify as meta click on middle-click or Mouse-wheel click', () => { it('should identify as meta click on middle-click or Mouse-wheel click', () => {
...@@ -261,11 +249,18 @@ import '~/lib/utils/common_utils'; ...@@ -261,11 +249,18 @@ import '~/lib/utils/common_utils';
which: 2, which: 2,
}; };
expect(gl.utils.isMetaClick(e)).toBe(true); expect(commonUtils.isMetaClick(e)).toBe(true);
});
});
describe('convertPermissionToBoolean', () => {
it('should convert a boolean in a string to a boolean', () => {
expect(commonUtils.convertPermissionToBoolean('true')).toEqual(true);
expect(commonUtils.convertPermissionToBoolean('false')).toEqual(false);
}); });
}); });
describe('gl.utils.backOff', () => { describe('backOff', () => {
beforeEach(() => { beforeEach(() => {
// shortcut our timeouts otherwise these tests will take a long time to finish // shortcut our timeouts otherwise these tests will take a long time to finish
const origSetTimeout = window.setTimeout; const origSetTimeout = window.setTimeout;
...@@ -274,7 +269,7 @@ import '~/lib/utils/common_utils'; ...@@ -274,7 +269,7 @@ import '~/lib/utils/common_utils';
it('solves the promise from the callback', (done) => { it('solves the promise from the callback', (done) => {
const expectedResponseValue = 'Success!'; const expectedResponseValue = 'Success!';
gl.utils.backOff((next, stop) => ( commonUtils.backOff((next, stop) => (
new Promise((resolve) => { new Promise((resolve) => {
resolve(expectedResponseValue); resolve(expectedResponseValue);
}).then((resp) => { }).then((resp) => {
...@@ -288,7 +283,7 @@ import '~/lib/utils/common_utils'; ...@@ -288,7 +283,7 @@ import '~/lib/utils/common_utils';
it('catches the rejected promise from the callback ', (done) => { it('catches the rejected promise from the callback ', (done) => {
const errorMessage = 'Mistakes were made!'; const errorMessage = 'Mistakes were made!';
gl.utils.backOff((next, stop) => { commonUtils.backOff((next, stop) => {
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
reject(new Error(errorMessage)); reject(new Error(errorMessage));
}).then((resp) => { }).then((resp) => {
...@@ -304,7 +299,7 @@ import '~/lib/utils/common_utils'; ...@@ -304,7 +299,7 @@ import '~/lib/utils/common_utils';
it('solves the promise correctly after retrying a third time', (done) => { it('solves the promise correctly after retrying a third time', (done) => {
let numberOfCalls = 1; let numberOfCalls = 1;
const expectedResponseValue = 'Success!'; const expectedResponseValue = 'Success!';
gl.utils.backOff((next, stop) => ( commonUtils.backOff((next, stop) => (
Promise.resolve(expectedResponseValue) Promise.resolve(expectedResponseValue)
.then((resp) => { .then((resp) => {
if (numberOfCalls < 3) { if (numberOfCalls < 3) {
...@@ -323,7 +318,7 @@ import '~/lib/utils/common_utils'; ...@@ -323,7 +318,7 @@ import '~/lib/utils/common_utils';
}); });
it('rejects the backOff promise after timing out', (done) => { it('rejects the backOff promise after timing out', (done) => {
gl.utils.backOff(next => next(), 64000) commonUtils.backOff(next => next(), 64000)
.catch((errBackoffResp) => { .catch((errBackoffResp) => {
const timeouts = window.setTimeout.calls.allArgs().map(([, timeout]) => timeout); const timeouts = window.setTimeout.calls.allArgs().map(([, timeout]) => timeout);
expect(timeouts).toEqual([2000, 4000, 8000, 16000, 32000, 32000]); expect(timeouts).toEqual([2000, 4000, 8000, 16000, 32000, 32000]);
...@@ -334,65 +329,87 @@ import '~/lib/utils/common_utils'; ...@@ -334,65 +329,87 @@ import '~/lib/utils/common_utils';
}); });
}); });
describe('gl.utils.setFavicon', () => { describe('setFavicon', () => {
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
favicon.setAttribute('href', 'default/favicon');
document.body.appendChild(favicon);
});
afterEach(() => {
document.body.removeChild(document.getElementById('favicon'));
});
it('should set page favicon to provided favicon', () => { it('should set page favicon to provided favicon', () => {
const faviconPath = '//custom_favicon'; const faviconPath = '//custom_favicon';
const fakeLink = { commonUtils.setFavicon(faviconPath);
setAttribute() {},
};
spyOn(window.document, 'getElementById').and.callFake(() => fakeLink); expect(document.getElementById('favicon').getAttribute('href')).toEqual(faviconPath);
spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => { });
expect(attr).toEqual('href');
expect(val.indexOf(faviconPath) > -1).toBe(true);
}); });
gl.utils.setFavicon(faviconPath);
describe('resetFavicon', () => {
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
favicon.setAttribute('href', 'default/favicon');
document.body.appendChild(favicon);
}); });
afterEach(() => {
document.body.removeChild(document.getElementById('favicon'));
}); });
describe('gl.utils.resetFavicon', () => {
it('should reset page favicon to tanuki', () => { it('should reset page favicon to tanuki', () => {
const fakeLink = { commonUtils.resetFavicon();
setAttribute() {}, expect(document.getElementById('favicon').getAttribute('href')).toEqual('default/favicon');
}; });
});
spyOn(window.document, 'getElementById').and.callFake(() => fakeLink); describe('setCiStatusFavicon', () => {
spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`;
expect(attr).toEqual('href');
expect(val).toMatch(/favicon/); beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
document.body.appendChild(favicon);
}); });
gl.utils.resetFavicon();
afterEach(() => {
document.body.removeChild(document.getElementById('favicon'));
}); });
it('should reset favicon in case of error', () => {
const favicon = document.getElementById('favicon');
spyOn($, 'ajax').and.callFake(function (options) {
options.error();
expect(favicon.getAttribute('href')).toEqual('null');
});
commonUtils.setCiStatusFavicon(BUILD_URL);
}); });
describe('gl.utils.setCiStatusFavicon', () => {
it('should set page favicon to CI status favicon based on provided status', () => { it('should set page favicon to CI status favicon based on provided status', () => {
const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`;
const FAVICON_PATH = '//icon_status_success'; const FAVICON_PATH = '//icon_status_success';
const spySetFavicon = spyOn(gl.utils, 'setFavicon').and.stub(); const favicon = document.getElementById('favicon');
const spyResetFavicon = spyOn(gl.utils, 'resetFavicon').and.stub();
spyOn($, 'ajax').and.callFake(function (options) { spyOn($, 'ajax').and.callFake(function (options) {
options.success({ favicon: FAVICON_PATH }); options.success({ favicon: FAVICON_PATH });
expect(spySetFavicon).toHaveBeenCalledWith(FAVICON_PATH); expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH);
options.success();
expect(spyResetFavicon).toHaveBeenCalled();
options.error();
expect(spyResetFavicon).toHaveBeenCalled();
}); });
gl.utils.setCiStatusFavicon(BUILD_URL); commonUtils.setCiStatusFavicon(BUILD_URL);
}); });
}); });
describe('gl.utils.ajaxPost', () => { describe('ajaxPost', () => {
it('should perform `$.ajax` call and do `POST` request', () => { it('should perform `$.ajax` call and do `POST` request', () => {
const requestURL = '/some/random/api'; const requestURL = '/some/random/api';
const data = { keyname: 'value' }; const data = { keyname: 'value' };
const ajaxSpy = spyOn($, 'ajax').and.callFake(() => {}); const ajaxSpy = spyOn($, 'ajax').and.callFake(() => {});
gl.utils.ajaxPost(requestURL, data); commonUtils.ajaxPost(requestURL, data);
expect(ajaxSpy.calls.allArgs()[0][0].type).toEqual('POST'); expect(ajaxSpy.calls.allArgs()[0][0].type).toEqual('POST');
}); });
}); });
}); });
})();
...@@ -78,8 +78,9 @@ import 'vendor/jquery.scrollTo'; ...@@ -78,8 +78,9 @@ import 'vendor/jquery.scrollTo';
}); });
describe('meta click', () => { describe('meta click', () => {
let metakeyEvent;
beforeEach(function () { beforeEach(function () {
spyOn(gl.utils, 'isMetaClick').and.returnValue(true); metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
}); });
it('opens page when commits link is clicked', function () { it('opens page when commits link is clicked', function () {
...@@ -89,7 +90,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -89,7 +90,7 @@ import 'vendor/jquery.scrollTo';
}); });
this.class.bindEvents(); this.class.bindEvents();
document.querySelector('.merge-request-tabs .commits-tab a').click(); $('.merge-request-tabs .commits-tab a').trigger(metakeyEvent);
}); });
it('opens page when commits badge is clicked', function () { it('opens page when commits badge is clicked', function () {
...@@ -99,7 +100,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -99,7 +100,7 @@ import 'vendor/jquery.scrollTo';
}); });
this.class.bindEvents(); this.class.bindEvents();
document.querySelector('.merge-request-tabs .commits-tab a .badge').click(); $('.merge-request-tabs .commits-tab a .badge').trigger(metakeyEvent);
}); });
}); });
......
...@@ -26,37 +26,30 @@ describe('Todos', () => { ...@@ -26,37 +26,30 @@ describe('Todos', () => {
describe('meta click', () => { describe('meta click', () => {
let visitUrlSpy; let visitUrlSpy;
let windowOpenSpy;
let metakeyEvent;
beforeEach(() => { beforeEach(() => {
spyOn(gl.utils, 'isMetaClick').and.returnValue(true); metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
visitUrlSpy = spyOn(gl.utils, 'visitUrl').and.callFake(() => {}); visitUrlSpy = spyOn(gl.utils, 'visitUrl').and.callFake(() => {});
windowOpenSpy = spyOn(window, 'open').and.callFake(() => {});
}); });
it('opens the todo url in another tab', (done) => { it('opens the todo url in another tab', () => {
const todoLink = todoItem.dataset.url; const todoLink = todoItem.dataset.url;
spyOn(window, 'open').and.callFake((url, target) => { $('.todos-list .todo').trigger(metakeyEvent);
expect(todoLink).toEqual(url);
expect(target).toEqual('_blank');
done();
});
todoItem.click();
expect(visitUrlSpy).not.toHaveBeenCalled(); expect(visitUrlSpy).not.toHaveBeenCalled();
expect(windowOpenSpy).toHaveBeenCalledWith(todoLink, '_blank');
}); });
it('opens the avatar\'s url in another tab when the avatar is clicked', (done) => { it('run native funcionality when avatar is clicked', () => {
const avatarImage = todoItem.querySelector('img'); $('.todos-list a').on('click', e => e.preventDefault());
const avatarUrl = avatarImage.parentElement.getAttribute('href'); $('.todos-list img').trigger(metakeyEvent);
spyOn(window, 'open').and.callFake((url, target) => {
expect(avatarUrl).toEqual(url);
expect(target).toEqual('_blank');
done();
});
avatarImage.click();
expect(visitUrlSpy).not.toHaveBeenCalled(); expect(visitUrlSpy).not.toHaveBeenCalled();
expect(windowOpenSpy).not.toHaveBeenCalled();
}); });
}); });
}); });
......
...@@ -224,29 +224,41 @@ describe('mrWidgetOptions', () => { ...@@ -224,29 +224,41 @@ describe('mrWidgetOptions', () => {
describe('handleMounted', () => { describe('handleMounted', () => {
it('should call required methods to do the initial kick-off', () => { it('should call required methods to do the initial kick-off', () => {
spyOn(vm, 'initDeploymentsPolling'); spyOn(vm, 'initDeploymentsPolling');
spyOn(vm, 'setFavicon'); spyOn(vm, 'setFaviconHelper');
vm.handleMounted(); vm.handleMounted();
expect(vm.setFavicon).toHaveBeenCalled(); expect(vm.setFaviconHelper).toHaveBeenCalled();
expect(vm.initDeploymentsPolling).toHaveBeenCalled(); expect(vm.initDeploymentsPolling).toHaveBeenCalled();
}); });
}); });
describe('setFavicon', () => { describe('setFavicon', () => {
let faviconElement;
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
document.body.appendChild(favicon);
faviconElement = document.getElementById('favicon');
});
afterEach(() => {
document.body.removeChild(document.getElementById('favicon'));
});
it('should call setFavicon method', () => { it('should call setFavicon method', () => {
spyOn(gl.utils, 'setFavicon'); vm.setFaviconHelper();
vm.setFavicon();
expect(gl.utils.setFavicon).toHaveBeenCalledWith(vm.mr.ciStatusFaviconPath); expect(faviconElement.getAttribute('href')).toEqual(vm.mr.ciStatusFaviconPath);
}); });
it('should not call setFavicon when there is no ciStatusFaviconPath', () => { it('should not call setFavicon when there is no ciStatusFaviconPath', () => {
spyOn(gl.utils, 'setFavicon');
vm.mr.ciStatusFaviconPath = null; vm.mr.ciStatusFaviconPath = null;
vm.setFavicon(); vm.setFaviconHelper();
expect(gl.utils.setFavicon).not.toHaveBeenCalled(); expect(faviconElement.getAttribute('href')).toEqual(null);
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment