diff options
Diffstat (limited to 'web_src/js/features/repo-editor.js')
-rw-r--r-- | web_src/js/features/repo-editor.js | 180 |
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(); + } + }); +} |