Commit 96e6fc70 authored by Filipa Lacerda's avatar Filipa Lacerda

Import modules instead of using the ones in global namespace

Removes set favicon related methods from global scope
Improves test related with favicon

Removes convertPermissionToBoolean from global scope.
Adds tests for convertPermissionToBoolean - were non existant

Removes setParamInURL from gl.utils

Removes parseIntPagination from gl.utils namespace

Remove normalizeCRLFHeaders from gl.utils namespace

Removes normalizeHeaders from gl.utils namespace

Use gl.utils for filtered search

Fix bad import

Fix broken test by cleaning window.history namespace

Adds changelog
parent 6a1b84c7
/* global Flash */
import { handleLocationHash } from '../../lib/utils/common_utils';
export default class BlobViewer {
constructor() {
BlobViewer.initAuxiliaryViewer();
......@@ -114,7 +116,7 @@ export default class BlobViewer {
$(viewer).renderGFM();
this.$fileHolder.trigger('highlight:line');
gl.utils.handleLocationHash();
handleLocationHash();
this.toggleCopyButtonState();
})
......
......@@ -2,6 +2,7 @@
/* global List */
import _ from 'underscore';
import Cookies from 'js-cookie';
import { getUrlParamsArray } from '../../lib/utils/common_utils';
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
......@@ -21,7 +22,7 @@ gl.issueBoards.BoardsStore = {
},
create () {
this.state.lists = [];
this.filter.path = gl.utils.getUrlParamsArray().join('&');
this.filter.path = getUrlParamsArray().join('&');
this.detail = { issue: {} };
},
addList (listObj, defaultAvatar) {
......
......@@ -3,6 +3,7 @@ consistent-return, prefer-rest-params */
import _ from 'underscore';
import bp from './breakpoints';
import { bytesToKiB } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils';
window.Build = (function () {
Build.timeout = null;
......@@ -169,7 +170,7 @@ window.Build = (function () {
data: this.state,
})
.done((log) => {
gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`);
setCiStatusFavicon(`${this.pageUrl}/status.json`);
if (log.state) {
this.state = log.state;
......
/* 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 './lib/utils/common_utils';
import { insertText, getSelectedFragment, nodeMatchesSelector } from './lib/utils/common_utils';
import { placeholderImage } from './lazy_loader';
const gfmRules = {
......@@ -295,7 +295,7 @@ class CopyAsGFM {
const clipboardData = e.originalEvent.clipboardData;
if (!clipboardData) return;
const documentFragment = window.gl.utils.getSelectedFragment();
const documentFragment = getSelectedFragment();
if (!documentFragment) return;
const el = transformer(documentFragment.cloneNode(true));
......@@ -412,7 +412,7 @@ class CopyAsGFM {
for (const selector in rules) {
const func = rules[selector];
if (!window.gl.utils.nodeMatchesSelector(node, selector)) continue;
if (!nodeMatchesSelector(node, selector)) continue;
let result;
if (func.length === 2) {
......
......@@ -77,7 +77,7 @@ import initProjectVisibilitySelector from './project_visibility';
import GpgBadges from './gpg_badges';
import UserFeatureHelper from './helpers/user_feature_helper';
import initChangesDropdown from './init_changes_dropdown';
import { ajaxGet } from './lib/utils/common_utils';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
(function() {
var Dispatcher;
......@@ -101,7 +101,7 @@ import { ajaxGet } from './lib/utils/common_utils';
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
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), {
emojis: true,
members: enableGFM,
......
......@@ -6,7 +6,7 @@ import environmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.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 Poll from '../../lib/utils/poll';
import environmentsMixin from '../mixins/environments_mixin';
......@@ -51,19 +51,19 @@ export default {
computed: {
scope() {
return gl.utils.getParameterByName('scope');
return getParameterByName('scope');
},
canReadEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
return convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
return convertPermissionToBoolean(this.canCreateDeployment);
},
canCreateEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateEnvironment);
return convertPermissionToBoolean(this.canCreateEnvironment);
},
},
......@@ -72,8 +72,8 @@ export default {
* Toggles loading property.
*/
created() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint);
......@@ -126,15 +126,15 @@ export default {
* @return {String}
*/
changePage(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber);
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
},
fetchEnvironments() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true;
......
......@@ -9,7 +9,7 @@ import tablePagination from '../../vue_shared/components/table_pagination.vue';
import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import '../../lib/utils/common_utils';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default {
components: {
......@@ -47,15 +47,15 @@ export default {
computed: {
scope() {
return gl.utils.getParameterByName('scope');
return getParameterByName('scope');
},
canReadEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
return convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
return convertPermissionToBoolean(this.canCreateDeployment);
},
/**
......@@ -82,8 +82,8 @@ export default {
* Toggles loading property.
*/
created() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint);
......@@ -125,15 +125,15 @@ export default {
* @param {Number} pageNumber desired page to go to.
*/
changePage(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber);
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
},
fetchEnvironments() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true;
......
import '~/lib/utils/common_utils';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
/**
* Environments Store.
*
......@@ -66,8 +66,8 @@ export default class EnvironmentsStore {
}
setPagination(pagination = {}) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination);
const paginationInformation = gl.utils.parseIntPagination(normalizedHeaders);
const normalizedHeaders = normalizeHeaders(pagination);
const paginationInformation = parseIntPagination(normalizedHeaders);
this.state.paginationInformation = paginationInformation;
return paginationInformation;
......
<script>
import tablePagination from '~/vue_shared/components/table_pagination.vue';
import eventHub from '../event_hub';
import { getParameterByName } from '../../lib/utils/common_utils';
export default {
props: {
......@@ -18,8 +19,8 @@ export default {
},
methods: {
change(page) {
const filterGroupsParam = gl.utils.getParameterByName('filter_groups');
const sortParam = gl.utils.getParameterByName('sort');
const filterGroupsParam = getParameterByName('filter_groups');
const sortParam = getParameterByName('sort');
eventHub.$emit('fetchPage', page, filterGroupsParam, sortParam);
},
},
......
import FilterableList from '~/filterable_list';
import eventHub from './event_hub';
import { getParameterByName } from '../lib/utils/common_utils';
export default class GroupFilterableList extends FilterableList {
constructor({ form, filter, holder, filterEndpoint, pagePath }) {
......@@ -54,7 +55,7 @@ export default class GroupFilterableList extends FilterableList {
e.preventDefault();
const queryData = {};
const sortParam = gl.utils.getParameterByName('sort', e.currentTarget.href);
const sortParam = getParameterByName('sort', e.currentTarget.href);
if (sortParam) {
queryData.sort = sortParam;
......
......@@ -8,6 +8,7 @@ import GroupItem from './components/group_item.vue';
import GroupsStore from './stores/groups_store';
import GroupsService from './services/groups_service';
import eventHub from './event_hub';
import { getParameterByName } from '../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('dashboard-group-app');
......@@ -58,17 +59,17 @@ document.addEventListener('DOMContentLoaded', () => {
this.isLoading = true;
}
pageParam = gl.utils.getParameterByName('page');
pageParam = getParameterByName('page');
if (pageParam) {
page = pageParam;
}
filterGroupsParam = gl.utils.getParameterByName('filter_groups');
filterGroupsParam = getParameterByName('filter_groups');
if (filterGroupsParam) {
filterGroups = filterGroupsParam;
}
sortParam = gl.utils.getParameterByName('sort');
sortParam = getParameterByName('sort');
if (sortParam) {
sort = sortParam;
}
......
import Vue from 'vue';
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default class GroupsStore {
constructor() {
......@@ -30,8 +31,8 @@ export default class GroupsStore {
let paginationInfo;
if (Object.keys(pagination).length) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination);
paginationInfo = gl.utils.parseIntPagination(normalizedHeaders);
const normalizedHeaders = normalizeHeaders(pagination);
paginationInfo = parseIntPagination(normalizedHeaders);
} else {
paginationInfo = pagination;
}
......
......@@ -4,6 +4,7 @@
prefer-rest-params, prefer-spread, no-unused-vars, prefer-template,
promise/catch-or-return */
import Api from './api';
import { normalizeCRLFHeaders } from './lib/utils/common_utils';
var slice = [].slice;
......@@ -30,7 +31,7 @@ window.GroupsSelect = (function() {
$.ajax(params).then((data, status, xhr) => {
const results = data || [];
const headers = gl.utils.normalizeCRLFHeaders(xhr.getAllResponseHeaders());
const headers = normalizeCRLFHeaders(xhr.getAllResponseHeaders());
const currentPage = parseInt(headers['X-PAGE'], 10) || 0;
const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0;
const more = currentPage < totalPages;
......
/* eslint-disable no-param-reassing */
window.gl = window.gl || {};
window.gl.utils = window.gl.utils || {};
export const getPagePath = (index = 0) => $('body').data('page').split(':')[index];
window.gl.utils.getPagePath = getPagePath;
......@@ -48,7 +49,7 @@ export const ajaxPost = (url, data) => $.ajax({
window.gl.utils.ajaxPost = ajaxPost;
// TODO: This function seems not to be used anywhere
window.gl.utils.extractLast = term => this.split(term).pop();
// window.gl.utils.extractLast = term => this.split(term).pop();
export const rstrip = function rstrip(val) {
if (val) {
......@@ -145,10 +146,11 @@ window.gl.utils.parseUrlPathname = parseUrlPathname;
// We can trust that each param has one & since values containing & will be encoded
// Remove the first character of search as it is always ?
window.gl.utils.getUrlParamsArray = () => window.location.search.slice(1).split('&').map((param) => {
export const getUrlParamsArray = () => window.location.search.slice(1).split('&').map((param) => {
const split = param.split('=');
return [decodeURI(split[0]), split[1]].join('=');
});
window.gl.utils.getUrlParamsArray = getUrlParamsArray;
export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
window.gl.utils.isMetaKey = isMetaKey;
......@@ -178,8 +180,8 @@ window.gl.utils.scrollToElement = scrollToElement;
*/
export const getParameterByName = (name, urlToParse) => {
const url = urlToParse || window.location.href;
name = name.replace(/[[\]]/g, '\\$&');
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`);
const parsedName = name.replace(/[[\]]/g, '\\$&');
const regex = new RegExp(`[?&]${parsedName}(=([^&#]*)|&|#|$)`);
const results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
......@@ -200,6 +202,7 @@ export const getSelectedFragment = () => {
};
window.gl.utils.getSelectedFragment = getSelectedFragment;
// 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
const selectionStart = target.selectionStart;
......@@ -212,7 +215,9 @@ export const insertText = (target, text) => {
const insertedText = text instanceof Function ? text(textBefore, textAfter) : text;
const newText = textBefore + insertedText + textAfter;
// eslint-disable-next-line no-param-reassign
target.value = newText;
// eslint-disable-next-line no-param-reassign
target.selectionStart = target.selectionEnd = selectionStart + insertedText.length;
// Trigger autosave
......@@ -242,6 +247,7 @@ export const nodeMatchesSelector = (node, selector) => {
let parentNode = node.parentNode;
if (!parentNode) {
parentNode = document.createElement('div');
// eslint-disable-next-line no-param-reassign
node = node.cloneNode(true);
parentNode.appendChild(node);
}
......@@ -264,7 +270,6 @@ export const normalizeHeaders = (headers) => {
return upperCaseHeaders;
};
window.gl.utils.normalizeHeaders = normalizeHeaders;
/**
this will take in the getAllResponseHeaders result and normalize them
......@@ -281,7 +286,6 @@ export const normalizeCRLFHeaders = (headers) => {
return normalizeHeaders(headersObject);
};
window.gl.utils.normalizeCRLFHeaders = normalizeCRLFHeaders;
/**
* Parses pagination object string values into numbers.
......@@ -297,7 +301,6 @@ export const parseIntPagination = paginationInformation => ({
nextPage: parseInt(paginationInformation['X-NEXT-PAGE'], 10),
previousPage: parseInt(paginationInformation['X-PREV-PAGE'], 10),
});
window.gl.utils.parseIntPagination = parseIntPagination;
/**
* Updates the search parameter of a URL given the parameter and value provided.
......@@ -320,6 +323,7 @@ export const setParamInURL = (param, value) => {
.split('&')
.reduce((acc, element) => {
const val = element.split('=');
// eslint-disable-next-line no-param-reassign
acc[val[0]] = decodeURIComponent(val[1]);
return acc;
}, {});
......@@ -337,7 +341,6 @@ export const setParamInURL = (param, value) => {
return search;
};
window.gl.utils.setParamInURL = setParamInURL;
/**
* Converts permission provided as strings to booleans.
......@@ -346,7 +349,6 @@ window.gl.utils.setParamInURL = setParamInURL;
* @returns {Boolean}
*/
export const convertPermissionToBoolean = permission => permission === 'true';
window.gl.utils.convertPermissionToBoolean = convertPermissionToBoolean;
/**
* Back Off exponential algorithm
......@@ -400,7 +402,6 @@ export const backOff = (fn, timeout = 60000) => {
fn(next, stop);
});
};
window.gl.utils.backOff = backOff;
export const setFavicon = (faviconPath) => {
const faviconEl = document.getElementById('favicon');
......@@ -408,7 +409,6 @@ export const setFavicon = (faviconPath) => {
faviconEl.setAttribute('href', faviconPath);
}
};
window.gl.utils.setFavicon = setFavicon;
export const resetFavicon = () => {
const faviconEl = document.getElementById('favicon');
......@@ -417,7 +417,6 @@ export const resetFavicon = () => {
faviconEl.setAttribute('href', originalFavicon);
}
};
window.gl.utils.resetFavicon = resetFavicon;
export const setCiStatusFavicon = (pageUrl) => {
$.ajax({
......@@ -425,14 +424,13 @@ export const setCiStatusFavicon = (pageUrl) => {
dataType: 'json',
success: (data) => {
if (data && data.favicon) {
gl.utils.setFavicon(data.favicon);
setFavicon(data.favicon);
} else {
gl.utils.resetFavicon();
resetFavicon();
}
},
error: () => {
gl.utils.resetFavicon();
resetFavicon();
},
});
};
window.gl.utils.setCiStatusFavicon = setCiStatusFavicon;
import httpStatusCodes from './http_status';
import { normalizeHeaders } from './common_utils';
/**
* Polling utility for handling realtime updates.
......@@ -57,7 +58,7 @@ export default class Poll {
}
checkConditions(response) {
const headers = gl.utils.normalizeHeaders(response.headers);
const headers = normalizeHeaders(response.headers);
const pollInterval = parseInt(headers[this.intervalHeader], 10);
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
......
......@@ -41,7 +41,7 @@ import './commit/image_file';
// lib/utils
import './lib/utils/animate';
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/pretty_time';
import './lib/utils/text_utility';
......@@ -162,10 +162,10 @@ document.addEventListener('beforeunload', function () {
$('[data-toggle="popover"]').popover('destroy');
});
window.addEventListener('hashchange', gl.utils.handleLocationHash);
window.addEventListener('hashchange', handleLocationHash);
window.addEventListener('load', function onLoad() {
window.removeEventListener('load', onLoad, false);
gl.utils.handleLocationHash();
handleLocationHash();
}, false);
gl.lazyLoader = new LazyLoader({
......@@ -191,7 +191,7 @@ $(function () {
$body.on('click', 'a[href^="#"]', function() {
var href = this.getAttribute('href');
if (href.substr(1) === gl.utils.getLocationHash()) {
setTimeout(gl.utils.handleLocationHash, 1);
setTimeout(handleLocationHash, 1);
}
});
......
......@@ -7,7 +7,11 @@ import './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints';
import parseUrlPathname from './lib/utils/common_utils';
import {
parseUrlPathname,
handleLocationHash,
isMetaClick,
} from './lib/utils/common_utils';
/* eslint-disable max-len */
// MergeRequestTabs
......@@ -115,7 +119,7 @@ import parseUrlPathname from './lib/utils/common_utils';
}
clickTab(e) {
if (e.currentTarget && gl.utils.isMetaClick(e)) {
if (e.currentTarget && isMetaClick(e)) {
const targetLink = e.currentTarget.getAttribute('href');
e.stopImmediatePropagation();
e.preventDefault();
......@@ -310,7 +314,7 @@ import parseUrlPathname from './lib/utils/common_utils';
forceShow: true,
});
anchor[0].scrollIntoView();
window.gl.utils.handleLocationHash();
handleLocationHash();
// We have multiple elements on the page with `#note_xxx`
// (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target');
......
......@@ -8,7 +8,7 @@
import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub';
import { backOff } from '../../lib/utils/common_utils';
import { backOff, convertPermissionToBoolean } from '../../lib/utils/common_utils';
export default {
......@@ -19,7 +19,7 @@
return {
store,
state: 'gettingStarted',
hasMetrics: gl.utils.convertPermissionToBoolean(metricsData.hasMetrics),
hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics),
documentationPath: metricsData.documentationPath,
settingsPath: metricsData.settingsPath,
endpoint: metricsData.additionalMetrics,
......
......@@ -23,7 +23,7 @@ import loadAwardsHandler from './awards_handler';
import './autosave';
import './dropzone_input';
import TaskList from './task_list';
import { ajaxPost, isInViewport, getPagePath } from './lib/utils/common_utils';
import { ajaxPost, isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils';
window.autosize = autosize;
window.Dropzone = Dropzone;
......@@ -176,7 +176,7 @@ export default class Notes {
keydownNoteText(e) {
var $textarea, discussionNoteForm, editNote, myLastNote, myLastNoteEditBtn, newText, originalText;
if (gl.utils.isMetaKey(e)) {
if (isMetaKey(e)) {
return;
}
......@@ -1482,7 +1482,7 @@ export default class Notes {
*
* 1) Get Form metadata
* 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
* 1. Show submitted Note element
* b) If request failed
......
import '~/lib/utils/common_utils';
import { getParameterByName } from '~/lib/utils/common_utils';
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) {
this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']);
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.prepareData = prepareData;
this.callback = callback;
......
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
function insertRow($row) {
const $rowClone = $row.clone();
$rowClone.removeAttr('data-is-persisted');
......@@ -6,7 +8,7 @@ function insertRow($row) {
}
function removeRow($row) {
const isPersisted = gl.utils.convertPermissionToBoolean($row.attr('data-is-persisted'));
const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
if (isPersisted) {
$row.hide();
......
import LinkedTabs from './lib/utils/bootstrap_linked_tabs';
import { setCiStatusFavicon } from './lib/utils/common_utils';
export default class Pipelines {
constructor(options = {}) {
......@@ -8,7 +9,7 @@ export default class Pipelines {
}
if (options.pipelineStatusUrl) {
gl.utils.setCiStatusFavicon(options.pipelineStatusUrl);
setCiStatusFavicon(options.pipelineStatusUrl);
}
}
}
......@@ -4,6 +4,7 @@
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import navigationTabs from './navigation_tabs.vue';
import navigationControls from './nav_controls.vue';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default {
props: {
......@@ -44,10 +45,10 @@
},
computed: {
canCreatePipelineParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreatePipeline);
return convertPermissionToBoolean(this.canCreatePipeline);
},
scope() {
const scope = gl.utils.getParameterByName('scope');
const scope = getParameterByName('scope');
return scope === null ? 'all' : scope;
},
......@@ -105,10 +106,10 @@
};
},
pageParameter() {
return gl.utils.getParameterByName('page') || this.pagenum;
return getParameterByName('page') || this.pagenum;
},
scopeParameter() {
return gl.utils.getParameterByName('scope') || this.apiScope;
return getParameterByName('scope') || this.apiScope;
},
},
created() {
......@@ -122,7 +123,7 @@
* @param {Number} pageNumber desired page to go to.
*/
change(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber);
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
......
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default class PipelinesStore {
constructor() {
this.state = {};
......@@ -19,8 +21,8 @@ export default class PipelinesStore {
let paginationInfo;
if (Object.keys(pagination).length) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination);
paginationInfo = gl.utils.parseIntPagination(normalizedHeaders);
const normalizedHeaders = normalizeHeaders(pagination);
paginationInfo = parseIntPagination(normalizedHeaders);
} else {
paginationInfo = pagination;
}
......
/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
import UsersSelect from './users_select';
import { isMetaClick } from './lib/utils/common_utils';
export default class Todos {
constructor() {
......@@ -141,7 +142,7 @@ export default class Todos {
return;
}
if (gl.utils.isMetaClick(e)) {
if (isMetaClick(e)) {
const windowTarget = '_blank';
const selected = e.target;
e.stopPropagation();
......
......@@ -31,6 +31,7 @@ import {
SquashBeforeMerge,
notify,
} from './dependencies';
import { setFavicon } from '../lib/utils/common_utils';
export default {
el: '#js-vue-mr-widget',
......@@ -86,7 +87,7 @@ export default {
.then((res) => {
this.handleNotification(res);
this.mr.setData(res);
this.setFavicon();
this.setFaviconHelper();
if (cb) {
cb.call(null, res);
......@@ -115,9 +116,9 @@ export default {
immediateExecution: true,
});
},
setFavicon() {
setFaviconHelper() {
if (this.mr.ciStatusFaviconPath) {
gl.utils.setFavicon(this.mr.ciStatusFaviconPath);
setFavicon(this.mr.ciStatusFaviconPath);
}
},
fetchDeployments() {
......@@ -193,7 +194,7 @@ export default {
});
},
handleMounted() {
this.setFavicon();
this.setFaviconHelper();
this.initDeploymentsPolling();
},
},
......
---
title: Exports common_utils utility functions as modules
merge_request:
author:
type: other
......@@ -14,6 +14,10 @@ describe('Environments Folder View', () => {
window.history.pushState({}, null, 'environments/folders/build');
});
afterEach(() => {
window.history.pushState({}, null, '');
});
let component;
describe('successfull request', () => {
......
......@@ -18,26 +18,22 @@ describe('common_utils', () => {
});
describe('parseUrlPathname', () => {
beforeEach(() => {
spyOn(gl.utils, 'parseUrl').and.callFake(url => ({
pathname: url,
}));
});
it('returns an absolute url when given an absolute url', () => {
expect(commonUtils.parseUrlPathname('/some/absolute/url')).toEqual('/some/absolute/url');
});
it('returns an absolute url when given a relative url', () => {
expect(commonUtils.parseUrlPathname('some/relative/url')).toEqual('/some/relative/url');
});
});
describe('gl.utils.getUrlParamsArray', () => {
describe('getUrlParamsArray', () => {
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', () => {
const paramsArray = gl.utils.getUrlParamsArray();
const paramsArray = commonUtils.getUrlParamsArray();
expect(paramsArray[0][0] !== '?').toBe(true);
});
......@@ -45,7 +41,7 @@ describe('common_utils', () => {
history.pushState('', '', '?label_name%5B%5D=test');
expect(
gl.utils.getUrlParamsArray()[0],
commonUtils.getUrlParamsArray()[0],
).toBe('label_name[]=test');
history.pushState('', '', '?');
......@@ -90,7 +86,7 @@ describe('common_utils', () => {
});
});
describe('gl.utils.setParamInURL', () => {
describe('setParamInURL', () => {
afterEach(() => {
window.history.pushState({}, null, '');
});
......@@ -98,40 +94,40 @@ describe('common_utils', () => {
it('should return the parameter', () => {
window.history.replaceState({}, null, '');
expect(gl.utils.setParamInURL('page', 156)).toBe('?page=156');
expect(gl.utils.setParamInURL('page', '156')).toBe('?page=156');
expect(commonUtils.setParamInURL('page', 156)).toBe('?page=156');
expect(commonUtils.setParamInURL('page', '156')).toBe('?page=156');
});
it('should update the existing parameter when its a number', () => {
window.history.pushState({}, null, '?page=15');
expect(gl.utils.setParamInURL('page', 16)).toBe('?page=16');
expect(gl.utils.setParamInURL('page', '16')).toBe('?page=16');
expect(gl.utils.setParamInURL('page', true)).toBe('?page=true');
expect(commonUtils.setParamInURL('page', 16)).toBe('?page=16');
expect(commonUtils.setParamInURL('page', '16')).toBe('?page=16');
expect(commonUtils.setParamInURL('page', true)).toBe('?page=true');
});
it('should update the existing parameter when its a string', () => {
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', () => {
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', () => {
window.history.pushState({}, null, '?scope=all');
expect(gl.utils.setParamInURL('page', 16)).toBe('?scope=all&page=16');
expect(gl.utils.setParamInURL('page', '16')).toBe('?scope=all&page=16');
expect(gl.utils.setParamInURL('page', true)).toBe('?scope=all&page=true');
expect(commonUtils.setParamInURL('page', 16)).toBe('?scope=all&page=16');
expect(commonUtils.setParamInURL('page', '16')).toBe('?scope=all&page=16');
expect(commonUtils.setParamInURL('page', true)).toBe('?scope=all&page=true');
});
});
describe('gl.utils.getParameterByName', () => {
describe('getParameterByName', () => {
beforeEach(() => {
window.history.pushState({}, null, '?scope=all&p=2');
});
......@@ -141,33 +137,33 @@ describe('common_utils', () => {
});
it('should return valid parameter', () => {
const value = gl.utils.getParameterByName('scope');
expect(gl.utils.getParameterByName('p')).toEqual('2');
const value = commonUtils.getParameterByName('scope');
expect(commonUtils.getParameterByName('p')).toEqual('2');
expect(value).toBe('all');
});
it('should return invalid parameter', () => {
const value = gl.utils.getParameterByName('fakeParameter');
const value = commonUtils.getParameterByName('fakeParameter');
expect(value).toBe(null);
});
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');
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');
});
});
describe('gl.utils.normalizedHeaders', () => {
describe('normalizedHeaders', () => {
it('should upperCase all the header keys to keep them consistent', () => {
const apiHeaders = {
'X-Something-Workhorse': { workhorse: 'ok' },
'x-something-nginx': { nginx: 'ok' },
};
const normalized = gl.utils.normalizeHeaders(apiHeaders);
const normalized = commonUtils.normalizeHeaders(apiHeaders);
const WORKHORSE = 'X-SOMETHING-WORKHORSE';
const NGINX = 'X-SOMETHING-NGINX';
......@@ -177,14 +173,11 @@ describe('common_utils', () => {
});
});
describe('gl.utils.normalizeCRLFHeaders', () => {
describe('normalizeCRLFHeaders', () => {
beforeEach(function () {
this.CLRFHeaders = 'a-header: a-value\nAnother-Header: ANOTHER-VALUE\nLaSt-HeAdEr: last-VALUE';
spyOn(String.prototype, 'split').and.callThrough();
spyOn(gl.utils, 'normalizeHeaders').and.callThrough();
this.normalizeCRLFHeaders = gl.utils.normalizeCRLFHeaders(this.CLRFHeaders);
this.normalizeCRLFHeaders = commonUtils.normalizeCRLFHeaders(this.CLRFHeaders);
});
it('should split by newline', function () {
......@@ -195,10 +188,6 @@ describe('common_utils', () => {
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 () {
expect(this.normalizeCRLFHeaders).toEqual({
'A-HEADER': 'a-value',
......@@ -208,7 +197,7 @@ describe('common_utils', () => {
});
});
describe('gl.utils.parseIntPagination', () => {
describe('parseIntPagination', () => {
it('should parse to integers all string values and return pagination object', () => {
const pagination = {
'X-PER-PAGE': 10,
......@@ -228,11 +217,11 @@ describe('common_utils', () => {
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', () => {
const e = {
metaKey: false,
......@@ -240,7 +229,7 @@ describe('common_utils', () => {
which: 1,
};
expect(gl.utils.isMetaClick(e)).toBe(true);
expect(commonUtils.isMetaClick(e)).toBe(true);
});
it('should identify meta click on macOS', () => {
......@@ -250,7 +239,7 @@ describe('common_utils', () => {
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', () => {
......@@ -260,7 +249,14 @@ describe('common_utils', () => {
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);
});
});
......@@ -333,53 +329,76 @@ describe('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', () => {
const faviconPath = '//custom_favicon';
const fakeLink = {
setAttribute() {},
};
commonUtils.setFavicon(faviconPath);
spyOn(window.document, 'getElementById').and.callFake(() => fakeLink);
spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => {
expect(attr).toEqual('href');
expect(val.indexOf(faviconPath) > -1).toBe(true);
expect(document.getElementById('favicon').getAttribute('href')).toEqual(faviconPath);
});
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', () => {
const fakeLink = {
setAttribute() {},
};
commonUtils.resetFavicon();
expect(document.getElementById('favicon').getAttribute('href')).toEqual('default/favicon');
});
});
describe('setCiStatusFavicon', () => {
const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`;
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
document.body.appendChild(favicon);
});
spyOn(window.document, 'getElementById').and.callFake(() => fakeLink);
spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => {
expect(attr).toEqual('href');
expect(val).toMatch(/favicon/);
afterEach(() => {
document.body.removeChild(document.getElementById('favicon'));
});
gl.utils.resetFavicon();
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', () => {
const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`;
const FAVICON_PATH = '//icon_status_success';
const spySetFavicon = spyOn(gl.utils, 'setFavicon').and.stub();
const spyResetFavicon = spyOn(gl.utils, 'resetFavicon').and.stub();
const favicon = document.getElementById('favicon');
spyOn($, 'ajax').and.callFake(function (options) {
options.success({ favicon: FAVICON_PATH });
expect(spySetFavicon).toHaveBeenCalledWith(FAVICON_PATH);
options.success();
expect(spyResetFavicon).toHaveBeenCalled();
options.error();
expect(spyResetFavicon).toHaveBeenCalled();
expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH);
});
gl.utils.setCiStatusFavicon(BUILD_URL);
commonUtils.setCiStatusFavicon(BUILD_URL);
});
});
......
......@@ -78,8 +78,9 @@ import 'vendor/jquery.scrollTo';
});
describe('meta click', () => {
let metakeyEvent;
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 () {
......@@ -89,7 +90,7 @@ import 'vendor/jquery.scrollTo';
});
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 () {
......@@ -99,7 +100,7 @@ import 'vendor/jquery.scrollTo';
});
this.class.bindEvents();
document.querySelector('.merge-request-tabs .commits-tab a .badge').click();
$('.merge-request-tabs .commits-tab a .badge').trigger(metakeyEvent);
});
});
......
......@@ -26,9 +26,10 @@ describe('Todos', () => {
describe('meta click', () => {
let visitUrlSpy;
let metakeyEvent;
beforeEach(() => {
spyOn(gl.utils, 'isMetaClick').and.returnValue(true);
metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
visitUrlSpy = spyOn(gl.utils, 'visitUrl').and.callFake(() => {});
});
......@@ -41,7 +42,7 @@ describe('Todos', () => {
done();
});
todoItem.click();
$('.todos-list .todo').trigger(metakeyEvent);
expect(visitUrlSpy).not.toHaveBeenCalled();
});
......
......@@ -232,29 +232,42 @@ describe('mrWidgetOptions', () => {
describe('handleMounted', () => {
it('should call required methods to do the initial kick-off', () => {
spyOn(vm, 'initDeploymentsPolling');
spyOn(vm, 'setFavicon');
spyOn(vm, 'setFaviconHelper');
vm.handleMounted();
expect(vm.setFavicon).toHaveBeenCalled();
expect(vm.setFaviconHelper).toHaveBeenCalled();
expect(vm.initDeploymentsPolling).toHaveBeenCalled();
});
});
describe('setFavicon', () => {
let faviconElement;
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
favicon.setAttribute('href', 'default/favicon');
document.body.appendChild(favicon);
faviconElement = document.body.getElementById('favicon');
});
afterEach(() => {
document.body.removeChild(document.getElementById('favicon'));
});
it('should call setFavicon method', () => {
spyOn(gl.utils, 'setFavicon');
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', () => {
spyOn(gl.utils, 'setFavicon');
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