aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js/features/repo-editor.js
diff options
context:
space:
mode:
Diffstat (limited to 'web_src/js/features/repo-editor.js')
-rw-r--r--web_src/js/features/repo-editor.js180
1 files changed, 180 insertions, 0 deletions
diff --git a/web_src/js/features/repo-editor.js b/web_src/js/features/repo-editor.js
new file mode 100644
index 0000000000..831b621fde
--- /dev/null
+++ b/web_src/js/features/repo-editor.js
@@ -0,0 +1,180 @@
+import {initMarkupContent} from '../markup/content.js';
+import {createCodeEditor} from './codeeditor.js';
+
+const {csrf} = window.config;
+
+let previewFileModes;
+
+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) {
+ previewFileModes = $previewTab.data('preview-file-modes').split(',');
+ $previewTab.on('click', function () {
+ const $this = $(this);
+ let context = `${$this.data('context')}/`;
+ const mode = $this.data('markdown-mode') || 'comment';
+ const treePathEl = $form.find('input#tree_path');
+ if (treePathEl.length > 0) {
+ context += treePathEl.val();
+ }
+ context = context.substring(0, context.lastIndexOf('/'));
+ $.post($this.data('url'), {
+ _csrf: csrf,
+ mode,
+ context,
+ text: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val()
+ }, (data) => {
+ const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`);
+ $previewPanel.html(data);
+ initMarkupContent();
+ });
+ });
+ }
+}
+
+function initEditDiffTab($form) {
+ const $tabMenu = $form.find('.tabular.menu');
+ $tabMenu.find('.item').tab();
+ $tabMenu.find(`.item[data-tab="${$tabMenu.data('diff')}"]`).on('click', function () {
+ const $this = $(this);
+ $.post($this.data('url'), {
+ _csrf: csrf,
+ context: $this.data('context'),
+ content: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val()
+ }, (data) => {
+ const $diffPreviewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('diff')}"]`);
+ $diffPreviewPanel.html(data);
+ });
+ });
+}
+
+function initEditorForm() {
+ if ($('.repository .edit.form').length === 0) {
+ return;
+ }
+
+ initEditPreviewTab($('.repository .edit.form'));
+ initEditDiffTab($('.repository .edit.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 async function initRepoEditor() {
+ initEditorForm();
+
+ $('.js-quick-pull-choice-option').on('change', function () {
+ if ($(this).val() === 'commit-to-new-branch') {
+ $('.quick-pull-branch-name').show();
+ $('.quick-pull-branch-name input').prop('required', true);
+ } else {
+ $('.quick-pull-branch-name').hide();
+ $('.quick-pull-branch-name input').prop('required', false);
+ }
+ $('#commit-button').text($(this).attr('button_text'));
+ });
+
+ const $editFilename = $('#file-name');
+ $editFilename.on('keyup', function (e) {
+ const $section = $('.breadcrumb span.section');
+ const $divider = $('.breadcrumb div.divider');
+ let value;
+ let parts;
+
+ if (e.keyCode === 8 && getCursorPosition($(this)) === 0 && $section.length > 0) {
+ value = $section.last().find('a').text();
+ $(this).val(value + $(this).val());
+ $(this)[0].setSelectionRange(value.length, value.length);
+ $section.last().remove();
+ $divider.last().remove();
+ }
+ if (e.keyCode === 191) {
+ parts = $(this).val().split('/');
+ for (let i = 0; i < parts.length; ++i) {
+ value = parts[i];
+ if (i < parts.length - 1) {
+ if (value.length) {
+ $(`<span class="section"><a href="#">${value}</a></span>`).insertBefore($(this));
+ $('<div class="divider"> / </div>').insertBefore($(this));
+ }
+ } else {
+ $(this).val(value);
+ }
+ $(this)[0].setSelectionRange(0, 0);
+ }
+ }
+ 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 ($(this).val()) parts.push($(this).val());
+ $('#tree_path').val(parts.join('/'));
+ }).trigger('keyup');
+
+ const $editArea = $('.repository.editor textarea#edit_area');
+ if (!$editArea.length) return;
+
+ const editor = await createCodeEditor($editArea[0], $editFilename[0], previewFileModes);
+
+ // Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
+ // to enable or disable the commit button
+ const $commitButton = $('#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.prop('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.prop('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.on('click', (event) => {
+ // A modal which asks if an empty file should be committed
+ if ($editArea.val().length === 0) {
+ $('#edit-empty-content-modal').modal({
+ onApprove() {
+ $('.edit.form').trigger('submit');
+ }
+ }).modal('show');
+ event.preventDefault();
+ }
+ });
+}