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 122 123 124 125 126 127 | 1x 1x 1x 1x 1x 72x 28x 28x 37x 28x 1x 1x 1x 1x 27x 4x 4x 4x 12x 4x 4x 4x 4x 4x 4x 4x 4x 23x 45x 23x 12x 12x 12x 11x 1x 10x 10x 10x 10x 10x 5x 5x 1x 1x 4x 23x 23x | 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, add 4 spaces. * 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 || (segment.segmentType == 'Text' && segment.text.trim().length == 0) ); if (isAllSelected) { const { marginLeft, marginRight, direction } = paragraph.format; const isRtl = direction === 'rtl'; Iif ( 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 { if (markerIndex <= 0) { return false; } 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; } |