Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /app/assets/javascripts/behaviors
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'app/assets/javascripts/behaviors')
-rw-r--r--app/assets/javascripts/behaviors/copy_to_clipboard.js38
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_math.js99
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/keybindings.js135
-rw-r--r--app/assets/javascripts/behaviors/toggler_behavior.js2
4 files changed, 137 insertions, 137 deletions
diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js
index a31bcc2cb41..de248340738 100644
--- a/app/assets/javascripts/behaviors/copy_to_clipboard.js
+++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js
@@ -1,31 +1,27 @@
import Clipboard from 'clipboard';
import $ from 'jquery';
import { sprintf, __ } from '~/locale';
-import { fixTitle, show } from '~/tooltips';
+import { fixTitle, add, show, once } from '~/tooltips';
function showTooltip(target, title) {
- const { originalTitle } = target.dataset;
- const hideTooltip = () => {
- target.removeEventListener('mouseout', hideTooltip);
- setTimeout(() => {
+ const { title: originalTitle } = target.dataset;
+
+ once('hidden', (tooltip) => {
+ if (tooltip.target === target) {
target.setAttribute('title', originalTitle);
fixTitle(target);
- }, 100);
- };
+ }
+ });
target.setAttribute('title', title);
-
fixTitle(target);
show(target);
-
- target.addEventListener('mouseout', hideTooltip);
+ setTimeout(() => target.blur(), 1000);
}
function genericSuccess(e) {
// Clear the selection and blur the trigger so it loses its border
e.clearSelection();
- $(e.trigger).blur();
-
showTooltip(e.trigger, __('Copied'));
}
@@ -88,24 +84,8 @@ export default function initCopyToClipboard() {
* @param {HTMLElement} btnElement
*/
export function clickCopyToClipboardButton(btnElement) {
- const $btnElement = $(btnElement);
-
// Ensure the button has already been tooltip'd.
- // If the use hasn't yet interacted (i.e. hovered or clicked)
- // with the button, Bootstrap hasn't yet initialized
- // the tooltip, and its `data-original-title` will be `undefined`.
- // This value is used in the functions above.
- $btnElement.tooltip();
- btnElement.dispatchEvent(new MouseEvent('mouseover'));
+ add([btnElement], { show: true });
btnElement.click();
-
- // Manually trigger the necessary events to hide the
- // button's tooltip and allow the button to perform its
- // tooltip cleanup (updating the title from "Copied" back
- // to its original title, "Copy branch name").
- setTimeout(() => {
- btnElement.dispatchEvent(new MouseEvent('mouseout'));
- $btnElement.tooltip('hide');
- }, 2000);
}
diff --git a/app/assets/javascripts/behaviors/markdown/render_math.js b/app/assets/javascripts/behaviors/markdown/render_math.js
index 5479866c99a..8238f5523f3 100644
--- a/app/assets/javascripts/behaviors/markdown/render_math.js
+++ b/app/assets/javascripts/behaviors/markdown/render_math.js
@@ -1,6 +1,6 @@
-import { deprecatedCreateFlash as flash } from '~/flash';
+import { spriteIcon } from '~/lib/utils/common_utils';
import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
-import { s__, sprintf } from '~/locale';
+import { s__ } from '~/locale';
// Renders math using KaTeX in any element with the
// `js-render-math` class
@@ -13,30 +13,10 @@ import { s__, sprintf } from '~/locale';
const MAX_MATH_CHARS = 1000;
const MAX_RENDER_TIME_MS = 2000;
-// These messages might be used with inline errors in the future. Keep them around. For now, we will
-// display a single error message using flash().
-
-// const CHAR_LIMIT_EXCEEDED_MSG = sprintf(
-// s__(
-// 'math|The following math is too long. For performance reasons, math blocks are limited to %{maxChars} characters. Try splitting up this block, or include an image instead.',
-// ),
-// { maxChars: MAX_MATH_CHARS },
-// );
-// const RENDER_TIME_EXCEEDED_MSG = s__(
-// "math|The math in this entry is taking too long to render. Any math below this point won't be shown. Consider splitting it among multiple entries.",
-// );
-
-const RENDER_FLASH_MSG = sprintf(
- s__(
- 'math|The math in this entry is taking too long to render and may not be displayed as expected. For performance reasons, math blocks are also limited to %{maxChars} characters. Consider splitting up large formulae, splitting math blocks among multiple entries, or using an image instead.',
- ),
- { maxChars: MAX_MATH_CHARS },
-);
-
// Wait for the browser to reflow the layout. Reflowing SVG takes time.
// This has to wrap the inner function, otherwise IE/Edge throw "invalid calling object".
const waitForReflow = (fn) => {
- window.requestAnimationFrame(fn);
+ window.requestIdleCallback(fn);
};
/**
@@ -67,37 +47,69 @@ class SafeMathRenderer {
this.renderElement = this.renderElement.bind(this);
this.render = this.render.bind(this);
+ this.attachEvents = this.attachEvents.bind(this);
}
- renderElement() {
- if (!this.queue.length) {
+ renderElement(chosenEl) {
+ if (!this.queue.length && !chosenEl) {
return;
}
- const el = this.queue.shift();
+ const el = chosenEl || this.queue.shift();
+ const forceRender = Boolean(chosenEl);
const text = el.textContent;
el.removeAttribute('style');
-
- if (this.totalMS >= MAX_RENDER_TIME_MS || text.length > MAX_MATH_CHARS) {
- if (!this.flashShown) {
- flash(RENDER_FLASH_MSG);
- this.flashShown = true;
- }
-
+ if (!forceRender && (this.totalMS >= MAX_RENDER_TIME_MS || text.length > MAX_MATH_CHARS)) {
// Show unrendered math code
+ const wrapperElement = document.createElement('div');
const codeElement = document.createElement('pre');
+
codeElement.className = 'code';
codeElement.textContent = el.textContent;
- el.parentNode.replaceChild(codeElement, el);
+
+ const { parentNode } = el;
+ parentNode.replaceChild(wrapperElement, el);
+
+ const html = `
+ <div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-math-container js-lazy-render-math-container fade show" role="alert">
+ ${spriteIcon('warning', 'text-warning-600 s16 gl-alert-icon')}
+ <div class="display-flex gl-alert-content">
+ <div>${s__(
+ 'math|Displaying this math block may cause performance issues on this page',
+ )}</div>
+ <div class="gl-alert-actions">
+ <button class="js-lazy-render-math btn gl-alert-action btn-primary btn-md gl-button">Display anyway</button>
+ </div>
+ </div>
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+ ${spriteIcon('close', 's16')}
+ </button>
+ </div>
+ `;
+
+ if (!wrapperElement.classList.contains('lazy-alert-shown')) {
+ wrapperElement.innerHTML = html;
+ wrapperElement.append(codeElement);
+ wrapperElement.classList.add('lazy-alert-shown');
+ }
// Render the next math
this.renderElement();
} else {
this.startTime = Date.now();
+ /* Get the correct reference to the display container when:
+ * a.) Happy path: when the math block is present, and
+ * b.) When we've replace the block with <pre> for lazy rendering
+ */
+ let displayContainer = el;
+ if (el.tagName === 'PRE') {
+ displayContainer = el.parentElement;
+ }
+
try {
- el.innerHTML = this.katex.renderToString(text, {
+ displayContainer.innerHTML = this.katex.renderToString(text, {
displayMode: el.getAttribute('data-math-style') === 'display',
throwOnError: true,
maxSize: 20,
@@ -135,6 +147,22 @@ class SafeMathRenderer {
// and less prone to timeouts.
setTimeout(this.renderElement, 400);
}
+
+ attachEvents() {
+ document.body.addEventListener('click', (event) => {
+ if (!event.target.classList.contains('js-lazy-render-math')) {
+ return;
+ }
+
+ const parent = event.target.closest('.js-lazy-render-math-container');
+
+ const pre = parent.nextElementSibling;
+
+ parent.remove();
+
+ this.renderElement(pre);
+ });
+ }
}
export default function renderMath($els) {
@@ -146,6 +174,7 @@ export default function renderMath($els) {
.then(([katex]) => {
const renderer = new SafeMathRenderer($els.get(), katex);
renderer.render();
+ renderer.attachEvents();
})
.catch(() => {});
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/keybindings.js b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
index 0513e807ed6..a8fe00d26e6 100644
--- a/app/assets/javascripts/behaviors/shortcuts/keybindings.js
+++ b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
@@ -1,91 +1,80 @@
-import { flatten } from 'lodash';
+import { memoize } from 'lodash';
import AccessorUtilities from '~/lib/utils/accessor';
import { s__ } from '~/locale';
-import { shouldDisableShortcuts } from './shortcuts_toggle';
-export const LOCAL_STORAGE_KEY = 'gl-keyboard-shortcuts-customizations';
-
-let parsedCustomizations = {};
-const localStorageIsSafe = AccessorUtilities.isLocalStorageAccessSafe();
+const isCustomizable = (command) =>
+ 'customizable' in command ? Boolean(command.customizable) : true;
-if (localStorageIsSafe) {
- try {
- parsedCustomizations = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) || '{}');
- } catch (e) {
- /* do nothing */
- }
-}
+export const LOCAL_STORAGE_KEY = 'gl-keyboard-shortcuts-customizations';
/**
- * A map of command => keys of all keyboard shortcuts
- * that have been customized by the user.
+ * @returns { Object.<string, string[]> } A map of command ID => keys of all
+ * keyboard shortcuts that have been customized by the user. These
+ * customizations are fetched from `localStorage`. This function is memoized,
+ * so its return value will not reflect changes made to the `localStorage` data
+ * after it has been called once.
*
* @example
* { "globalShortcuts.togglePerformanceBar": ["p e r f"] }
- *
- * @type { Object.<string, string[]> }
*/
-export const customizations = parsedCustomizations;
+export const getCustomizations = memoize(() => {
+ let parsedCustomizations = {};
+ const localStorageIsSafe = AccessorUtilities.isLocalStorageAccessSafe();
+
+ if (localStorageIsSafe) {
+ try {
+ parsedCustomizations = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) || '{}');
+ } catch (e) {
+ /* do nothing */
+ }
+ }
+
+ return parsedCustomizations;
+});
// All available commands
-export const TOGGLE_PERFORMANCE_BAR = 'globalShortcuts.togglePerformanceBar';
-export const TOGGLE_CANARY = 'globalShortcuts.toggleCanary';
+export const TOGGLE_PERFORMANCE_BAR = {
+ id: 'globalShortcuts.togglePerformanceBar',
+ description: s__('KeyboardShortcuts|Toggle the Performance Bar'),
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ defaultKeys: ['p b'],
+};
-/** All keybindings, grouped and ordered with descriptions */
-export const keybindingGroups = [
- {
- groupId: 'globalShortcuts',
- name: s__('KeyboardShortcuts|Global Shortcuts'),
- keybindings: [
- {
- description: s__('KeyboardShortcuts|Toggle the Performance Bar'),
- command: TOGGLE_PERFORMANCE_BAR,
- // eslint-disable-next-line @gitlab/require-i18n-strings
- defaultKeys: ['p b'],
- },
- {
- description: s__('KeyboardShortcuts|Toggle GitLab Next'),
- command: TOGGLE_CANARY,
- // eslint-disable-next-line @gitlab/require-i18n-strings
- defaultKeys: ['g x'],
- },
- ],
- },
-]
+export const TOGGLE_CANARY = {
+ id: 'globalShortcuts.toggleCanary',
+ description: s__('KeyboardShortcuts|Toggle GitLab Next'),
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ defaultKeys: ['g x'],
+};
- // For each keybinding object, add a `customKeys` property populated with the
- // user's custom keybindings (if the command has been customized).
- // `customKeys` will be `undefined` if the command hasn't been customized.
- .map((group) => {
- return {
- ...group,
- keybindings: group.keybindings.map((binding) => ({
- ...binding,
- customKeys: customizations[binding.command],
- })),
- };
- });
+export const WEB_IDE_COMMIT = {
+ id: 'webIDE.commit',
+ description: s__('KeyboardShortcuts|Commit (when editing commit message)'),
+ defaultKeys: ['mod+enter'],
+ customizable: false,
+};
-/**
- * A simple map of command => keys. All user customizations are included in this map.
- * This mapping is used to simplify `keysFor` below.
- *
- * @example
- * { "globalShortcuts.togglePerformanceBar": ["p e r f"] }
- */
-const commandToKeys = flatten(keybindingGroups.map((group) => group.keybindings)).reduce(
- (acc, binding) => {
- acc[binding.command] = binding.customKeys || binding.defaultKeys;
- return acc;
- },
- {},
-);
+// All keybinding groups
+export const GLOBAL_SHORTCUTS_GROUP = {
+ id: 'globalShortcuts',
+ name: s__('KeyboardShortcuts|Global Shortcuts'),
+ keybindings: [TOGGLE_PERFORMANCE_BAR, TOGGLE_CANARY],
+};
+
+export const WEB_IDE_GROUP = {
+ id: 'webIDE',
+ name: s__('KeyboardShortcuts|Web IDE'),
+ keybindings: [WEB_IDE_COMMIT],
+};
+
+/** All keybindings, grouped and ordered with descriptions */
+export const keybindingGroups = [GLOBAL_SHORTCUTS_GROUP, WEB_IDE_GROUP];
/**
* Gets keyboard shortcuts associated with a command
*
- * @param {string} command The command string. All command
- * strings are available as imports from this file.
+ * @param {string} command The command object. All command
+ * objects are available as imports from this file.
*
* @returns {string[]} An array of keyboard shortcut strings bound to the command
*
@@ -95,9 +84,11 @@ const commandToKeys = flatten(keybindingGroups.map((group) => group.keybindings)
* Mousetrap.bind(keysFor(TOGGLE_PERFORMANCE_BAR), handler);
*/
export const keysFor = (command) => {
- if (shouldDisableShortcuts()) {
- return [];
+ if (!isCustomizable(command)) {
+ // if the command is defined with `customizable: false`,
+ // don't allow this command to be customized.
+ return command.defaultKeys;
}
- return commandToKeys[command];
+ return getCustomizations()[command.id] || command.defaultKeys;
};
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js
index 4b63143c4ba..30424fee46a 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.js
+++ b/app/assets/javascripts/behaviors/toggler_behavior.js
@@ -30,7 +30,7 @@ $(() => {
}
$('body').on('click', '.js-toggle-button', function toggleButton(e) {
- e.currentTarget.classList.toggle(e.currentTarget.dataset.toggleOpenClass || 'open');
+ e.currentTarget.classList.toggle(e.currentTarget.dataset.toggleOpenClass || 'selected');
toggleContainer($(this).closest('.js-toggle-container'));
const targetTag = e.currentTarget.tagName.toLowerCase();