Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 1x 1x 1x 1x 1x 68x 27x 33x 27x 6x 6x 6x 1x 5x 21x 4x 4x 4x 12x 4x 4x 4x 4x 4x 4x 4x 4x 17x 37x 17x 9x 9x 9x 8x 8x 8x 8x 8x 3x 5x 1x 1x 4x 22x 22x | import { setModelIndentation } from 'roosterjs-content-model-api'; import { createSelectionMarker, createText, mutateBlock, mutateSegment, } from 'roosterjs-content-model-dom'; import type { FormatContentModelContext, ReadonlyContentModelDocument, ReadonlyContentModelParagraph, } from 'roosterjs-content-model-types'; const tabSpaces = ' '; const space = ' '; /** * @internal The handleTabOnParagraph function will handle the tab key in following scenarios: * 1. When the selection is collapsed and the cursor is at the end of a paragraph, add 4 spaces. * 2. When the selection is collapsed and the cursor is at the start of a paragraph, call setModelIndention function to indent the whole paragraph * 3. When the selection is collapsed and the cursor is at the middle of a paragraph, add 4 spaces. * 4. When the selection is not collapsed, replace the selected range with a single space. * 5. When the selection is not collapsed, but all segments are selected, call setModelIndention function to indent the whole paragraph The handleTabOnParagraph function will handle the shift + tab key in a indented paragraph in following scenarios: * 1. When the selection is collapsed and the cursor is at the end of a paragraph, remove 4 spaces. * 2. When the selection is collapsed and the cursor is at the start of a paragraph, call setModelIndention function to outdent the whole paragraph * 3. When the selection is collapsed and the cursor is at the middle of a paragraph, remove 4 spaces. * 4. When the selection is not collapsed, replace the selected range with a 4 space. * 5. When the selection is not collapsed, but all segments are selected, call setModelIndention function to outdent the whole paragraph */ export function handleTabOnParagraph( model: ReadonlyContentModelDocument, paragraph: ReadonlyContentModelParagraph, rawEvent: KeyboardEvent, context?: FormatContentModelContext ) { const selectedSegments = paragraph.segments.filter(segment => segment.isSelected); const isCollapsed = selectedSegments.length === 1 && selectedSegments[0].segmentType === 'SelectionMarker'; const isAllSelected = paragraph.segments.every(segment => segment.isSelected); if ((paragraph.segments[0].segmentType === 'SelectionMarker' && isCollapsed) || isAllSelected) { const { marginLeft, marginRight, direction } = paragraph.format; const isRtl = direction === 'rtl'; if ( rawEvent.shiftKey && ((!isRtl && (!marginLeft || marginLeft == '0px')) || (isRtl && (!marginRight || marginRight == '0px'))) ) { return false; } setModelIndentation( model, rawEvent.shiftKey ? 'outdent' : 'indent', undefined /*length*/, context ); } else { if (!isCollapsed) { let firstSelectedSegmentIndex: number | undefined = undefined; let lastSelectedSegmentIndex: number | undefined = undefined; paragraph.segments.forEach((segment, index) => { if (segment.isSelected) { Eif (!firstSelectedSegmentIndex) { firstSelectedSegmentIndex = index; } lastSelectedSegmentIndex = index; } }); Eif (firstSelectedSegmentIndex && lastSelectedSegmentIndex) { const firstSelectedSegment = paragraph.segments[firstSelectedSegmentIndex]; const spaceText = createText( rawEvent.shiftKey ? tabSpaces : space, firstSelectedSegment.format ); const marker = createSelectionMarker(firstSelectedSegment.format); mutateBlock(paragraph).segments.splice( firstSelectedSegmentIndex, lastSelectedSegmentIndex - firstSelectedSegmentIndex + 1, spaceText, marker ); } else { return false; } } else { const markerIndex = paragraph.segments.findIndex( segment => segment.segmentType === 'SelectionMarker' ); if (!rawEvent.shiftKey) { const markerFormat = paragraph.segments[markerIndex].format; const tabText = createText(tabSpaces, markerFormat); mutateBlock(paragraph).segments.splice(markerIndex, 0, tabText); } else { const tabText = paragraph.segments[markerIndex - 1]; const tabSpacesLength = tabSpaces.length; Eif (tabText.segmentType == 'Text') { const tabSpaceTextLength = tabText.text.length - tabSpacesLength; if (tabText.text === tabSpaces) { mutateBlock(paragraph).segments.splice(markerIndex - 1, 1); } else if (tabText.text.substring(tabSpaceTextLength) === tabSpaces) { mutateSegment(paragraph, tabText, text => { text.text = text.text.substring(0, tabSpaceTextLength); }); } else { return false; } } } } } rawEvent.preventDefault(); return true; } |