|
698 | 698 | } |
699 | 699 | } |
700 | 700 |
|
| 701 | + // Indent/outdent handlers |
| 702 | + function indentLines() { |
| 703 | + var textarea = textareaRef.current ? textareaRef.current.querySelector( 'textarea' ) : null; |
| 704 | + if ( ! textarea ) return; |
| 705 | + |
| 706 | + var text = content || ''; |
| 707 | + var start = textarea.selectionStart; |
| 708 | + var end = textarea.selectionEnd; |
| 709 | + |
| 710 | + // Find line boundaries |
| 711 | + var lineStart = start; |
| 712 | + while ( lineStart > 0 && text[ lineStart - 1 ] !== '\n' ) { |
| 713 | + lineStart--; |
| 714 | + } |
| 715 | + var lineEnd = end; |
| 716 | + while ( lineEnd < text.length && text[ lineEnd ] !== '\n' ) { |
| 717 | + lineEnd++; |
| 718 | + } |
| 719 | + |
| 720 | + // Get selected lines and indent each |
| 721 | + var selectedText = text.substring( lineStart, lineEnd ); |
| 722 | + var indentedText = selectedText.split( '\n' ).map( function( line ) { |
| 723 | + return ' ' + line; |
| 724 | + } ).join( '\n' ); |
| 725 | + |
| 726 | + var newText = text.substring( 0, lineStart ) + indentedText + text.substring( lineEnd ); |
| 727 | + var lineCount = selectedText.split( '\n' ).length; |
| 728 | + var newStart = start + 4; |
| 729 | + var newEnd = end + ( lineCount * 4 ); |
| 730 | + |
| 731 | + setAttributes( { content: newText } ); |
| 732 | + requestAnimationFrame( function() { |
| 733 | + textarea.focus( { preventScroll: true } ); |
| 734 | + textarea.setSelectionRange( newStart, newEnd ); |
| 735 | + } ); |
| 736 | + } |
| 737 | + |
| 738 | + function outdentLines() { |
| 739 | + var textarea = textareaRef.current ? textareaRef.current.querySelector( 'textarea' ) : null; |
| 740 | + if ( ! textarea ) return; |
| 741 | + |
| 742 | + var text = content || ''; |
| 743 | + var start = textarea.selectionStart; |
| 744 | + var end = textarea.selectionEnd; |
| 745 | + |
| 746 | + // Find line boundaries |
| 747 | + var lineStart = start; |
| 748 | + while ( lineStart > 0 && text[ lineStart - 1 ] !== '\n' ) { |
| 749 | + lineStart--; |
| 750 | + } |
| 751 | + var lineEnd = end; |
| 752 | + while ( lineEnd < text.length && text[ lineEnd ] !== '\n' ) { |
| 753 | + lineEnd++; |
| 754 | + } |
| 755 | + |
| 756 | + // Get selected lines and outdent each |
| 757 | + var selectedText = text.substring( lineStart, lineEnd ); |
| 758 | + var removedTotal = 0; |
| 759 | + var removedFirst = 0; |
| 760 | + var isFirst = true; |
| 761 | + var outdentedText = selectedText.split( '\n' ).map( function( line ) { |
| 762 | + var removed = 0; |
| 763 | + // Remove up to 4 spaces or 1 tab |
| 764 | + if ( line.startsWith( ' ' ) ) { |
| 765 | + line = line.substring( 4 ); |
| 766 | + removed = 4; |
| 767 | + } else if ( line.startsWith( '\t' ) ) { |
| 768 | + line = line.substring( 1 ); |
| 769 | + removed = 1; |
| 770 | + } else if ( line.startsWith( ' ' ) ) { |
| 771 | + line = line.substring( 3 ); |
| 772 | + removed = 3; |
| 773 | + } else if ( line.startsWith( ' ' ) ) { |
| 774 | + line = line.substring( 2 ); |
| 775 | + removed = 2; |
| 776 | + } else if ( line.startsWith( ' ' ) ) { |
| 777 | + line = line.substring( 1 ); |
| 778 | + removed = 1; |
| 779 | + } |
| 780 | + if ( isFirst ) { |
| 781 | + removedFirst = removed; |
| 782 | + isFirst = false; |
| 783 | + } |
| 784 | + removedTotal += removed; |
| 785 | + return line; |
| 786 | + } ).join( '\n' ); |
| 787 | + |
| 788 | + var newText = text.substring( 0, lineStart ) + outdentedText + text.substring( lineEnd ); |
| 789 | + var newStart = Math.max( lineStart, start - removedFirst ); |
| 790 | + var newEnd = Math.max( newStart, end - removedTotal ); |
| 791 | + |
| 792 | + setAttributes( { content: newText } ); |
| 793 | + requestAnimationFrame( function() { |
| 794 | + textarea.focus( { preventScroll: true } ); |
| 795 | + textarea.setSelectionRange( newStart, newEnd ); |
| 796 | + } ); |
| 797 | + } |
| 798 | + |
701 | 799 | // Keyboard shortcut handler for textarea |
702 | 800 | function handleTextareaKeyDown( e ) { |
| 801 | + // Handle Tab/Shift+Tab for indent/outdent |
| 802 | + if ( e.key === 'Tab' ) { |
| 803 | + e.preventDefault(); |
| 804 | + if ( e.shiftKey ) { |
| 805 | + outdentLines(); |
| 806 | + } else { |
| 807 | + indentLines(); |
| 808 | + } |
| 809 | + return; |
| 810 | + } |
| 811 | + |
703 | 812 | const isMod = e.ctrlKey || e.metaKey; |
704 | 813 | if ( ! isMod ) return; |
705 | 814 |
|
|
1030 | 1139 | wp.element.createElement( 'div', null, wp.element.createElement( 'kbd', null, 'Ctrl+,' ), ' Subscript' ), |
1031 | 1140 | wp.element.createElement( 'div', null, wp.element.createElement( 'kbd', null, 'Ctrl+Shift+H' ), ' Highlight' ), |
1032 | 1141 | wp.element.createElement( 'div', null, wp.element.createElement( 'kbd', null, 'Ctrl+Shift+X' ), ' Strikethrough' ), |
| 1142 | + wp.element.createElement( 'div', null, wp.element.createElement( 'kbd', null, 'Tab' ), ' Indent' ), |
| 1143 | + wp.element.createElement( 'div', null, wp.element.createElement( 'kbd', null, 'Shift+Tab' ), ' Outdent' ), |
1033 | 1144 | wp.element.createElement( 'div', null, wp.element.createElement( 'kbd', null, 'ESC' ), ' Exit preview' ) |
1034 | 1145 | ) |
1035 | 1146 | ), |
|
0 commit comments