forked from Shiloh/githaven
Remove jQuery .text()
(#30506)
Remove and forbid [.text()](https://api.jquery.com/text/). Tested some, but not all functionality, but I think these are pretty safe replacements. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
4f7d6feab7
commit
a2304cb163
@ -324,7 +324,7 @@ rules:
|
|||||||
jquery/no-sizzle: [2]
|
jquery/no-sizzle: [2]
|
||||||
jquery/no-slide: [2]
|
jquery/no-slide: [2]
|
||||||
jquery/no-submit: [2]
|
jquery/no-submit: [2]
|
||||||
jquery/no-text: [0]
|
jquery/no-text: [2]
|
||||||
jquery/no-toggle: [2]
|
jquery/no-toggle: [2]
|
||||||
jquery/no-trigger: [0]
|
jquery/no-trigger: [0]
|
||||||
jquery/no-trim: [2]
|
jquery/no-trim: [2]
|
||||||
@ -477,7 +477,7 @@ rules:
|
|||||||
no-jquery/no-slide: [2]
|
no-jquery/no-slide: [2]
|
||||||
no-jquery/no-sub: [2]
|
no-jquery/no-sub: [2]
|
||||||
no-jquery/no-support: [2]
|
no-jquery/no-support: [2]
|
||||||
no-jquery/no-text: [0]
|
no-jquery/no-text: [2]
|
||||||
no-jquery/no-trigger: [0]
|
no-jquery/no-trigger: [0]
|
||||||
no-jquery/no-trim: [2]
|
no-jquery/no-trim: [2]
|
||||||
no-jquery/no-type: [2]
|
no-jquery/no-type: [2]
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<div class="quick-pull-choice js-quick-pull-choice">
|
<div class="quick-pull-choice js-quick-pull-choice">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox {{if not .CanCommitToBranch.CanCommitToBranch}}disabled{{end}}">
|
<div class="ui radio checkbox {{if not .CanCommitToBranch.CanCommitToBranch}}disabled{{end}}">
|
||||||
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" button_text="{{ctx.Locale.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "direct"}}checked{{end}}>
|
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" data-button-text="{{ctx.Locale.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "direct"}}checked{{end}}>
|
||||||
<label>
|
<label>
|
||||||
{{svg "octicon-git-commit"}}
|
{{svg "octicon-git-commit"}}
|
||||||
{{ctx.Locale.Tr "repo.editor.commit_directly_to_this_branch" .BranchName}}
|
{{ctx.Locale.Tr "repo.editor.commit_directly_to_this_branch" .BranchName}}
|
||||||
@ -43,9 +43,9 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
{{if .CanCreatePullRequest}}
|
{{if .CanCreatePullRequest}}
|
||||||
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" button_text="{{ctx.Locale.Tr "repo.editor.propose_file_change"}}" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
|
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" data-button-text="{{ctx.Locale.Tr "repo.editor.propose_file_change"}}" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" button_text="{{ctx.Locale.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
|
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" data-button-text="{{ctx.Locale.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
|
||||||
{{end}}
|
{{end}}
|
||||||
<label>
|
<label>
|
||||||
{{svg "octicon-git-pull-request"}}
|
{{svg "octicon-git-pull-request"}}
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
<div class="flex-item-trailing">
|
<div class="flex-item-trailing">
|
||||||
<div class="flex-text-block">
|
<div class="flex-text-block">
|
||||||
{{svg "octicon-shield-lock"}}
|
{{svg "octicon-shield-lock"}}
|
||||||
<div class="ui inline dropdown access-mode" data-url="{{$.Link}}/access_mode" data-uid="{{.ID}}" data-last-value="{{printf "%d" .Collaboration.Mode}}">
|
<div class="ui dropdown custom access-mode" data-url="{{$.Link}}/access_mode" data-uid="{{.ID}}" data-last-value="{{.Collaboration.Mode}}">
|
||||||
<div class="text">{{if eq .Collaboration.Mode 1}}{{ctx.Locale.Tr "repo.settings.collaboration.read"}}{{else if eq .Collaboration.Mode 2}}{{ctx.Locale.Tr "repo.settings.collaboration.write"}}{{else if eq .Collaboration.Mode 3}}{{ctx.Locale.Tr "repo.settings.collaboration.admin"}}{{else}}{{ctx.Locale.Tr "repo.settings.collaboration.undefined"}}{{end}}</div>
|
<div class="text">{{if eq .Collaboration.Mode 1}}{{ctx.Locale.Tr "repo.settings.collaboration.read"}}{{else if eq .Collaboration.Mode 2}}{{ctx.Locale.Tr "repo.settings.collaboration.write"}}{{else if eq .Collaboration.Mode 3}}{{ctx.Locale.Tr "repo.settings.collaboration.admin"}}{{else}}{{ctx.Locale.Tr "repo.settings.collaboration.undefined"}}{{end}}</div>
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="item" data-text="{{ctx.Locale.Tr "repo.settings.collaboration.admin"}}" data-value="3">{{ctx.Locale.Tr "repo.settings.collaboration.admin"}}</div>
|
<div class="item" data-value="3">{{ctx.Locale.Tr "repo.settings.collaboration.admin"}}</div>
|
||||||
<div class="item" data-text="{{ctx.Locale.Tr "repo.settings.collaboration.write"}}" data-value="2">{{ctx.Locale.Tr "repo.settings.collaboration.write"}}</div>
|
<div class="item" data-value="2">{{ctx.Locale.Tr "repo.settings.collaboration.write"}}</div>
|
||||||
<div class="item" data-text="{{ctx.Locale.Tr "repo.settings.collaboration.read"}}" data-value="1">{{ctx.Locale.Tr "repo.settings.collaboration.read"}}</div>
|
<div class="item" data-value="1">{{ctx.Locale.Tr "repo.settings.collaboration.read"}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -301,52 +301,65 @@ async function linkAction(e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initGlobalLinkActions() {
|
export function initGlobalDeleteButton() {
|
||||||
function showDeletePopup(e) {
|
// ".delete-button" shows a confirmation modal defined by `data-modal-id` attribute.
|
||||||
e.preventDefault();
|
// Some model/form elements will be filled by `data-id` / `data-name` / `data-data-xxx` attributes.
|
||||||
const $this = $(this);
|
// If there is a form defined by `data-form`, then the form will be submitted as-is (without any modification).
|
||||||
const dataArray = $this.data();
|
// If there is no form, then the data will be posted to `data-url`.
|
||||||
let filter = '';
|
// TODO: it's not encouraged to use this method. `show-modal` does far better than this.
|
||||||
if (this.getAttribute('data-modal-id')) {
|
for (const btn of document.querySelectorAll('.delete-button')) {
|
||||||
filter += `#${this.getAttribute('data-modal-id')}`;
|
btn.addEventListener('click', (e) => {
|
||||||
}
|
e.preventDefault();
|
||||||
|
|
||||||
const $dialog = $(`.delete.modal${filter}`);
|
// eslint-disable-next-line github/no-dataset -- code depends on the camel-casing
|
||||||
$dialog.find('.name').text($this.data('name'));
|
const dataObj = btn.dataset;
|
||||||
for (const [key, value] of Object.entries(dataArray)) {
|
|
||||||
if (key && key.startsWith('data')) {
|
const modalId = btn.getAttribute('data-modal-id');
|
||||||
$dialog.find(`.${key}`).text(value);
|
const modal = document.querySelector(`.delete.modal${modalId ? `#${modalId}` : ''}`);
|
||||||
|
|
||||||
|
// set the modal "display name" by `data-name`
|
||||||
|
const modalNameEl = modal.querySelector('.name');
|
||||||
|
if (modalNameEl) modalNameEl.textContent = btn.getAttribute('data-name');
|
||||||
|
|
||||||
|
// fill the modal elements with data-xxx attributes: `data-data-organization-name="..."` => `<span class="dataOrganizationName">...</span>`
|
||||||
|
for (const [key, value] of Object.entries(dataObj)) {
|
||||||
|
if (key.startsWith('data')) {
|
||||||
|
const textEl = modal.querySelector(`.${key}`);
|
||||||
|
if (textEl) textEl.textContent = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$dialog.modal({
|
$(modal).modal({
|
||||||
closable: false,
|
closable: false,
|
||||||
onApprove: async () => {
|
onApprove: async () => {
|
||||||
if ($this.data('type') === 'form') {
|
// if `data-type="form"` exists, then submit the form by the selector provided by `data-form="..."`
|
||||||
$($this.data('form')).trigger('submit');
|
if (btn.getAttribute('data-type') === 'form') {
|
||||||
return;
|
const formSelector = btn.getAttribute('data-form');
|
||||||
}
|
const form = document.querySelector(formSelector);
|
||||||
const postData = new FormData();
|
if (!form) throw new Error(`no form named ${formSelector} found`);
|
||||||
for (const [key, value] of Object.entries(dataArray)) {
|
form.submit();
|
||||||
if (key && key.startsWith('data')) {
|
|
||||||
postData.append(key.slice(4), value);
|
|
||||||
}
|
}
|
||||||
if (key === 'id') {
|
|
||||||
postData.append('id', value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await POST($this.data('url'), {data: postData});
|
// prepare an AJAX form by data attributes
|
||||||
if (response.ok) {
|
const postData = new FormData();
|
||||||
const data = await response.json();
|
for (const [key, value] of Object.entries(dataObj)) {
|
||||||
window.location.href = data.redirect;
|
if (key.startsWith('data')) { // for data-data-xxx (HTML) -> dataXxx (form)
|
||||||
}
|
postData.append(key.slice(4), value);
|
||||||
},
|
}
|
||||||
}).modal('show');
|
if (key === 'id') { // for data-id="..."
|
||||||
|
postData.append('id', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await POST(btn.getAttribute('data-url'), {data: postData});
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
window.location.href = data.redirect;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}).modal('show');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers.
|
|
||||||
$('.delete-button').on('click', showDeletePopup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initGlobalShowModal() {
|
function initGlobalShowModal() {
|
||||||
@ -382,7 +395,7 @@ function initGlobalShowModal() {
|
|||||||
} else if ($attrTarget[0].matches('input, textarea')) {
|
} else if ($attrTarget[0].matches('input, textarea')) {
|
||||||
$attrTarget.val(attrib.value); // FIXME: add more supports like checkbox
|
$attrTarget.val(attrib.value); // FIXME: add more supports like checkbox
|
||||||
} else {
|
} else {
|
||||||
$attrTarget.text(attrib.value); // FIXME: it should be more strict here, only handle div/span/p
|
$attrTarget[0].textContent = attrib.value; // FIXME: it should be more strict here, only handle div/span/p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,20 +79,20 @@ export function initImageDiff() {
|
|||||||
path: this.getAttribute('data-path-after'),
|
path: this.getAttribute('data-path-after'),
|
||||||
mime: this.getAttribute('data-mime-after'),
|
mime: this.getAttribute('data-mime-after'),
|
||||||
$images: $container.find('img.image-after'), // matches 3 <img>
|
$images: $container.find('img.image-after'), // matches 3 <img>
|
||||||
$boundsInfo: $container.find('.bounds-info-after'),
|
boundsInfo: this.querySelector('.bounds-info-after'),
|
||||||
}, {
|
}, {
|
||||||
path: this.getAttribute('data-path-before'),
|
path: this.getAttribute('data-path-before'),
|
||||||
mime: this.getAttribute('data-mime-before'),
|
mime: this.getAttribute('data-mime-before'),
|
||||||
$images: $container.find('img.image-before'), // matches 3 <img>
|
$images: $container.find('img.image-before'), // matches 3 <img>
|
||||||
$boundsInfo: $container.find('.bounds-info-before'),
|
boundsInfo: this.querySelector('.bounds-info-before'),
|
||||||
}];
|
}];
|
||||||
|
|
||||||
await Promise.all(imageInfos.map(async (info) => {
|
await Promise.all(imageInfos.map(async (info) => {
|
||||||
const [success] = await Promise.all(Array.from(info.$images, (img) => {
|
const [success] = await Promise.all(Array.from(info.$images, (img) => {
|
||||||
return loadElem(img, info.path);
|
return loadElem(img, info.path);
|
||||||
}));
|
}));
|
||||||
// only the first images is associated with $boundsInfo
|
// only the first images is associated with boundsInfo
|
||||||
if (!success) info.$boundsInfo.text('(image error)');
|
if (!success && info.boundsInfo) info.boundsInfo.textContent = '(image error)';
|
||||||
if (info.mime === 'image/svg+xml') {
|
if (info.mime === 'image/svg+xml') {
|
||||||
const resp = await GET(info.path);
|
const resp = await GET(info.path);
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
@ -102,7 +102,7 @@ export function initImageDiff() {
|
|||||||
this.setAttribute('width', bounds.width);
|
this.setAttribute('width', bounds.width);
|
||||||
this.setAttribute('height', bounds.height);
|
this.setAttribute('height', bounds.height);
|
||||||
});
|
});
|
||||||
hideElem(info.$boundsInfo);
|
hideElem(info.boundsInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -47,17 +47,13 @@ async function receiveUpdateCount(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initNotificationCount() {
|
export function initNotificationCount() {
|
||||||
const $notificationCount = $('.notification_count');
|
if (!document.querySelector('.notification_count')) return;
|
||||||
|
|
||||||
if (!$notificationCount.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let usingPeriodicPoller = false;
|
let usingPeriodicPoller = false;
|
||||||
const startPeriodicPoller = (timeout, lastCount) => {
|
const startPeriodicPoller = (timeout, lastCount) => {
|
||||||
if (timeout <= 0 || !Number.isFinite(timeout)) return;
|
if (timeout <= 0 || !Number.isFinite(timeout)) return;
|
||||||
usingPeriodicPoller = true;
|
usingPeriodicPoller = true;
|
||||||
lastCount = lastCount ?? $notificationCount.text();
|
lastCount = lastCount ?? getCurrentCount();
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
await updateNotificationCountWithCallback(startPeriodicPoller, timeout, lastCount);
|
await updateNotificationCountWithCallback(startPeriodicPoller, timeout, lastCount);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
@ -121,8 +117,12 @@ export function initNotificationCount() {
|
|||||||
startPeriodicPoller(notificationSettings.MinTimeout);
|
startPeriodicPoller(notificationSettings.MinTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentCount() {
|
||||||
|
return document.querySelector('.notification_count').textContent;
|
||||||
|
}
|
||||||
|
|
||||||
async function updateNotificationCountWithCallback(callback, timeout, lastCount) {
|
async function updateNotificationCountWithCallback(callback, timeout, lastCount) {
|
||||||
const currentCount = $('.notification_count').text();
|
const currentCount = getCurrentCount();
|
||||||
if (lastCount !== currentCount) {
|
if (lastCount !== currentCount) {
|
||||||
callback(notificationSettings.MinTimeout, currentCount);
|
callback(notificationSettings.MinTimeout, currentCount);
|
||||||
return;
|
return;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {createCodeEditor} from './codeeditor.js';
|
import {createCodeEditor} from './codeeditor.js';
|
||||||
import {hideElem, showElem} from '../utils/dom.js';
|
import {hideElem, queryElems, showElem} from '../utils/dom.js';
|
||||||
import {initMarkupContent} from '../markup/content.js';
|
import {initMarkupContent} from '../markup/content.js';
|
||||||
import {attachRefIssueContextPopup} from './contextpopup.js';
|
import {attachRefIssueContextPopup} from './contextpopup.js';
|
||||||
import {POST} from '../modules/fetch.js';
|
import {POST} from '../modules/fetch.js';
|
||||||
@ -40,98 +40,75 @@ function initEditPreviewTab($form) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initEditorForm() {
|
|
||||||
const $form = $('.repository .edit.form');
|
|
||||||
if (!$form) return;
|
|
||||||
initEditPreviewTab($form);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCursorPosition($e) {
|
|
||||||
const el = $e.get(0);
|
|
||||||
let pos = 0;
|
|
||||||
if ('selectionStart' in el) {
|
|
||||||
pos = el.selectionStart;
|
|
||||||
} else if ('selection' in document) {
|
|
||||||
el.focus();
|
|
||||||
const Sel = document.selection.createRange();
|
|
||||||
const SelLength = document.selection.createRange().text.length;
|
|
||||||
Sel.moveStart('character', -el.value.length);
|
|
||||||
pos = Sel.text.length - SelLength;
|
|
||||||
}
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initRepoEditor() {
|
export function initRepoEditor() {
|
||||||
initEditorForm();
|
const $editArea = $('.repository.editor textarea#edit_area');
|
||||||
|
if (!$editArea.length) return;
|
||||||
|
|
||||||
$('.js-quick-pull-choice-option').on('change', function () {
|
for (const el of queryElems('.js-quick-pull-choice-option')) {
|
||||||
if ($(this).val() === 'commit-to-new-branch') {
|
el.addEventListener('input', () => {
|
||||||
showElem('.quick-pull-branch-name');
|
if (el.value === 'commit-to-new-branch') {
|
||||||
document.querySelector('.quick-pull-branch-name input').required = true;
|
showElem('.quick-pull-branch-name');
|
||||||
} else {
|
document.querySelector('.quick-pull-branch-name input').required = true;
|
||||||
hideElem('.quick-pull-branch-name');
|
|
||||||
document.querySelector('.quick-pull-branch-name input').required = false;
|
|
||||||
}
|
|
||||||
$('#commit-button').text(this.getAttribute('button_text'));
|
|
||||||
});
|
|
||||||
|
|
||||||
const joinTreePath = ($fileNameEl) => {
|
|
||||||
const parts = [];
|
|
||||||
$('.breadcrumb span.section').each(function () {
|
|
||||||
const $element = $(this);
|
|
||||||
if ($element.find('a').length) {
|
|
||||||
parts.push($element.find('a').text());
|
|
||||||
} else {
|
} else {
|
||||||
parts.push($element.text());
|
hideElem('.quick-pull-branch-name');
|
||||||
|
document.querySelector('.quick-pull-branch-name input').required = false;
|
||||||
}
|
}
|
||||||
|
document.querySelector('#commit-button').textContent = el.getAttribute('data-button-text');
|
||||||
});
|
});
|
||||||
if ($fileNameEl.val()) parts.push($fileNameEl.val());
|
}
|
||||||
$('#tree_path').val(parts.join('/'));
|
|
||||||
};
|
|
||||||
|
|
||||||
const $editFilename = $('#file-name');
|
|
||||||
$editFilename.on('input', function () {
|
|
||||||
const parts = $(this).val().split('/');
|
|
||||||
|
|
||||||
|
const filenameInput = document.querySelector('#file-name');
|
||||||
|
function joinTreePath() {
|
||||||
|
const parts = [];
|
||||||
|
for (const el of document.querySelectorAll('.breadcrumb span.section')) {
|
||||||
|
const link = el.querySelector('a');
|
||||||
|
parts.push(link ? link.textContent : el.textContent);
|
||||||
|
}
|
||||||
|
if (filenameInput.value) {
|
||||||
|
parts.push(filenameInput.value);
|
||||||
|
}
|
||||||
|
document.querySelector('#tree_path').value = parts.join('/');
|
||||||
|
}
|
||||||
|
filenameInput.addEventListener('input', function () {
|
||||||
|
const parts = filenameInput.value.split('/');
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
for (let i = 0; i < parts.length; ++i) {
|
for (let i = 0; i < parts.length; ++i) {
|
||||||
const value = parts[i];
|
const value = parts[i];
|
||||||
if (i < parts.length - 1) {
|
if (i < parts.length - 1) {
|
||||||
if (value.length) {
|
if (value.length) {
|
||||||
$(`<span class="section"><a href="#">${htmlEscape(value)}</a></span>`).insertBefore($(this));
|
$(`<span class="section"><a href="#">${htmlEscape(value)}</a></span>`).insertBefore($(filenameInput));
|
||||||
$('<div class="breadcrumb-divider">/</div>').insertBefore($(this));
|
$('<div class="breadcrumb-divider">/</div>').insertBefore($(filenameInput));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(this).val(value);
|
filenameInput.value = value;
|
||||||
}
|
}
|
||||||
this.setSelectionRange(0, 0);
|
this.setSelectionRange(0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
joinTreePath();
|
||||||
joinTreePath($(this));
|
|
||||||
});
|
});
|
||||||
|
filenameInput.addEventListener('keydown', function (e) {
|
||||||
$editFilename.on('keydown', function (e) {
|
const sections = queryElems('.breadcrumb span.section');
|
||||||
const $section = $('.breadcrumb span.section');
|
const dividers = queryElems('.breadcrumb .breadcrumb-divider');
|
||||||
|
|
||||||
// Jump back to last directory once the filename is empty
|
// Jump back to last directory once the filename is empty
|
||||||
if (e.code === 'Backspace' && getCursorPosition($(this)) === 0 && $section.length > 0) {
|
if (e.code === 'Backspace' && filenameInput.selectionStart === 0 && sections.length > 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const $divider = $('.breadcrumb .breadcrumb-divider');
|
const lastSection = sections[sections.length - 1];
|
||||||
const value = $section.last().find('a').text();
|
const lastDivider = dividers.length ? dividers[dividers.length - 1] : null;
|
||||||
$(this).val(value + $(this).val());
|
const value = lastSection.querySelector('a').textContent;
|
||||||
|
filenameInput.value = value + filenameInput.value;
|
||||||
this.setSelectionRange(value.length, value.length);
|
this.setSelectionRange(value.length, value.length);
|
||||||
$section.last().remove();
|
lastDivider?.remove();
|
||||||
$divider.last().remove();
|
lastSection.remove();
|
||||||
joinTreePath($(this));
|
joinTreePath();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const $editArea = $('.repository.editor textarea#edit_area');
|
const $form = $('.repository.editor .edit.form');
|
||||||
if (!$editArea.length) return;
|
initEditPreviewTab($form);
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const editor = await createCodeEditor($editArea[0], $editFilename[0]);
|
const editor = await createCodeEditor($editArea[0], filenameInput);
|
||||||
|
|
||||||
// Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
|
// Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
|
||||||
// to enable or disable the commit button
|
// to enable or disable the commit button
|
||||||
|
@ -189,11 +189,12 @@ export function initRepoIssueCommentEdit() {
|
|||||||
// Quote reply
|
// Quote reply
|
||||||
$(document).on('click', '.quote-reply', async function (event) {
|
$(document).on('click', '.quote-reply', async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const target = $(this).data('target');
|
const target = this.getAttribute('data-target');
|
||||||
const quote = $(`#${target}`).text().replace(/\n/g, '\n> ');
|
const quote = document.querySelector(`#${target}`).textContent.replace(/\n/g, '\n> ');
|
||||||
const content = `> ${quote}\n\n`;
|
const content = `> ${quote}\n\n`;
|
||||||
|
|
||||||
let editor;
|
let editor;
|
||||||
if ($(this).hasClass('quote-reply-diff')) {
|
if (this.classList.contains('quote-reply-diff')) {
|
||||||
const $replyBtn = $(this).closest('.comment-code-cloud').find('button.comment-form-reply');
|
const $replyBtn = $(this).closest('.comment-code-cloud').find('button.comment-form-reply');
|
||||||
editor = await handleReply($replyBtn);
|
editor = await handleReply($replyBtn);
|
||||||
} else {
|
} else {
|
||||||
|
@ -278,11 +278,12 @@ export function initRepoPullRequestUpdate() {
|
|||||||
|
|
||||||
$('.update-button > .dropdown').dropdown({
|
$('.update-button > .dropdown').dropdown({
|
||||||
onChange(_text, _value, $choice) {
|
onChange(_text, _value, $choice) {
|
||||||
const url = $choice[0].getAttribute('data-do');
|
const choiceEl = $choice[0];
|
||||||
|
const url = choiceEl.getAttribute('data-do');
|
||||||
if (url) {
|
if (url) {
|
||||||
const buttonText = pullUpdateButton.querySelector('.button-text');
|
const buttonText = pullUpdateButton.querySelector('.button-text');
|
||||||
if (buttonText) {
|
if (buttonText) {
|
||||||
buttonText.textContent = $choice.text();
|
buttonText.textContent = choiceEl.textContent;
|
||||||
}
|
}
|
||||||
pullUpdateButton.setAttribute('data-do', url);
|
pullUpdateButton.setAttribute('data-do', url);
|
||||||
}
|
}
|
||||||
@ -567,14 +568,15 @@ export function initRepoPullRequestReview() {
|
|||||||
export function initRepoIssueReferenceIssue() {
|
export function initRepoIssueReferenceIssue() {
|
||||||
// Reference issue
|
// Reference issue
|
||||||
$(document).on('click', '.reference-issue', function (event) {
|
$(document).on('click', '.reference-issue', function (event) {
|
||||||
const $this = $(this);
|
const target = this.getAttribute('data-target');
|
||||||
const content = $(`#${$this.data('target')}`).text();
|
const content = document.querySelector(`#${target}`)?.textContent ?? '';
|
||||||
const poster = $this.data('poster-username');
|
const poster = this.getAttribute('data-poster-username');
|
||||||
const reference = toAbsoluteUrl($this.data('reference'));
|
const reference = toAbsoluteUrl(this.getAttribute('data-reference'));
|
||||||
const $modal = $($this.data('modal'));
|
const modalSelector = this.getAttribute('data-modal');
|
||||||
$modal.find('textarea[name="content"]').val(`${content}\n\n_Originally posted by @${poster} in ${reference}_`);
|
const modal = document.querySelector(modalSelector);
|
||||||
$modal.modal('show');
|
const textarea = modal.querySelector('textarea[name="content"]');
|
||||||
|
textarea.value = `${content}\n\n_Originally posted by @${poster} in ${reference}_`;
|
||||||
|
$(modal).modal('show');
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -272,9 +272,9 @@ export function initRepoCommentForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$list.find('.selected').html(`
|
$list.find('.selected').html(`
|
||||||
<a class="item muted sidebar-item-link" href=${$(this).data('href')}>
|
<a class="item muted sidebar-item-link" href=${htmlEscape(this.getAttribute('href'))}>
|
||||||
${icon}
|
${icon}
|
||||||
${htmlEscape($(this).text())}
|
${htmlEscape(this.textContent)}
|
||||||
</a>
|
</a>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
@ -1,47 +1,46 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {minimatch} from 'minimatch';
|
import {minimatch} from 'minimatch';
|
||||||
import {createMonaco} from './codeeditor.js';
|
import {createMonaco} from './codeeditor.js';
|
||||||
import {onInputDebounce, toggleElem} from '../utils/dom.js';
|
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.js';
|
||||||
import {POST} from '../modules/fetch.js';
|
import {POST} from '../modules/fetch.js';
|
||||||
|
|
||||||
const {appSubUrl, csrfToken} = window.config;
|
const {appSubUrl, csrfToken} = window.config;
|
||||||
|
|
||||||
export function initRepoSettingsCollaboration() {
|
export function initRepoSettingsCollaboration() {
|
||||||
// Change collaborator access mode
|
// Change collaborator access mode
|
||||||
$('.page-content.repository .ui.dropdown.access-mode').each((_, el) => {
|
for (const dropdownEl of queryElems('.page-content.repository .ui.dropdown.access-mode')) {
|
||||||
const $dropdown = $(el);
|
const textEl = dropdownEl.querySelector(':scope > .text');
|
||||||
const $text = $dropdown.find('> .text');
|
$(dropdownEl).dropdown({
|
||||||
$dropdown.dropdown({
|
async action(text, value) {
|
||||||
async action(_text, value) {
|
dropdownEl.classList.add('is-loading', 'loading-icon-2px');
|
||||||
const lastValue = el.getAttribute('data-last-value');
|
const lastValue = dropdownEl.getAttribute('data-last-value');
|
||||||
|
$(dropdownEl).dropdown('hide');
|
||||||
try {
|
try {
|
||||||
el.setAttribute('data-last-value', value);
|
const uid = dropdownEl.getAttribute('data-uid');
|
||||||
$dropdown.dropdown('hide');
|
await POST(dropdownEl.getAttribute('data-url'), {data: new URLSearchParams({uid, 'mode': value})});
|
||||||
const data = new FormData();
|
textEl.textContent = text;
|
||||||
data.append('uid', el.getAttribute('data-uid'));
|
dropdownEl.setAttribute('data-last-value', value);
|
||||||
data.append('mode', value);
|
|
||||||
await POST(el.getAttribute('data-url'), {data});
|
|
||||||
} catch {
|
} catch {
|
||||||
$text.text('(error)'); // prevent from misleading users when error occurs
|
textEl.textContent = '(error)'; // prevent from misleading users when error occurs
|
||||||
el.setAttribute('data-last-value', lastValue);
|
dropdownEl.setAttribute('data-last-value', lastValue);
|
||||||
|
} finally {
|
||||||
|
dropdownEl.classList.remove('is-loading');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChange(_value, text, _$choice) {
|
|
||||||
$text.text(text); // update the text when using keyboard navigating
|
|
||||||
},
|
|
||||||
onHide() {
|
onHide() {
|
||||||
// set to the really selected value, defer to next tick to make sure `action` has finished its work because the calling order might be onHide -> action
|
// set to the really selected value, defer to next tick to make sure `action` has finished
|
||||||
|
// its work because the calling order might be onHide -> action
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const $item = $dropdown.dropdown('get item', el.getAttribute('data-last-value'));
|
const $item = $(dropdownEl).dropdown('get item', dropdownEl.getAttribute('data-last-value'));
|
||||||
if ($item) {
|
if ($item) {
|
||||||
$dropdown.dropdown('set selected', el.getAttribute('data-last-value'));
|
$(dropdownEl).dropdown('set selected', dropdownEl.getAttribute('data-last-value'));
|
||||||
} else {
|
} else {
|
||||||
$text.text('(none)'); // prevent from misleading users when the access mode is undefined
|
textEl.textContent = '(none)'; // prevent from misleading users when the access mode is undefined
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initRepoSettingSearchTeamBox() {
|
export function initRepoSettingSearchTeamBox() {
|
||||||
|
@ -43,7 +43,7 @@ import {
|
|||||||
initGlobalDropzone,
|
initGlobalDropzone,
|
||||||
initGlobalEnterQuickSubmit,
|
initGlobalEnterQuickSubmit,
|
||||||
initGlobalFormDirtyLeaveConfirm,
|
initGlobalFormDirtyLeaveConfirm,
|
||||||
initGlobalLinkActions,
|
initGlobalDeleteButton,
|
||||||
initHeadNavbarContentToggle,
|
initHeadNavbarContentToggle,
|
||||||
} from './features/common-global.js';
|
} from './features/common-global.js';
|
||||||
import {initRepoTopicBar} from './features/repo-home.js';
|
import {initRepoTopicBar} from './features/repo-home.js';
|
||||||
@ -103,7 +103,7 @@ onDomReady(() => {
|
|||||||
initGlobalDropzone();
|
initGlobalDropzone();
|
||||||
initGlobalEnterQuickSubmit();
|
initGlobalEnterQuickSubmit();
|
||||||
initGlobalFormDirtyLeaveConfirm();
|
initGlobalFormDirtyLeaveConfirm();
|
||||||
initGlobalLinkActions();
|
initGlobalDeleteButton();
|
||||||
|
|
||||||
initCommonOrganization();
|
initCommonOrganization();
|
||||||
initCommonIssueListQuickGoto();
|
initCommonIssueListQuickGoto();
|
||||||
|
Loading…
Reference in New Issue
Block a user