gitea源码

repo-wiki.ts 3.6KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
  2. import {fomanticMobileScreen} from '../modules/fomantic.ts';
  3. import {POST} from '../modules/fetch.ts';
  4. import type {ComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
  5. import {html, htmlRaw} from '../utils/html.ts';
  6. async function initRepoWikiFormEditor() {
  7. const editArea = document.querySelector<HTMLTextAreaElement>('.repository.wiki .combo-markdown-editor textarea');
  8. if (!editArea) return;
  9. const form = document.querySelector('.repository.wiki.new .ui.form');
  10. const editorContainer = form.querySelector<HTMLElement>('.combo-markdown-editor');
  11. let editor: ComboMarkdownEditor;
  12. let renderRequesting = false;
  13. let lastContent: string = '';
  14. const renderEasyMDEPreview = async function () {
  15. if (renderRequesting) return;
  16. const previewFull = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active');
  17. const previewSide = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active-side');
  18. const previewTarget = previewSide || previewFull;
  19. const newContent = editArea.value;
  20. if (editor && previewTarget && lastContent !== newContent) {
  21. renderRequesting = true;
  22. const formData = new FormData();
  23. formData.append('mode', editor.previewMode);
  24. formData.append('context', editor.previewContext);
  25. formData.append('text', newContent);
  26. try {
  27. const response = await POST(editor.previewUrl, {data: formData});
  28. const data = await response.text();
  29. lastContent = newContent;
  30. previewTarget.innerHTML = html`<div class="render-content markup ui segment">${htmlRaw(data)}</div>`;
  31. } catch (error) {
  32. console.error('Error rendering preview:', error);
  33. } finally {
  34. renderRequesting = false;
  35. setTimeout(renderEasyMDEPreview, 1000);
  36. }
  37. } else {
  38. setTimeout(renderEasyMDEPreview, 1000);
  39. }
  40. };
  41. renderEasyMDEPreview();
  42. editor = await initComboMarkdownEditor(editorContainer, {
  43. // EasyMDE has some problems of height definition, it has inline style height 300px by default, so we also use inline styles to override it.
  44. // And another benefit is that we only need to write the style once for both editors.
  45. // TODO: Move height style to CSS after EasyMDE removal.
  46. editorHeights: {minHeight: '300px', height: 'calc(100vh - 600px)'},
  47. easyMDEOptions: {
  48. previewRender: (_content, previewTarget) => previewTarget.innerHTML, // disable builtin preview render
  49. toolbar: ['bold', 'italic', 'strikethrough', '|',
  50. 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|',
  51. 'gitea-code-inline', 'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|',
  52. 'unordered-list', 'ordered-list', '|',
  53. 'link', 'image', 'table', 'horizontal-rule', '|',
  54. 'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea',
  55. ] as any, // to use custom toolbar buttons
  56. },
  57. });
  58. form.addEventListener('submit', (e) => {
  59. if (!validateTextareaNonEmpty(editArea)) {
  60. e.preventDefault();
  61. e.stopPropagation();
  62. }
  63. });
  64. }
  65. function collapseWikiTocForMobile(collapse: boolean) {
  66. if (collapse) {
  67. document.querySelector('.wiki-content-toc details')?.removeAttribute('open');
  68. }
  69. }
  70. export function initRepoWikiForm() {
  71. if (!document.querySelector('.page-content.repository.wiki')) return;
  72. fomanticMobileScreen.addEventListener('change', (e) => collapseWikiTocForMobile(e.matches));
  73. collapseWikiTocForMobile(fomanticMobileScreen.matches);
  74. initRepoWikiFormEditor();
  75. }