@fendent/react-native-enriched 0.5.2-fork.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +343 -0
- package/ReactNativeEnriched.podspec +31 -0
- package/android/build.gradle +106 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +197 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +72 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ComponentDescriptors.cpp +22 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ComponentDescriptors.h +24 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.cpp +434 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.h +391 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/Props.cpp +173 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/Props.h +833 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ShadowNodes.cpp +17 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ShadowNodes.h +23 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/States.cpp +16 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/States.h +20 -0
- package/android/gradle.properties +5 -0
- package/android/lint.gradle +70 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/swmansion/enriched/ReactNativeEnrichedPackage.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/AsyncDrawable.kt +126 -0
- package/android/src/main/java/com/swmansion/enriched/common/CheckboxDrawable.kt +81 -0
- package/android/src/main/java/com/swmansion/enriched/common/EnrichedConstants.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/common/EnrichedStyle.kt +57 -0
- package/android/src/main/java/com/swmansion/enriched/common/ForceRedrawSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/common/GumboNormalizer.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/common/MentionStyle.kt +7 -0
- package/android/src/main/java/com/swmansion/enriched/common/ResourceManager.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedParser.java +956 -0
- package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt +79 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBlockQuoteSpan.kt +53 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBoldSpan.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCheckboxListSpan.kt +92 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCodeBlockSpan.kt +81 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH1Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH2Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH3Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH4Span.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH5Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH6Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedImageSpan.kt +184 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedInlineCodeSpan.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedItalicSpan.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedLinkSpan.kt +29 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedMentionSpan.kt +35 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedOrderedListSpan.kt +79 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedStrikeThroughSpan.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnderlineSpan.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnorderedListSpan.kt +62 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedBlockSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedHeadingSpan.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedInlineSpan.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedParagraphSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedSpan.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputConnectionWrapper.kt +140 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt +83 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt +1120 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewLayoutManager.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt +478 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt +225 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/MentionHandler.kt +55 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeHtmlEvent.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeSelectionEvent.kt +30 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeStateEvent.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeTextEvent.kt +30 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnContextMenuItemPressEvent.kt +35 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputBlurEvent.kt +25 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputFocusEvent.kt +25 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputKeyPressEvent.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnLinkDetectedEvent.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnMentionDetectedEvent.kt +30 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnMentionEvent.kt +34 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnPasteImagesEvent.kt +47 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnRequestHtmlResultEvent.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnSubmitEditingEvent.kt +29 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBlockQuoteSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBoldSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCheckboxListSpan.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCodeBlockSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH1Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH2Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH3Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH4Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH5Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH6Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputImageSpan.kt +36 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputInlineCodeSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputItalicSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputLinkSpan.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputMentionSpan.kt +18 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputOrderedListSpan.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputStrikeThroughSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnderlineSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnorderedListSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedLineHeightSpan.kt +44 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedSpans.kt +241 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/interfaces/EnrichedInputSpan.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/styles/HtmlStyle.kt +372 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/styles/InlineStyles.kt +164 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/styles/ListStyles.kt +263 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/styles/ParagraphStyles.kt +434 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/styles/ParametrizedStyles.kt +394 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedEditableFactory.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSelection.kt +320 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpanState.kt +310 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt +106 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannableStringBuilder.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/RichContentReceiver.kt +127 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/Utils.kt +106 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedSpanWatcher.kt +107 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedTextWatcher.kt +74 -0
- package/android/src/main/new_arch/CMakeLists.txt +62 -0
- package/android/src/main/new_arch/GumboNormalizerJni.cpp +14 -0
- package/android/src/main/new_arch/ReactNativeEnrichedSpec.cpp +11 -0
- package/android/src/main/new_arch/ReactNativeEnrichedSpec.h +15 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputComponentDescriptor.h +35 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputMeasurementManager.cpp +53 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputMeasurementManager.h +25 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.cpp +35 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.h +53 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputState.cpp +9 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputState.h +24 -0
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/conversions.h +27 -0
- package/android/src/main/res/drawable/broken_image.xml +10 -0
- package/cpp/CMakeLists.txt +50 -0
- package/cpp/GumboParser/GumboParser.h +34043 -0
- package/cpp/README.md +59 -0
- package/cpp/parser/GumboNormalizer.c +915 -0
- package/cpp/parser/GumboParser.cpp +16 -0
- package/cpp/parser/GumboParser.hpp +23 -0
- package/cpp/tests/GumboParserTest.cpp +457 -0
- package/ios/EnrichedTextInputView.h +53 -0
- package/ios/EnrichedTextInputView.mm +2360 -0
- package/ios/EnrichedTextInputViewManager.mm +13 -0
- package/ios/attributesManager/AttributesManager.h +17 -0
- package/ios/attributesManager/AttributesManager.mm +195 -0
- package/ios/config/InputConfig.h +104 -0
- package/ios/config/InputConfig.mm +664 -0
- package/ios/extensions/ColorExtension.h +7 -0
- package/ios/extensions/ColorExtension.mm +38 -0
- package/ios/extensions/FontExtension.h +11 -0
- package/ios/extensions/FontExtension.mm +72 -0
- package/ios/extensions/ImageExtension.h +34 -0
- package/ios/extensions/ImageExtension.mm +165 -0
- package/ios/extensions/LayoutManagerExtension.h +6 -0
- package/ios/extensions/LayoutManagerExtension.mm +443 -0
- package/ios/extensions/StringExtension.h +15 -0
- package/ios/extensions/StringExtension.mm +69 -0
- package/ios/generated/ReactNativeEnrichedSpec/ComponentDescriptors.cpp +22 -0
- package/ios/generated/ReactNativeEnrichedSpec/ComponentDescriptors.h +24 -0
- package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.cpp +434 -0
- package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.h +391 -0
- package/ios/generated/ReactNativeEnrichedSpec/Props.cpp +173 -0
- package/ios/generated/ReactNativeEnrichedSpec/Props.h +833 -0
- package/ios/generated/ReactNativeEnrichedSpec/RCTComponentViewHelpers.h +582 -0
- package/ios/generated/ReactNativeEnrichedSpec/ShadowNodes.cpp +17 -0
- package/ios/generated/ReactNativeEnrichedSpec/ShadowNodes.h +23 -0
- package/ios/generated/ReactNativeEnrichedSpec/States.cpp +16 -0
- package/ios/generated/ReactNativeEnrichedSpec/States.h +20 -0
- package/ios/inputParser/InputParser.h +11 -0
- package/ios/inputParser/InputParser.mm +1463 -0
- package/ios/inputTextView/InputTextView.h +6 -0
- package/ios/inputTextView/InputTextView.mm +285 -0
- package/ios/interfaces/AttributeEntry.h +9 -0
- package/ios/interfaces/AttributeEntry.mm +4 -0
- package/ios/interfaces/BaseStyleProtocol.h +17 -0
- package/ios/interfaces/ImageAttachment.h +11 -0
- package/ios/interfaces/ImageAttachment.mm +107 -0
- package/ios/interfaces/ImageData.h +10 -0
- package/ios/interfaces/ImageData.mm +4 -0
- package/ios/interfaces/LinkData.h +11 -0
- package/ios/interfaces/LinkData.mm +29 -0
- package/ios/interfaces/LinkRegexConfig.h +19 -0
- package/ios/interfaces/LinkRegexConfig.mm +37 -0
- package/ios/interfaces/MediaAttachment.h +23 -0
- package/ios/interfaces/MediaAttachment.mm +31 -0
- package/ios/interfaces/MentionParams.h +8 -0
- package/ios/interfaces/MentionParams.mm +4 -0
- package/ios/interfaces/MentionStyleProps.h +13 -0
- package/ios/interfaces/MentionStyleProps.mm +63 -0
- package/ios/interfaces/StyleBase.h +36 -0
- package/ios/interfaces/StyleBase.mm +256 -0
- package/ios/interfaces/StyleHeaders.h +102 -0
- package/ios/interfaces/StylePair.h +9 -0
- package/ios/interfaces/StylePair.mm +4 -0
- package/ios/interfaces/StyleTypeEnum.h +26 -0
- package/ios/interfaces/TextDecorationLineEnum.h +6 -0
- package/ios/interfaces/TextDecorationLineEnum.mm +4 -0
- package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +19 -0
- package/ios/internals/EnrichedTextInputViewShadowNode.h +44 -0
- package/ios/internals/EnrichedTextInputViewShadowNode.mm +103 -0
- package/ios/internals/EnrichedTextInputViewState.cpp +10 -0
- package/ios/internals/EnrichedTextInputViewState.h +22 -0
- package/ios/styles/BlockQuoteStyle.mm +55 -0
- package/ios/styles/BoldStyle.mm +37 -0
- package/ios/styles/CheckboxListStyle.mm +153 -0
- package/ios/styles/CodeBlockStyle.mm +49 -0
- package/ios/styles/H1Style.mm +20 -0
- package/ios/styles/H2Style.mm +20 -0
- package/ios/styles/H3Style.mm +20 -0
- package/ios/styles/H4Style.mm +20 -0
- package/ios/styles/H5Style.mm +20 -0
- package/ios/styles/H6Style.mm +20 -0
- package/ios/styles/HeadingStyleBase.mm +65 -0
- package/ios/styles/ImageStyle.mm +146 -0
- package/ios/styles/InlineCodeStyle.mm +65 -0
- package/ios/styles/ItalicStyle.mm +37 -0
- package/ios/styles/LinkStyle.mm +532 -0
- package/ios/styles/MentionStyle.mm +538 -0
- package/ios/styles/OrderedListStyle.mm +86 -0
- package/ios/styles/StrikethroughStyle.mm +25 -0
- package/ios/styles/UnderlineStyle.mm +24 -0
- package/ios/styles/UnorderedListStyle.mm +86 -0
- package/ios/utils/CheckboxHitTestUtils.h +10 -0
- package/ios/utils/CheckboxHitTestUtils.mm +122 -0
- package/ios/utils/DotReplacementUtils.h +10 -0
- package/ios/utils/DotReplacementUtils.mm +68 -0
- package/ios/utils/KeyboardUtils.h +7 -0
- package/ios/utils/KeyboardUtils.mm +31 -0
- package/ios/utils/OccurenceUtils.h +44 -0
- package/ios/utils/OccurenceUtils.mm +179 -0
- package/ios/utils/ParagraphAttributesUtils.h +15 -0
- package/ios/utils/ParagraphAttributesUtils.mm +257 -0
- package/ios/utils/RangeUtils.h +12 -0
- package/ios/utils/RangeUtils.mm +183 -0
- package/ios/utils/TextBlockTapGestureRecognizer.h +17 -0
- package/ios/utils/TextBlockTapGestureRecognizer.mm +56 -0
- package/ios/utils/TextInsertionUtils.h +17 -0
- package/ios/utils/TextInsertionUtils.mm +64 -0
- package/ios/utils/WordsUtils.h +7 -0
- package/ios/utils/WordsUtils.mm +98 -0
- package/ios/utils/ZeroWidthSpaceUtils.h +9 -0
- package/ios/utils/ZeroWidthSpaceUtils.mm +270 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/EnrichedTextInput.js +304 -0
- package/lib/module/native/EnrichedTextInput.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/spec/EnrichedTextInputNativeComponent.ts +517 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils/EnrichedTextInputDefaultProps.js +12 -0
- package/lib/module/utils/EnrichedTextInputDefaultProps.js.map +1 -0
- package/lib/module/utils/normalizeHtmlStyle.js +155 -0
- package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
- package/lib/module/utils/nullthrows.js +9 -0
- package/lib/module/utils/nullthrows.js.map +1 -0
- package/lib/module/utils/regexParser.js +46 -0
- package/lib/module/utils/regexParser.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/native/EnrichedTextInput.d.ts +3 -0
- package/lib/typescript/src/native/EnrichedTextInput.d.ts.map +1 -0
- package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts +397 -0
- package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +447 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utils/EnrichedTextInputDefaultProps.d.ts +10 -0
- package/lib/typescript/src/utils/EnrichedTextInputDefaultProps.d.ts.map +1 -0
- package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +4 -0
- package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
- package/lib/typescript/src/utils/nullthrows.d.ts +2 -0
- package/lib/typescript/src/utils/nullthrows.d.ts.map +1 -0
- package/lib/typescript/src/utils/regexParser.d.ts +3 -0
- package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
- package/package.json +226 -0
- package/react-native.config.js +13 -0
- package/src/index.tsx +20 -0
- package/src/native/EnrichedTextInput.tsx +370 -0
- package/src/spec/EnrichedTextInputNativeComponent.ts +517 -0
- package/src/types.ts +499 -0
- package/src/utils/EnrichedTextInputDefaultProps.ts +9 -0
- package/src/utils/normalizeHtmlStyle.ts +199 -0
- package/src/utils/nullthrows.ts +7 -0
- package/src/utils/regexParser.ts +56 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
#import "AttributeEntry.h"
|
|
2
|
+
#import "ColorExtension.h"
|
|
3
|
+
#import "EnrichedTextInputView.h"
|
|
4
|
+
#import "StyleHeaders.h"
|
|
5
|
+
#import "TextInsertionUtils.h"
|
|
6
|
+
#import "UIView+React.h"
|
|
7
|
+
#import "WordsUtils.h"
|
|
8
|
+
|
|
9
|
+
// custom NSAttributedStringKey to differentiate from links
|
|
10
|
+
static NSString *const MentionAttributeName = @"EnrichedMention";
|
|
11
|
+
|
|
12
|
+
@implementation MentionStyle {
|
|
13
|
+
NSValue *_activeMentionRange;
|
|
14
|
+
NSString *_activeMentionIndicator;
|
|
15
|
+
BOOL _blockMentionEditing;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
+ (StyleType)getType {
|
|
19
|
+
return Mention;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
- (NSString *)getKey {
|
|
23
|
+
return MentionAttributeName;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (BOOL)isParagraph {
|
|
27
|
+
return NO;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
- (instancetype)initWithInput:(id)input {
|
|
31
|
+
self = [super initWithInput:(EnrichedTextInputView *)input];
|
|
32
|
+
if (self) {
|
|
33
|
+
_activeMentionRange = nullptr;
|
|
34
|
+
_activeMentionIndicator = nullptr;
|
|
35
|
+
_blockMentionEditing = NO;
|
|
36
|
+
}
|
|
37
|
+
return self;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
- (void)applyStyling:(NSRange)range {
|
|
41
|
+
if (range.length == 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
MentionParams *params = [self getMentionParamsAt:range.location];
|
|
45
|
+
if (params == nullptr) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
MentionStyleProps *styleProps =
|
|
50
|
+
[self.input->config mentionStylePropsForIndicator:params.indicator];
|
|
51
|
+
|
|
52
|
+
NSMutableDictionary *newAttrs = [@{
|
|
53
|
+
NSForegroundColorAttributeName : styleProps.color,
|
|
54
|
+
NSUnderlineColorAttributeName : styleProps.color,
|
|
55
|
+
NSStrikethroughColorAttributeName : styleProps.color,
|
|
56
|
+
NSBackgroundColorAttributeName :
|
|
57
|
+
[styleProps.backgroundColor colorWithAlphaIfNotTransparent:0.4],
|
|
58
|
+
} mutableCopy];
|
|
59
|
+
|
|
60
|
+
if (styleProps.decorationLine == DecorationUnderline) {
|
|
61
|
+
newAttrs[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
[self.input->textView.textStorage addAttributes:newAttrs range:range];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (void)reapplyFromStylePair:(StylePair *)pair {
|
|
68
|
+
NSRange range = [pair.rangeValue rangeValue];
|
|
69
|
+
MentionParams *params = (MentionParams *)pair.styleValue;
|
|
70
|
+
if (params == nullptr) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
[self applyMentionMeta:params range:range];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// we don't want the mention to be extended, thus returning nullptr here.
|
|
77
|
+
- (AttributeEntry *)getEntryIfPresent:(NSRange)range {
|
|
78
|
+
return nullptr;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (void)toggle:(NSRange)range {
|
|
82
|
+
// no-op for mentions
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Strip meta only, AttributesManager dirty pass resets visuals and reapplies
|
|
86
|
+
// other styles
|
|
87
|
+
- (void)remove:(NSRange)range withDirtyRange:(BOOL)withDirtyRange {
|
|
88
|
+
NSArray<StylePair *> *mentions = [self all:range];
|
|
89
|
+
[self.input->textView.textStorage beginEditing];
|
|
90
|
+
for (StylePair *pair in mentions) {
|
|
91
|
+
NSRange mentionRange =
|
|
92
|
+
[self getFullMentionRangeAt:[pair.rangeValue rangeValue].location];
|
|
93
|
+
if (mentionRange.length == 0) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
[self.input->textView.textStorage removeAttribute:MentionAttributeName
|
|
97
|
+
range:mentionRange];
|
|
98
|
+
if (withDirtyRange) {
|
|
99
|
+
[self.input->attributesManager addDirtyRange:mentionRange];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
[self.input->textView.textStorage endEditing];
|
|
103
|
+
|
|
104
|
+
[super removeTyping];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// used for conflicts, we have to remove the whole mention
|
|
108
|
+
- (void)removeTyping {
|
|
109
|
+
NSRange mentionRange =
|
|
110
|
+
[self getFullMentionRangeAt:self.input->textView.selectedRange.location];
|
|
111
|
+
if (mentionRange.length > 0) {
|
|
112
|
+
[self.input->textView.textStorage beginEditing];
|
|
113
|
+
[self.input->textView.textStorage removeAttribute:MentionAttributeName
|
|
114
|
+
range:mentionRange];
|
|
115
|
+
[self.input->textView.textStorage endEditing];
|
|
116
|
+
[self.input->attributesManager addDirtyRange:mentionRange];
|
|
117
|
+
}
|
|
118
|
+
[super removeTyping];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
- (BOOL)styleCondition:(id _Nullable)value range:(NSRange)range {
|
|
122
|
+
MentionParams *params = (MentionParams *)value;
|
|
123
|
+
return params != nullptr;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
- (BOOL)detect:(NSRange)range {
|
|
127
|
+
if (range.length >= 1) {
|
|
128
|
+
return [super detect:range];
|
|
129
|
+
}
|
|
130
|
+
return [self getMentionParamsAt:range.location] != nullptr;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
- (void)applyMentionMeta:(MentionParams *)params range:(NSRange)range {
|
|
134
|
+
[self.input->textView.textStorage addAttribute:MentionAttributeName
|
|
135
|
+
value:params
|
|
136
|
+
range:range];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MARK: - Public non-standard methods
|
|
140
|
+
|
|
141
|
+
- (void)addMention:(NSString *)indicator
|
|
142
|
+
text:(NSString *)text
|
|
143
|
+
attributes:(NSString *)attributes {
|
|
144
|
+
if (_activeMentionRange == nullptr) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_blockMentionEditing = YES;
|
|
149
|
+
|
|
150
|
+
MentionParams *params = [[MentionParams alloc] init];
|
|
151
|
+
params.text = text;
|
|
152
|
+
params.indicator = indicator;
|
|
153
|
+
params.attributes = attributes;
|
|
154
|
+
|
|
155
|
+
// add a single space after the mention
|
|
156
|
+
NSString *newText = [NSString stringWithFormat:@"%@ ", text];
|
|
157
|
+
NSRange rangeToBeReplaced = [_activeMentionRange rangeValue];
|
|
158
|
+
[TextInsertionUtils replaceText:newText
|
|
159
|
+
at:rangeToBeReplaced
|
|
160
|
+
additionalAttributes:nullptr
|
|
161
|
+
input:self.input
|
|
162
|
+
withSelection:YES];
|
|
163
|
+
|
|
164
|
+
// THEN, add the attributes to not apply them on the space
|
|
165
|
+
NSRange mentionRange = NSMakeRange(rangeToBeReplaced.location, text.length);
|
|
166
|
+
[self applyMentionMeta:params range:mentionRange];
|
|
167
|
+
[self.input->attributesManager addDirtyRange:mentionRange];
|
|
168
|
+
// mention editing should finish
|
|
169
|
+
[self removeActiveMentionRange];
|
|
170
|
+
|
|
171
|
+
_blockMentionEditing = NO;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
- (void)addMentionAtRange:(NSRange)range params:(MentionParams *)params {
|
|
175
|
+
_blockMentionEditing = YES;
|
|
176
|
+
|
|
177
|
+
[self applyMentionMeta:params range:range];
|
|
178
|
+
[self.input->attributesManager addDirtyRange:range];
|
|
179
|
+
|
|
180
|
+
_blockMentionEditing = NO;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
- (void)startMentionWithIndicator:(NSString *)indicator {
|
|
184
|
+
NSRange currentRange = self.input->textView.selectedRange;
|
|
185
|
+
|
|
186
|
+
BOOL addSpaceBefore = NO;
|
|
187
|
+
BOOL addSpaceAfter = NO;
|
|
188
|
+
|
|
189
|
+
if (currentRange.location > 0) {
|
|
190
|
+
unichar charBefore = [self.input->textView.textStorage.string
|
|
191
|
+
characterAtIndex:(currentRange.location - 1)];
|
|
192
|
+
if (![[NSCharacterSet whitespaceAndNewlineCharacterSet]
|
|
193
|
+
characterIsMember:charBefore]) {
|
|
194
|
+
addSpaceBefore = YES;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (currentRange.location + currentRange.length <
|
|
199
|
+
self.input->textView.textStorage.string.length) {
|
|
200
|
+
unichar charAfter = [self.input->textView.textStorage.string
|
|
201
|
+
characterAtIndex:(currentRange.location + currentRange.length)];
|
|
202
|
+
if (![[NSCharacterSet whitespaceAndNewlineCharacterSet]
|
|
203
|
+
characterIsMember:charAfter]) {
|
|
204
|
+
addSpaceAfter = YES;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
NSString *finalString =
|
|
209
|
+
[NSString stringWithFormat:@"%@%@%@", addSpaceBefore ? @" " : @"",
|
|
210
|
+
indicator, addSpaceAfter ? @" " : @""];
|
|
211
|
+
|
|
212
|
+
NSRange newSelect = NSMakeRange(
|
|
213
|
+
currentRange.location + finalString.length + (addSpaceAfter ? -1 : 0), 0);
|
|
214
|
+
|
|
215
|
+
if (currentRange.length == 0) {
|
|
216
|
+
[TextInsertionUtils insertText:finalString
|
|
217
|
+
at:currentRange.location
|
|
218
|
+
additionalAttributes:nullptr
|
|
219
|
+
input:self.input
|
|
220
|
+
withSelection:NO];
|
|
221
|
+
} else {
|
|
222
|
+
[TextInsertionUtils replaceText:finalString
|
|
223
|
+
at:currentRange
|
|
224
|
+
additionalAttributes:nullptr
|
|
225
|
+
input:self.input
|
|
226
|
+
withSelection:NO];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
[self.input->textView reactFocus];
|
|
230
|
+
self.input->textView.selectedRange = newSelect;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// handles removing no longer valid mentions
|
|
234
|
+
- (void)handleExistingMentions {
|
|
235
|
+
// unfortunately whole text needs to be checked for them
|
|
236
|
+
// checking the modified words doesn't work because mention's text can have
|
|
237
|
+
// any number of spaces, which makes one mention any number of words long
|
|
238
|
+
|
|
239
|
+
NSRange wholeText =
|
|
240
|
+
NSMakeRange(0, self.input->textView.textStorage.string.length);
|
|
241
|
+
// get mentions in ascending range.location order
|
|
242
|
+
NSArray<StylePair *> *mentions = [[self all:wholeText]
|
|
243
|
+
sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1,
|
|
244
|
+
id _Nonnull obj2) {
|
|
245
|
+
NSRange range1 = [((StylePair *)obj1).rangeValue rangeValue];
|
|
246
|
+
NSRange range2 = [((StylePair *)obj2).rangeValue rangeValue];
|
|
247
|
+
if (range1.location < range2.location) {
|
|
248
|
+
return NSOrderedAscending;
|
|
249
|
+
}
|
|
250
|
+
return NSOrderedDescending;
|
|
251
|
+
}];
|
|
252
|
+
|
|
253
|
+
// set of ranges to have their mentions removed - aren't valid anymore
|
|
254
|
+
NSMutableSet<NSValue *> *rangesToRemove = [[NSMutableSet alloc] init];
|
|
255
|
+
|
|
256
|
+
for (NSInteger i = 0; i < mentions.count; i++) {
|
|
257
|
+
StylePair *mention = mentions[i];
|
|
258
|
+
NSRange currentRange = [mention.rangeValue rangeValue];
|
|
259
|
+
NSString *currentText = ((MentionParams *)mention.styleValue).text;
|
|
260
|
+
// check locations with the previous mention if it exists - if they got
|
|
261
|
+
// merged they need to be removed
|
|
262
|
+
if (i > 0) {
|
|
263
|
+
NSRange prevRange =
|
|
264
|
+
[((StylePair *)mentions[i - 1]).rangeValue rangeValue];
|
|
265
|
+
// mentions merged - both need to go out
|
|
266
|
+
if (prevRange.location + prevRange.length == currentRange.location) {
|
|
267
|
+
[rangesToRemove addObject:[NSValue valueWithRange:prevRange]];
|
|
268
|
+
[rangesToRemove addObject:[NSValue valueWithRange:currentRange]];
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// check for text, any modifications to it makes mention invalid
|
|
274
|
+
NSString *existingText = [self.input->textView.textStorage.string
|
|
275
|
+
substringWithRange:currentRange];
|
|
276
|
+
if (![existingText isEqualToString:currentText]) {
|
|
277
|
+
[rangesToRemove addObject:[NSValue valueWithRange:currentRange]];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
for (NSValue *value in rangesToRemove) {
|
|
282
|
+
[self remove:[value rangeValue] withDirtyRange:YES];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// manages active mention range, which in turn emits proper onMention event
|
|
287
|
+
- (void)manageMentionEditing {
|
|
288
|
+
// no actions performed when block is active
|
|
289
|
+
if (_blockMentionEditing) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// we don't take longer selections into consideration
|
|
294
|
+
if (self.input->textView.selectedRange.length > 0) {
|
|
295
|
+
[self removeActiveMentionRange];
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// get the text (and its range) that could be an editable mention
|
|
300
|
+
NSArray *mentionCandidate = [self getMentionCandidate];
|
|
301
|
+
if (mentionCandidate == nullptr) {
|
|
302
|
+
[self removeActiveMentionRange];
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
NSString *candidateText = mentionCandidate[0];
|
|
306
|
+
NSRange candidateRange = [(NSValue *)mentionCandidate[1] rangeValue];
|
|
307
|
+
|
|
308
|
+
// get style classes that the mention shouldn't be recognized in, together
|
|
309
|
+
// with other mentions
|
|
310
|
+
NSArray *conflicts = self.input->conflictingStyles[@([MentionStyle getType])];
|
|
311
|
+
NSArray *blocks = self.input->blockingStyles[@([MentionStyle getType])];
|
|
312
|
+
NSArray *allConflicts = [[conflicts arrayByAddingObjectsFromArray:blocks]
|
|
313
|
+
arrayByAddingObject:@([MentionStyle getType])];
|
|
314
|
+
BOOL conflictingStyle = NO;
|
|
315
|
+
|
|
316
|
+
for (NSNumber *styleType in allConflicts) {
|
|
317
|
+
StyleBase *styleInst = self.input->stylesDict[styleType];
|
|
318
|
+
if (styleInst != nullptr && [styleInst any:candidateRange]) {
|
|
319
|
+
conflictingStyle = YES;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// if any of the conflicting styles were present, don't edit the mention
|
|
325
|
+
if (conflictingStyle) {
|
|
326
|
+
[self removeActiveMentionRange];
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// everything checks out - we are indeed editing a mention
|
|
331
|
+
[self setActiveMentionRange:candidateRange text:candidateText];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// returns mention params if it exists
|
|
335
|
+
- (MentionParams *)getMentionParamsAt:(NSUInteger)location {
|
|
336
|
+
NSRange mentionRange = NSMakeRange(0, 0);
|
|
337
|
+
NSRange inputRange = NSMakeRange(0, self.input->textView.textStorage.length);
|
|
338
|
+
|
|
339
|
+
// don't search at the very end of input
|
|
340
|
+
NSUInteger searchLocation = location;
|
|
341
|
+
if (searchLocation == self.input->textView.textStorage.length) {
|
|
342
|
+
return nullptr;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
MentionParams *value =
|
|
346
|
+
[self.input->textView.textStorage attribute:MentionAttributeName
|
|
347
|
+
atIndex:searchLocation
|
|
348
|
+
longestEffectiveRange:&mentionRange
|
|
349
|
+
inRange:inputRange];
|
|
350
|
+
return value;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
- (NSValue *)getActiveMentionRange {
|
|
354
|
+
return _activeMentionRange;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// returns full range of a mention at some location
|
|
358
|
+
- (NSRange)getFullMentionRangeAt:(NSUInteger)location {
|
|
359
|
+
NSRange mentionRange = NSMakeRange(0, 0);
|
|
360
|
+
NSRange inputRange = NSMakeRange(0, self.input->textView.textStorage.length);
|
|
361
|
+
|
|
362
|
+
// get the previous index if possible when at the very end of input
|
|
363
|
+
NSUInteger searchLocation = location;
|
|
364
|
+
if (searchLocation == self.input->textView.textStorage.length) {
|
|
365
|
+
if (searchLocation == 0) {
|
|
366
|
+
return mentionRange;
|
|
367
|
+
}
|
|
368
|
+
searchLocation = searchLocation - 1;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
[self.input->textView.textStorage attribute:MentionAttributeName
|
|
372
|
+
atIndex:searchLocation
|
|
373
|
+
longestEffectiveRange:&mentionRange
|
|
374
|
+
inRange:inputRange];
|
|
375
|
+
return mentionRange;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
- (MentionStyleProps *)stylePropsWithParams:(MentionParams *)params {
|
|
379
|
+
return [self.input->config mentionStylePropsForIndicator:params.indicator];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// finds if any word/words around current selection are eligible to be edited as
|
|
383
|
+
// mentions since we allow for a single space inside an edited mention, we have
|
|
384
|
+
// take both current and the previous word into account
|
|
385
|
+
- (NSArray *)getMentionCandidate {
|
|
386
|
+
NSDictionary *currentWord, *previousWord;
|
|
387
|
+
NSString *currentWordText, *previousWordText, *finalText;
|
|
388
|
+
NSValue *currentWordRange, *previousWordRange;
|
|
389
|
+
NSRange finalRange;
|
|
390
|
+
|
|
391
|
+
// word at the current selection
|
|
392
|
+
currentWord =
|
|
393
|
+
[WordsUtils getCurrentWord:self.input->textView.textStorage.string
|
|
394
|
+
range:self.input->textView.selectedRange];
|
|
395
|
+
if (currentWord != nullptr) {
|
|
396
|
+
currentWordText = (NSString *)[currentWord objectForKey:@"word"];
|
|
397
|
+
currentWordRange = (NSValue *)[currentWord objectForKey:@"range"];
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (currentWord != nullptr) {
|
|
401
|
+
// current word exists
|
|
402
|
+
unichar currentFirstChar = [currentWordText characterAtIndex:0];
|
|
403
|
+
|
|
404
|
+
if ([[self.input->config mentionIndicators]
|
|
405
|
+
containsObject:@(currentFirstChar)]) {
|
|
406
|
+
// current word exists and has a mention indicator; no need to check for
|
|
407
|
+
// the previous word
|
|
408
|
+
finalText = currentWordText;
|
|
409
|
+
finalRange = [currentWordRange rangeValue];
|
|
410
|
+
} else {
|
|
411
|
+
// current word exists but no traces of mention indicator; get the
|
|
412
|
+
// previous word
|
|
413
|
+
|
|
414
|
+
NSInteger previousWordSearchLocation =
|
|
415
|
+
[currentWordRange rangeValue].location - 1;
|
|
416
|
+
if (previousWordSearchLocation < 0) {
|
|
417
|
+
// previous word can't exist
|
|
418
|
+
return nullptr;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
unichar separatorChar = [self.input->textView.textStorage.string
|
|
422
|
+
characterAtIndex:previousWordSearchLocation];
|
|
423
|
+
if (![[NSCharacterSet whitespaceCharacterSet]
|
|
424
|
+
characterIsMember:separatorChar]) {
|
|
425
|
+
// we want to check for the previous word ONLY if the separating
|
|
426
|
+
// character was a space newlines don't make it
|
|
427
|
+
return nullptr;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
previousWord = [WordsUtils
|
|
431
|
+
getCurrentWord:self.input->textView.textStorage.string
|
|
432
|
+
range:NSMakeRange(previousWordSearchLocation, 0)];
|
|
433
|
+
|
|
434
|
+
if (previousWord != nullptr) {
|
|
435
|
+
// previous word exists; get its properties
|
|
436
|
+
previousWordText = (NSString *)[previousWord objectForKey:@"word"];
|
|
437
|
+
previousWordRange = (NSValue *)[previousWord objectForKey:@"range"];
|
|
438
|
+
|
|
439
|
+
// check for the mention indicators in the previous word
|
|
440
|
+
unichar previousFirstChar = [previousWordText characterAtIndex:0];
|
|
441
|
+
|
|
442
|
+
if ([[self.input->config mentionIndicators]
|
|
443
|
+
containsObject:@(previousFirstChar)]) {
|
|
444
|
+
// previous word has a proper mention indicator: treat both words as
|
|
445
|
+
// an editable mention
|
|
446
|
+
finalText = [NSString
|
|
447
|
+
stringWithFormat:@"%@ %@", previousWordText, currentWordText];
|
|
448
|
+
// range length is both words' lengths + 1 for a space between them
|
|
449
|
+
finalRange =
|
|
450
|
+
NSMakeRange([previousWordRange rangeValue].location,
|
|
451
|
+
[previousWordRange rangeValue].length +
|
|
452
|
+
[currentWordRange rangeValue].length + 1);
|
|
453
|
+
} else {
|
|
454
|
+
// neither current nor previous words have a mention indicator
|
|
455
|
+
return nullptr;
|
|
456
|
+
}
|
|
457
|
+
} else {
|
|
458
|
+
// previous word doesn't exist and no mention indicators in the current
|
|
459
|
+
// word
|
|
460
|
+
return nullptr;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
// current word doesn't exist; try getting the previous one
|
|
465
|
+
|
|
466
|
+
NSInteger previousWordSearchLocation =
|
|
467
|
+
self.input->textView.selectedRange.location - 1;
|
|
468
|
+
if (previousWordSearchLocation < 0) {
|
|
469
|
+
// previous word can't exist
|
|
470
|
+
return nullptr;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
unichar separatorChar = [self.input->textView.textStorage.string
|
|
474
|
+
characterAtIndex:previousWordSearchLocation];
|
|
475
|
+
if (![[NSCharacterSet whitespaceCharacterSet]
|
|
476
|
+
characterIsMember:separatorChar]) {
|
|
477
|
+
// we want to check for the previous word ONLY if the separating character
|
|
478
|
+
// was a space newlines don't make it
|
|
479
|
+
return nullptr;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
previousWord =
|
|
483
|
+
[WordsUtils getCurrentWord:self.input->textView.textStorage.string
|
|
484
|
+
range:NSMakeRange(previousWordSearchLocation, 0)];
|
|
485
|
+
|
|
486
|
+
if (previousWord != nullptr) {
|
|
487
|
+
// previous word exists; get its properties
|
|
488
|
+
previousWordText = (NSString *)[previousWord objectForKey:@"word"];
|
|
489
|
+
previousWordRange = (NSValue *)[previousWord objectForKey:@"range"];
|
|
490
|
+
|
|
491
|
+
// check for the mention indicators in the previous word
|
|
492
|
+
unichar previousFirstChar = [previousWordText characterAtIndex:0];
|
|
493
|
+
|
|
494
|
+
if ([[self.input->config mentionIndicators]
|
|
495
|
+
containsObject:@(previousFirstChar)]) {
|
|
496
|
+
// previous word has a proper mention indicator; treat previous word + a
|
|
497
|
+
// space as a editable mention
|
|
498
|
+
finalText = [NSString stringWithFormat:@"%@ ", previousWordText];
|
|
499
|
+
// the range length is previous word length + 1 for a space
|
|
500
|
+
finalRange = NSMakeRange([previousWordRange rangeValue].location,
|
|
501
|
+
[previousWordRange rangeValue].length + 1);
|
|
502
|
+
} else {
|
|
503
|
+
// no current word, previous has no mention indicators
|
|
504
|
+
return nullptr;
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
// no current word, no previous word
|
|
508
|
+
return nullptr;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return @[ finalText, [NSValue valueWithRange:finalRange] ];
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// both used for setting the active mention range + indicator and fires proper
|
|
516
|
+
// onMention event
|
|
517
|
+
- (void)setActiveMentionRange:(NSRange)range text:(NSString *)text {
|
|
518
|
+
NSString *indicatorString =
|
|
519
|
+
[NSString stringWithFormat:@"%C", [text characterAtIndex:0]];
|
|
520
|
+
NSString *textString =
|
|
521
|
+
[text substringWithRange:NSMakeRange(1, text.length - 1)];
|
|
522
|
+
_activeMentionIndicator = indicatorString;
|
|
523
|
+
_activeMentionRange = [NSValue valueWithRange:range];
|
|
524
|
+
[self.input emitOnMentionEvent:indicatorString text:textString];
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// removes stored mention range + indicator, which means that we no longer edit
|
|
528
|
+
// a mention and onMention event gets fired
|
|
529
|
+
- (void)removeActiveMentionRange {
|
|
530
|
+
if (_activeMentionIndicator != nullptr && _activeMentionRange != nullptr) {
|
|
531
|
+
NSString *indicatorCopy = [_activeMentionIndicator copy];
|
|
532
|
+
_activeMentionIndicator = nullptr;
|
|
533
|
+
_activeMentionRange = nullptr;
|
|
534
|
+
[self.input emitOnMentionEvent:indicatorCopy text:nullptr];
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
@end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#import "EnrichedTextInputView.h"
|
|
2
|
+
#import "RangeUtils.h"
|
|
3
|
+
#import "StyleHeaders.h"
|
|
4
|
+
#import "TextInsertionUtils.h"
|
|
5
|
+
|
|
6
|
+
@implementation OrderedListStyle
|
|
7
|
+
|
|
8
|
+
+ (StyleType)getType {
|
|
9
|
+
return OrderedList;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
- (NSString *)getValue {
|
|
13
|
+
return @"EnrichedOrderedList";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (BOOL)isParagraph {
|
|
17
|
+
return YES;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
- (BOOL)needsZWS {
|
|
21
|
+
return YES;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
- (void)applyStyling:(NSRange)range {
|
|
25
|
+
// lists are drawn manually
|
|
26
|
+
// margin before marker + gap between marker and paragraph
|
|
27
|
+
CGFloat listHeadIndent = [self.input->config orderedListMarginLeft] +
|
|
28
|
+
[self.input->config orderedListGapWidth];
|
|
29
|
+
|
|
30
|
+
[self.input->textView.textStorage
|
|
31
|
+
enumerateAttribute:NSParagraphStyleAttributeName
|
|
32
|
+
inRange:range
|
|
33
|
+
options:0
|
|
34
|
+
usingBlock:^(id _Nullable value, NSRange range,
|
|
35
|
+
BOOL *_Nonnull stop) {
|
|
36
|
+
NSMutableParagraphStyle *pStyle =
|
|
37
|
+
[(NSParagraphStyle *)value mutableCopy];
|
|
38
|
+
pStyle.headIndent = listHeadIndent;
|
|
39
|
+
pStyle.firstLineHeadIndent = listHeadIndent;
|
|
40
|
+
[self.input->textView.textStorage
|
|
41
|
+
addAttribute:NSParagraphStyleAttributeName
|
|
42
|
+
value:pStyle
|
|
43
|
+
range:range];
|
|
44
|
+
}];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
- (BOOL)tryHandlingListShorcutInRange:(NSRange)range
|
|
48
|
+
replacementText:(NSString *)text {
|
|
49
|
+
NSRange paragraphRange =
|
|
50
|
+
[self.input->textView.textStorage.string paragraphRangeForRange:range];
|
|
51
|
+
// a dot was added - check if we are both at the paragraph beginning + 1
|
|
52
|
+
// character (which we want to be a digit '1')
|
|
53
|
+
if ([text isEqualToString:@"."] &&
|
|
54
|
+
range.location - 1 == paragraphRange.location) {
|
|
55
|
+
unichar charBefore = [self.input->textView.textStorage.string
|
|
56
|
+
characterAtIndex:range.location - 1];
|
|
57
|
+
if (charBefore == '1') {
|
|
58
|
+
// we got a match - add a list if possible
|
|
59
|
+
if ([self.input handleStyleBlocksAndConflicts:[[self class] getType]
|
|
60
|
+
range:paragraphRange]) {
|
|
61
|
+
// don't emit during the replacing
|
|
62
|
+
self.input->blockEmitting = YES;
|
|
63
|
+
|
|
64
|
+
// remove the number
|
|
65
|
+
[TextInsertionUtils replaceText:@""
|
|
66
|
+
at:NSMakeRange(paragraphRange.location, 1)
|
|
67
|
+
additionalAttributes:nullptr
|
|
68
|
+
input:self.input
|
|
69
|
+
withSelection:YES];
|
|
70
|
+
|
|
71
|
+
self.input->blockEmitting = NO;
|
|
72
|
+
|
|
73
|
+
// add attributes on the paragraph
|
|
74
|
+
[self add:NSMakeRange(paragraphRange.location,
|
|
75
|
+
paragraphRange.length - 1)
|
|
76
|
+
withTyping:YES
|
|
77
|
+
withDirtyRange:YES];
|
|
78
|
+
|
|
79
|
+
return YES;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return NO;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#import "EnrichedTextInputView.h"
|
|
2
|
+
#import "StyleHeaders.h"
|
|
3
|
+
|
|
4
|
+
@implementation StrikethroughStyle : StyleBase
|
|
5
|
+
|
|
6
|
+
+ (StyleType)getType {
|
|
7
|
+
return Strikethrough;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
- (NSString *)getKey {
|
|
11
|
+
return @"EnrichedStrikethrough";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
- (BOOL)isParagraph {
|
|
15
|
+
return NO;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
- (void)applyStyling:(NSRange)range {
|
|
19
|
+
[self.input->textView.textStorage addAttributes:@{
|
|
20
|
+
NSStrikethroughStyleAttributeName : @(NSUnderlineStyleSingle)
|
|
21
|
+
}
|
|
22
|
+
range:range];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#import "EnrichedTextInputView.h"
|
|
2
|
+
#import "StyleHeaders.h"
|
|
3
|
+
|
|
4
|
+
@implementation UnderlineStyle
|
|
5
|
+
|
|
6
|
+
+ (StyleType)getType {
|
|
7
|
+
return Underline;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
- (NSString *)getKey {
|
|
11
|
+
return @"EnrichedUnderline";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
- (BOOL)isParagraph {
|
|
15
|
+
return NO;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
- (void)applyStyling:(NSRange)range {
|
|
19
|
+
[self.input->textView.textStorage addAttribute:NSUnderlineStyleAttributeName
|
|
20
|
+
value:@(NSUnderlineStyleSingle)
|
|
21
|
+
range:range];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@end
|