@@ -79,6 +79,7 @@ type Style = {
7979 replaceNext ?: string
8080 scanFor ?: string
8181 orderedList ?: boolean
82+ unorderedList ?: boolean
8283 prefixSpace ?: boolean
8384}
8485
@@ -205,7 +206,7 @@ if (!window.customElements.get('md-image')) {
205206class MarkdownUnorderedListButtonElement extends MarkdownButtonElement {
206207 constructor ( ) {
207208 super ( )
208- styles . set ( this , { prefix : '- ' , multiline : true , surroundWithNewlines : true } )
209+ styles . set ( this , { prefix : '- ' , multiline : true , unorderedList : true } )
209210 }
210211}
211212
@@ -421,8 +422,8 @@ function styleSelectedText(textarea: HTMLTextAreaElement, styleArgs: StyleArgs)
421422 const text = textarea . value . slice ( textarea . selectionStart , textarea . selectionEnd )
422423
423424 let result
424- if ( styleArgs . orderedList ) {
425- result = orderedList ( textarea )
425+ if ( styleArgs . orderedList || styleArgs . unorderedList ) {
426+ result = listStyle ( textarea , styleArgs )
426427 } else if ( styleArgs . multiline && isMultipleLines ( text ) ) {
427428 result = multilineStyle ( textarea , styleArgs )
428429 } else {
@@ -432,6 +433,17 @@ function styleSelectedText(textarea: HTMLTextAreaElement, styleArgs: StyleArgs)
432433 insertText ( textarea , result )
433434}
434435
436+ export function selectionIndexForLine ( lines : string [ ] , line : number ) : SelectionRange | null {
437+ let counter = 0
438+ for ( let index = 0 ; index < lines . length ; index ++ ) {
439+ if ( index === line ) {
440+ return { selectionStart : counter , selectionEnd : counter + lines [ index ] . length , text : '' }
441+ }
442+ counter += lines [ index ] . length + 1
443+ }
444+ return null
445+ }
446+
435447function expandSelectedText (
436448 textarea : HTMLTextAreaElement ,
437449 prefixToUse : string ,
@@ -587,6 +599,79 @@ function multilineStyle(textarea: HTMLTextAreaElement, arg: StyleArgs) {
587599 return { text, selectionStart, selectionEnd}
588600}
589601
602+ function undoOrderedListStyle ( textarea : HTMLTextAreaElement ) : string [ ] {
603+ const text = textarea . value . slice ( textarea . selectionStart , textarea . selectionEnd )
604+ const lines = text . split ( '\n' )
605+ const orderedListRegex = / ^ \d + \. \s + /
606+ const result = lines
607+ const shouldUndoOrderedList = lines . every ( line => orderedListRegex . test ( line ) )
608+ if ( shouldUndoOrderedList ) {
609+ return lines . map ( line => line . replace ( orderedListRegex , '' ) )
610+ }
611+ return result
612+ }
613+
614+ function undoUnorderedListStyle ( textarea : HTMLTextAreaElement ) : string [ ] {
615+ const text = textarea . value . slice ( textarea . selectionStart , textarea . selectionEnd )
616+ const lines = text . split ( '\n' )
617+ const unorderedListPrefix = '- '
618+ const shouldUndoUnorderedList = lines . every ( line => line . startsWith ( unorderedListPrefix ) )
619+ const result = lines
620+ if ( shouldUndoUnorderedList ) {
621+ return lines . map ( line => line . slice ( unorderedListPrefix . length , line . length ) )
622+ }
623+ return result
624+ }
625+
626+ function listStyle ( textarea : HTMLTextAreaElement , style : StyleArgs ) : SelectionRange {
627+ const noInitialSelection = textarea . selectionStart === textarea . selectionEnd
628+ let selectionStart = textarea . selectionStart
629+ let selectionEnd = textarea . selectionEnd
630+ let lines : string [ ] = [ ]
631+ let text = textarea . value . slice ( textarea . selectionStart , textarea . selectionEnd )
632+ let startOfLine , endOfLine
633+
634+ undoOrderedListStyle ( textarea )
635+ undoUnorderedListStyle ( textarea )
636+
637+ const prefix = '- '
638+
639+ //let selectedText = expandSelectedText(textarea, prefix, '', style.multiline)
640+
641+ // Style only the selected line
642+ if ( noInitialSelection ) {
643+ const linesBefore = textarea . value . slice ( 0 , textarea . selectionStart ) . split ( / \n / )
644+ lines = textarea . value . split ( '\n' )
645+
646+ const currentLine = linesBefore . length - 1
647+ const currentLineText = lines [ currentLine ]
648+
649+ // Select whole line
650+ const range = selectionIndexForLine ( lines , currentLine )
651+ if ( range ) {
652+ textarea . selectionStart = range . selectionStart ?? 0
653+ textarea . selectionEnd = range . selectionEnd ?? 0
654+ }
655+
656+ // line with caret
657+ //lines[linesBefore.length - 1] = prefix + linesBefore[linesBefore.length - 1]
658+
659+ text = prefix + currentLineText
660+
661+ // if (style.surroundWithNewlines) {
662+ const { newlinesToAppend, newlinesToPrepend} = newlinesToSurroundSelectedText ( textarea )
663+ selectionStart = selectionStart + prefix . length + 1
664+ selectionEnd = selectionStart
665+ text = newlinesToAppend + text + newlinesToPrepend
666+
667+ return { text, selectionStart, selectionEnd}
668+ }
669+
670+ text = lines . join ( '\n' )
671+
672+ return { text, selectionStart, selectionEnd}
673+ }
674+
590675function orderedList ( textarea : HTMLTextAreaElement ) : SelectionRange {
591676 const orderedListRegex = / ^ \d + \. \s + /
592677 const noInitialSelection = textarea . selectionStart === textarea . selectionEnd
@@ -638,6 +723,7 @@ interface StyleArgs {
638723 scanFor : string
639724 surroundWithNewlines : boolean
640725 orderedList : boolean
726+ unorderedList : boolean
641727 trimFirst : boolean
642728}
643729
@@ -668,6 +754,7 @@ function applyStyle(button: Element, stylesToApply: Style) {
668754 scanFor : '' ,
669755 surroundWithNewlines : false ,
670756 orderedList : false ,
757+ unorderedList : false ,
671758 trimFirst : false
672759 }
673760
0 commit comments