2022-01-29 00:00:11 +03:00
import $ from 'jquery' ;
2021-11-17 21:08:25 +03:00
import { htmlEscape } from 'escape-goat' ;
2021-10-16 20:28:04 +03:00
import { createCodeEditor } from './codeeditor.js' ;
2023-02-19 07:06:14 +03:00
import { hideElem , showElem } from '../utils/dom.js' ;
2023-04-12 06:03:23 +03:00
import { initMarkupContent } from '../markup/content.js' ;
import { attachRefIssueContextPopup } from './contextpopup.js' ;
2021-10-16 20:28:04 +03:00
2021-10-21 10:37:43 +03:00
const { csrfToken } = window . config ;
2021-10-16 20:28:04 +03:00
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' , function ( ) {
const $this = $ ( this ) ;
let context = ` ${ $this . data ( 'context' ) } / ` ;
2023-03-24 09:12:23 +03:00
const mode = $this . data ( 'markup-mode' ) || 'comment' ;
2021-10-16 20:28:04 +03:00
const treePathEl = $form . find ( 'input#tree_path' ) ;
if ( treePathEl . length > 0 ) {
context += treePathEl . val ( ) ;
}
context = context . substring ( 0 , context . lastIndexOf ( '/' ) ) ;
$ . post ( $this . data ( 'url' ) , {
2021-10-21 10:37:43 +03:00
_csrf : csrfToken ,
2021-10-16 20:28:04 +03:00
mode ,
context ,
2021-11-09 12:27:25 +03:00
text : $form . find ( ` .tab[data-tab=" ${ $tabMenu . data ( 'write' ) } "] textarea ` ) . val ( ) ,
2023-03-24 09:12:23 +03:00
file _path : treePathEl . val ( ) ,
2021-10-16 20:28:04 +03:00
} , ( data ) => {
const $previewPanel = $form . find ( ` .tab[data-tab=" ${ $tabMenu . data ( 'preview' ) } "] ` ) ;
2023-04-12 06:03:23 +03:00
renderPreviewPanelContent ( $previewPanel , data ) ;
2021-10-16 20:28:04 +03:00
} ) ;
} ) ;
}
}
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' ) , {
2021-10-21 10:37:43 +03:00
_csrf : csrfToken ,
2021-10-16 20:28:04 +03:00
context : $this . data ( 'context' ) ,
2021-11-09 12:27:25 +03:00
content : $form . find ( ` .tab[data-tab=" ${ $tabMenu . data ( 'write' ) } "] textarea ` ) . val ( ) ,
2021-10-16 20:28:04 +03:00
} , ( 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 ;
}
2021-11-09 12:27:25 +03:00
export function initRepoEditor ( ) {
2021-10-16 20:28:04 +03:00
initEditorForm ( ) ;
$ ( '.js-quick-pull-choice-option' ) . on ( 'change' , function ( ) {
if ( $ ( this ) . val ( ) === 'commit-to-new-branch' ) {
2023-02-19 07:06:14 +03:00
showElem ( $ ( '.quick-pull-branch-name' ) ) ;
2021-10-16 20:28:04 +03:00
$ ( '.quick-pull-branch-name input' ) . prop ( 'required' , true ) ;
} else {
2023-02-19 07:06:14 +03:00
hideElem ( $ ( '.quick-pull-branch-name' ) ) ;
2021-10-16 20:28:04 +03:00
$ ( '.quick-pull-branch-name input' ) . prop ( 'required' , false ) ;
}
$ ( '#commit-button' ) . text ( $ ( this ) . attr ( 'button_text' ) ) ;
} ) ;
2023-03-04 01:28:20 +03:00
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 ( '/' ) ) ;
} ;
2021-10-16 20:28:04 +03:00
const $editFilename = $ ( '#file-name' ) ;
2023-03-04 01:28:20 +03:00
$editFilename . on ( 'input' , function ( ) {
const parts = $ ( this ) . val ( ) . split ( '/' ) ;
2021-10-16 20:28:04 +03:00
2023-03-04 01:28:20 +03:00
if ( parts . length > 1 ) {
2021-10-16 20:28:04 +03:00
for ( let i = 0 ; i < parts . length ; ++ i ) {
2023-03-04 01:28:20 +03:00
const value = parts [ i ] ;
2021-10-16 20:28:04 +03:00
if ( i < parts . length - 1 ) {
if ( value . length ) {
2021-11-17 21:08:25 +03:00
$ ( ` <span class="section"><a href="#"> ${ htmlEscape ( value ) } </a></span> ` ) . insertBefore ( $ ( this ) ) ;
2023-08-16 03:08:23 +03:00
$ ( '<div class="breadcrumb-divider">/</div>' ) . insertBefore ( $ ( this ) ) ;
2021-10-16 20:28:04 +03:00
}
} else {
$ ( this ) . val ( value ) ;
}
2023-03-04 01:28:20 +03:00
this . setSelectionRange ( 0 , 0 ) ;
2021-10-16 20:28:04 +03:00
}
}
2023-03-04 01:28:20 +03:00
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 ( ) ;
2023-08-16 03:08:23 +03:00
const $divider = $ ( '.breadcrumb .breadcrumb-divider' ) ;
2023-03-04 01:28:20 +03:00
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 ) ) ;
}
} ) ;
2021-10-16 20:28:04 +03:00
const $editArea = $ ( '.repository.editor textarea#edit_area' ) ;
if ( ! $editArea . length ) return ;
2021-11-09 12:27:25 +03:00
( async ( ) => {
2023-03-24 09:12:23 +03:00
const editor = await createCodeEditor ( $editArea [ 0 ] , $editFilename [ 0 ] ) ;
2021-10-16 20:28:04 +03:00
2021-11-09 12:27:25 +03:00
// 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' ;
2021-10-16 20:28:04 +03:00
2021-11-09 12:27:25 +03:00
// Disabling the button at the start
if ( $ ( 'input[name="page_has_posted"]' ) . val ( ) !== 'true' ) {
$commitButton . prop ( 'disabled' , true ) ;
2021-10-16 20:28:04 +03:00
}
2021-11-09 12:27:25 +03:00
// 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 ) ;
} ,
} ) ;
2021-10-16 20:28:04 +03:00
2021-11-09 12:27:25 +03:00
// 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 ) ;
2021-10-16 20:28:04 +03:00
}
2021-11-09 12:27:25 +03:00
$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 ( ) ;
}
} ) ;
} ) ( ) ;
2021-10-16 20:28:04 +03:00
}
2023-04-12 06:03:23 +03:00
export function renderPreviewPanelContent ( $panelPreviewer , data ) {
$panelPreviewer . html ( data ) ;
initMarkupContent ( ) ;
const refIssues = $panelPreviewer . find ( 'p .ref-issue' ) ;
attachRefIssueContextPopup ( refIssues ) ;
}