forked from Shiloh/githaven
8fe26fb314
This pattern comes of often during review, so let's fix it once and for all. Did not test, but changes are trivial enough imho.
185 lines
6.0 KiB
JavaScript
185 lines
6.0 KiB
JavaScript
import $ from 'jquery';
|
|
import {htmlEscape} from 'escape-goat';
|
|
import {createCodeEditor} from './codeeditor.js';
|
|
import {hideElem, showElem} from '../utils/dom.js';
|
|
import {initMarkupContent} from '../markup/content.js';
|
|
import {attachRefIssueContextPopup} from './contextpopup.js';
|
|
import {POST} from '../modules/fetch.js';
|
|
|
|
function initEditPreviewTab($form) {
|
|
const $tabMenu = $form.find('.tabular.menu');
|
|
$tabMenu.find('.item').tab();
|
|
const $previewTab = $tabMenu.find(`.item[data-tab="${$tabMenu.data('preview')}"]`);
|
|
if ($previewTab.length) {
|
|
$previewTab.on('click', async function () {
|
|
const $this = $(this);
|
|
let context = `${$this.data('context')}/`;
|
|
const mode = $this.data('markup-mode') || 'comment';
|
|
const $treePathEl = $form.find('input#tree_path');
|
|
if ($treePathEl.length > 0) {
|
|
context += $treePathEl.val();
|
|
}
|
|
context = context.substring(0, context.lastIndexOf('/'));
|
|
|
|
const formData = new FormData();
|
|
formData.append('mode', mode);
|
|
formData.append('context', context);
|
|
formData.append('text', $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val());
|
|
formData.append('file_path', $treePathEl.val());
|
|
try {
|
|
const response = await POST($this.data('url'), {data: formData});
|
|
const data = await response.text();
|
|
const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`);
|
|
renderPreviewPanelContent($previewPanel, data);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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() {
|
|
initEditorForm();
|
|
|
|
$('.js-quick-pull-choice-option').on('change', function () {
|
|
if ($(this).val() === 'commit-to-new-branch') {
|
|
showElem($('.quick-pull-branch-name'));
|
|
document.querySelector('.quick-pull-branch-name input').required = true;
|
|
} else {
|
|
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 {
|
|
parts.push($element.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('/');
|
|
|
|
if (parts.length > 1) {
|
|
for (let i = 0; i < parts.length; ++i) {
|
|
const value = parts[i];
|
|
if (i < parts.length - 1) {
|
|
if (value.length) {
|
|
$(`<span class="section"><a href="#">${htmlEscape(value)}</a></span>`).insertBefore($(this));
|
|
$('<div class="breadcrumb-divider">/</div>').insertBefore($(this));
|
|
}
|
|
} else {
|
|
$(this).val(value);
|
|
}
|
|
this.setSelectionRange(0, 0);
|
|
}
|
|
}
|
|
|
|
joinTreePath($(this));
|
|
});
|
|
|
|
$editFilename.on('keydown', function (e) {
|
|
const $section = $('.breadcrumb span.section');
|
|
|
|
// Jump back to last directory once the filename is empty
|
|
if (e.code === 'Backspace' && getCursorPosition($(this)) === 0 && $section.length > 0) {
|
|
e.preventDefault();
|
|
const $divider = $('.breadcrumb .breadcrumb-divider');
|
|
const value = $section.last().find('a').text();
|
|
$(this).val(value + $(this).val());
|
|
this.setSelectionRange(value.length, value.length);
|
|
$section.last().remove();
|
|
$divider.last().remove();
|
|
joinTreePath($(this));
|
|
}
|
|
});
|
|
|
|
const $editArea = $('.repository.editor textarea#edit_area');
|
|
if (!$editArea.length) return;
|
|
|
|
(async () => {
|
|
const editor = await createCodeEditor($editArea[0], $editFilename[0]);
|
|
|
|
// Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
|
|
// to enable or disable the commit button
|
|
const commitButton = document.getElementById('commit-button');
|
|
const $editForm = $('.ui.edit.form');
|
|
const dirtyFileClass = 'dirty-file';
|
|
|
|
// Disabling the button at the start
|
|
if ($('input[name="page_has_posted"]').val() !== 'true') {
|
|
commitButton.disabled = true;
|
|
}
|
|
|
|
// Registering a custom listener for the file path and the file content
|
|
$editForm.areYouSure({
|
|
silent: true,
|
|
dirtyClass: dirtyFileClass,
|
|
fieldSelector: ':input:not(.commit-form-wrapper :input)',
|
|
change() {
|
|
const dirty = $(this).hasClass(dirtyFileClass);
|
|
commitButton.disabled = !dirty;
|
|
},
|
|
});
|
|
|
|
// Update the editor from query params, if available,
|
|
// only after the dirtyFileClass initialization
|
|
const params = new URLSearchParams(window.location.search);
|
|
const value = params.get('value');
|
|
if (value) {
|
|
editor.setValue(value);
|
|
}
|
|
|
|
commitButton?.addEventListener('click', (e) => {
|
|
// A modal which asks if an empty file should be committed
|
|
if (!$editArea.val()) {
|
|
$('#edit-empty-content-modal').modal({
|
|
onApprove() {
|
|
$('.edit.form').trigger('submit');
|
|
},
|
|
}).modal('show');
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
})();
|
|
}
|
|
|
|
export function renderPreviewPanelContent($panelPreviewer, data) {
|
|
$panelPreviewer.html(data);
|
|
initMarkupContent();
|
|
|
|
const $refIssues = $panelPreviewer.find('p .ref-issue');
|
|
attachRefIssueContextPopup($refIssues);
|
|
}
|