@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,65 @@
|
|
|
1
|
+
#import "ColorExtension.h"
|
|
2
|
+
#import "EnrichedTextInputView.h"
|
|
3
|
+
#import "FontExtension.h"
|
|
4
|
+
#import "RangeUtils.h"
|
|
5
|
+
#import "StyleHeaders.h"
|
|
6
|
+
|
|
7
|
+
@implementation InlineCodeStyle
|
|
8
|
+
|
|
9
|
+
+ (StyleType)getType {
|
|
10
|
+
return InlineCode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
- (NSString *)getKey {
|
|
14
|
+
return @"EnrichedInlineCode";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
- (BOOL)isParagraph {
|
|
18
|
+
return NO;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (void)applyStyling:(NSRange)range {
|
|
22
|
+
// we don't want to apply inline code to newline characters, it looks bad
|
|
23
|
+
NSArray *nonNewlineRanges =
|
|
24
|
+
[RangeUtils getNonNewlineRangesIn:self.input->textView range:range];
|
|
25
|
+
|
|
26
|
+
for (NSValue *value in nonNewlineRanges) {
|
|
27
|
+
NSRange subRange = [value rangeValue];
|
|
28
|
+
|
|
29
|
+
[self.input->textView.textStorage
|
|
30
|
+
addAttribute:NSBackgroundColorAttributeName
|
|
31
|
+
value:[[self.input->config inlineCodeBgColor]
|
|
32
|
+
colorWithAlphaIfNotTransparent:0.4]
|
|
33
|
+
range:subRange];
|
|
34
|
+
[self.input->textView.textStorage
|
|
35
|
+
addAttribute:NSForegroundColorAttributeName
|
|
36
|
+
value:[self.input->config inlineCodeFgColor]
|
|
37
|
+
range:subRange];
|
|
38
|
+
[self.input->textView.textStorage
|
|
39
|
+
addAttribute:NSUnderlineColorAttributeName
|
|
40
|
+
value:[self.input->config inlineCodeFgColor]
|
|
41
|
+
range:subRange];
|
|
42
|
+
[self.input->textView.textStorage
|
|
43
|
+
addAttribute:NSStrikethroughColorAttributeName
|
|
44
|
+
value:[self.input->config inlineCodeFgColor]
|
|
45
|
+
range:subRange];
|
|
46
|
+
[self.input->textView.textStorage
|
|
47
|
+
enumerateAttribute:NSFontAttributeName
|
|
48
|
+
inRange:subRange
|
|
49
|
+
options:0
|
|
50
|
+
usingBlock:^(id _Nullable value, NSRange fontRange,
|
|
51
|
+
BOOL *_Nonnull stop) {
|
|
52
|
+
UIFont *font = (UIFont *)value;
|
|
53
|
+
if (font != nullptr) {
|
|
54
|
+
UIFont *newFont = [[[self.input->config monospacedFont]
|
|
55
|
+
withFontTraits:font] setSize:font.pointSize];
|
|
56
|
+
[self.input->textView.textStorage
|
|
57
|
+
addAttribute:NSFontAttributeName
|
|
58
|
+
value:newFont
|
|
59
|
+
range:fontRange];
|
|
60
|
+
}
|
|
61
|
+
}];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#import "EnrichedTextInputView.h"
|
|
2
|
+
#import "FontExtension.h"
|
|
3
|
+
#import "StyleHeaders.h"
|
|
4
|
+
|
|
5
|
+
@implementation ItalicStyle : StyleBase
|
|
6
|
+
|
|
7
|
+
+ (StyleType)getType {
|
|
8
|
+
return Italic;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
- (NSString *)getKey {
|
|
12
|
+
return @"EnrichedItalic";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
- (BOOL)isParagraph {
|
|
16
|
+
return NO;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
- (void)applyStyling:(NSRange)range {
|
|
20
|
+
[self.input->textView.textStorage
|
|
21
|
+
enumerateAttribute:NSFontAttributeName
|
|
22
|
+
inRange:range
|
|
23
|
+
options:0
|
|
24
|
+
usingBlock:^(id _Nullable value, NSRange range,
|
|
25
|
+
BOOL *_Nonnull stop) {
|
|
26
|
+
UIFont *font = (UIFont *)value;
|
|
27
|
+
if (font != nullptr) {
|
|
28
|
+
UIFont *newFont = [font setItalic];
|
|
29
|
+
[self.input->textView.textStorage
|
|
30
|
+
addAttribute:NSFontAttributeName
|
|
31
|
+
value:newFont
|
|
32
|
+
range:range];
|
|
33
|
+
}
|
|
34
|
+
}];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@end
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
#import "AttributeEntry.h"
|
|
2
|
+
#import "EnrichedTextInputView.h"
|
|
3
|
+
#import "LinkData.h"
|
|
4
|
+
#import "OccurenceUtils.h"
|
|
5
|
+
#import "StyleHeaders.h"
|
|
6
|
+
#import "TextInsertionUtils.h"
|
|
7
|
+
#import "UIView+React.h"
|
|
8
|
+
#import "WordsUtils.h"
|
|
9
|
+
|
|
10
|
+
static NSString *const ManualLinkAttributeName = @"EnrichedManualLink";
|
|
11
|
+
static NSString *const AutomaticLinkAttributeName = @"EnrichedAutomaticLink";
|
|
12
|
+
|
|
13
|
+
@implementation LinkStyle
|
|
14
|
+
|
|
15
|
+
+ (StyleType)getType {
|
|
16
|
+
return Link;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
- (NSString *)getKey {
|
|
20
|
+
return ManualLinkAttributeName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
- (BOOL)isParagraph {
|
|
24
|
+
return NO;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
- (void)applyStyling:(NSRange)range {
|
|
28
|
+
LinkData *data = [self getLinkDataAt:range.location];
|
|
29
|
+
if (data == nullptr || data.url == nullptr) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
NSMutableDictionary *newAttrs = [[NSMutableDictionary alloc] init];
|
|
34
|
+
newAttrs[NSForegroundColorAttributeName] = [self.input->config linkColor];
|
|
35
|
+
newAttrs[NSUnderlineColorAttributeName] = [self.input->config linkColor];
|
|
36
|
+
newAttrs[NSStrikethroughColorAttributeName] = [self.input->config linkColor];
|
|
37
|
+
if ([self.input->config linkDecorationLine] == DecorationUnderline) {
|
|
38
|
+
newAttrs[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
|
|
39
|
+
}
|
|
40
|
+
[self.input->textView.textStorage addAttributes:newAttrs range:range];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
- (void)reapplyFromStylePair:(StylePair *)pair {
|
|
44
|
+
NSRange range = [pair.rangeValue rangeValue];
|
|
45
|
+
LinkData *linkData = (LinkData *)pair.styleValue;
|
|
46
|
+
|
|
47
|
+
if (linkData == nullptr) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
[self applyLinkMetaWithData:linkData range:range];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// we don't want the link to be extended, thus returning nullptr here.
|
|
55
|
+
- (AttributeEntry *)getEntryIfPresent:(NSRange)range {
|
|
56
|
+
return nullptr;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)toggle:(NSRange)range {
|
|
60
|
+
// no-op for links
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// we have to make sure all links in the range get fully removed here
|
|
64
|
+
- (void)remove:(NSRange)range withDirtyRange:(BOOL)withDirtyRange {
|
|
65
|
+
NSArray<StylePair *> *links = [self all:range];
|
|
66
|
+
[self.input->textView.textStorage beginEditing];
|
|
67
|
+
for (StylePair *pair in links) {
|
|
68
|
+
NSRange linkRange =
|
|
69
|
+
[self getFullLinkRangeAt:[pair.rangeValue rangeValue].location];
|
|
70
|
+
[self.input->textView.textStorage removeAttribute:ManualLinkAttributeName
|
|
71
|
+
range:linkRange];
|
|
72
|
+
[self.input->textView.textStorage removeAttribute:AutomaticLinkAttributeName
|
|
73
|
+
range:linkRange];
|
|
74
|
+
if (withDirtyRange) {
|
|
75
|
+
[self.input->attributesManager addDirtyRange:linkRange];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
[self.input->textView.textStorage endEditing];
|
|
79
|
+
[self removeLinkMetaFromTypingAttributes];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// used for conflicts, we have to remove the whole link
|
|
83
|
+
- (void)removeTyping {
|
|
84
|
+
NSRange linkRange =
|
|
85
|
+
[self getFullLinkRangeAt:self.input->textView.selectedRange.location];
|
|
86
|
+
if (linkRange.length > 0) {
|
|
87
|
+
[self.input->textView.textStorage beginEditing];
|
|
88
|
+
[self.input->textView.textStorage removeAttribute:ManualLinkAttributeName
|
|
89
|
+
range:linkRange];
|
|
90
|
+
[self.input->textView.textStorage removeAttribute:AutomaticLinkAttributeName
|
|
91
|
+
range:linkRange];
|
|
92
|
+
[self.input->textView.textStorage endEditing];
|
|
93
|
+
[self.input->attributesManager addDirtyRange:linkRange];
|
|
94
|
+
}
|
|
95
|
+
[self removeLinkMetaFromTypingAttributes];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
- (BOOL)styleCondition:(id _Nullable)value range:(NSRange)range {
|
|
99
|
+
LinkData *linkData = (LinkData *)value;
|
|
100
|
+
return linkData != nullptr;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
- (BOOL)detect:(NSRange)range {
|
|
104
|
+
if (range.length >= 1) {
|
|
105
|
+
BOOL onlyLinks = [OccurenceUtils
|
|
106
|
+
detectMultiple:@[ ManualLinkAttributeName, AutomaticLinkAttributeName ]
|
|
107
|
+
withInput:self.input
|
|
108
|
+
inRange:range
|
|
109
|
+
withCondition:^BOOL(id _Nullable value, NSRange subrange) {
|
|
110
|
+
return [self styleCondition:value range:subrange];
|
|
111
|
+
}];
|
|
112
|
+
return onlyLinks ? [self isSingleLinkIn:range] : NO;
|
|
113
|
+
}
|
|
114
|
+
return [self getLinkDataAt:range.location] != nullptr;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
- (BOOL)any:(NSRange)range {
|
|
118
|
+
return [OccurenceUtils
|
|
119
|
+
anyMultiple:@[ ManualLinkAttributeName, AutomaticLinkAttributeName ]
|
|
120
|
+
withInput:self.input
|
|
121
|
+
inRange:range
|
|
122
|
+
withCondition:^BOOL(id _Nullable value, NSRange subrange) {
|
|
123
|
+
return [self styleCondition:value range:subrange];
|
|
124
|
+
}];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
- (NSArray<StylePair *> *)all:(NSRange)range {
|
|
128
|
+
return [OccurenceUtils
|
|
129
|
+
allMultiple:@[ ManualLinkAttributeName, AutomaticLinkAttributeName ]
|
|
130
|
+
withInput:self.input
|
|
131
|
+
inRange:range
|
|
132
|
+
withCondition:^BOOL(id _Nullable value, NSRange subrange) {
|
|
133
|
+
return [self styleCondition:value range:subrange];
|
|
134
|
+
}];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
- (void)applyLinkMetaWithData:(LinkData *)linkData range:(NSRange)range {
|
|
138
|
+
if (range.length == 0 || linkData.url == nullptr) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
NSString *key =
|
|
142
|
+
linkData.isManual ? ManualLinkAttributeName : AutomaticLinkAttributeName;
|
|
143
|
+
[self.input->textView.textStorage addAttribute:key
|
|
144
|
+
value:[linkData copy]
|
|
145
|
+
range:range];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
- (void)removeLinkMetaFromTypingAttributes {
|
|
149
|
+
NSMutableDictionary *newTypingAttrs =
|
|
150
|
+
[self.input->textView.typingAttributes mutableCopy];
|
|
151
|
+
[newTypingAttrs removeObjectForKey:ManualLinkAttributeName];
|
|
152
|
+
[newTypingAttrs removeObjectForKey:AutomaticLinkAttributeName];
|
|
153
|
+
self.input->textView.typingAttributes = newTypingAttrs;
|
|
154
|
+
|
|
155
|
+
[self.input->attributesManager
|
|
156
|
+
didRemoveTypingAttribute:ManualLinkAttributeName];
|
|
157
|
+
[self.input->attributesManager
|
|
158
|
+
didRemoveTypingAttribute:AutomaticLinkAttributeName];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
- (void)addLink:(LinkData *)linkData
|
|
162
|
+
range:(NSRange)range
|
|
163
|
+
withSelection:(BOOL)withSelection {
|
|
164
|
+
NSString *currentText =
|
|
165
|
+
[self.input->textView.textStorage.string substringWithRange:range];
|
|
166
|
+
|
|
167
|
+
NSString *key =
|
|
168
|
+
linkData.isManual ? ManualLinkAttributeName : AutomaticLinkAttributeName;
|
|
169
|
+
NSDictionary *metaAttrs = @{key : [linkData copy]};
|
|
170
|
+
|
|
171
|
+
NSRange dirtyRange = NSMakeRange(0, 0);
|
|
172
|
+
|
|
173
|
+
if (range.length == 0) {
|
|
174
|
+
// insert link
|
|
175
|
+
[TextInsertionUtils insertText:linkData.text
|
|
176
|
+
at:range.location
|
|
177
|
+
additionalAttributes:metaAttrs
|
|
178
|
+
input:self.input
|
|
179
|
+
withSelection:withSelection];
|
|
180
|
+
dirtyRange = NSMakeRange(range.location, linkData.text.length);
|
|
181
|
+
} else if ([currentText isEqualToString:linkData.text]) {
|
|
182
|
+
[self applyLinkMetaWithData:linkData range:range];
|
|
183
|
+
dirtyRange = range;
|
|
184
|
+
// TextInsertionUtils take care of the selection but here we have to
|
|
185
|
+
// manually set it behind the link ONLY with manual links, automatic ones
|
|
186
|
+
// don't need the selection fix
|
|
187
|
+
if (linkData.isManual && withSelection) {
|
|
188
|
+
[self.input->textView reactFocus];
|
|
189
|
+
self.input->textView.selectedRange =
|
|
190
|
+
NSMakeRange(range.location + linkData.text.length, 0);
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
// replace text with link
|
|
194
|
+
[TextInsertionUtils replaceText:linkData.text
|
|
195
|
+
at:range
|
|
196
|
+
additionalAttributes:metaAttrs
|
|
197
|
+
input:self.input
|
|
198
|
+
withSelection:withSelection];
|
|
199
|
+
dirtyRange = NSMakeRange(range.location, linkData.text.length);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// add new dirty range
|
|
203
|
+
[self.input->attributesManager addDirtyRange:dirtyRange];
|
|
204
|
+
|
|
205
|
+
// mandatory connected links check
|
|
206
|
+
NSDictionary *currentWord =
|
|
207
|
+
[WordsUtils getCurrentWord:self.input->textView.textStorage.string
|
|
208
|
+
range:self.input->textView.selectedRange];
|
|
209
|
+
if (currentWord != nullptr) {
|
|
210
|
+
// get word properties
|
|
211
|
+
NSString *wordText = (NSString *)[currentWord objectForKey:@"word"];
|
|
212
|
+
NSValue *wordRangeValue = (NSValue *)[currentWord objectForKey:@"range"];
|
|
213
|
+
if (wordText != nullptr && wordRangeValue != nullptr) {
|
|
214
|
+
[self removeConnectedLinksIfNeeded:wordText
|
|
215
|
+
range:[wordRangeValue rangeValue]];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// get exact link data at the given location if it exists
|
|
221
|
+
- (LinkData *)getLinkDataAt:(NSUInteger)location {
|
|
222
|
+
NSRange manualLinkRange = NSMakeRange(0, 0);
|
|
223
|
+
NSRange automaticLinkRange = NSMakeRange(0, 0);
|
|
224
|
+
NSRange inputRange = NSMakeRange(0, self.input->textView.textStorage.length);
|
|
225
|
+
|
|
226
|
+
// don't search at the very end of input
|
|
227
|
+
NSUInteger searchLocation = location;
|
|
228
|
+
if (searchLocation == self.input->textView.textStorage.length) {
|
|
229
|
+
return nullptr;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
LinkData *manualData =
|
|
233
|
+
[self.input->textView.textStorage attribute:ManualLinkAttributeName
|
|
234
|
+
atIndex:searchLocation
|
|
235
|
+
longestEffectiveRange:&manualLinkRange
|
|
236
|
+
inRange:inputRange];
|
|
237
|
+
LinkData *automaticData =
|
|
238
|
+
[self.input->textView.textStorage attribute:AutomaticLinkAttributeName
|
|
239
|
+
atIndex:searchLocation
|
|
240
|
+
longestEffectiveRange:&automaticLinkRange
|
|
241
|
+
inRange:inputRange];
|
|
242
|
+
|
|
243
|
+
if ((manualData == nullptr && automaticData == nullptr) ||
|
|
244
|
+
(manualLinkRange.length == 0 && automaticLinkRange.length == 0)) {
|
|
245
|
+
return nullptr;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return manualData == nullptr ? automaticData : manualData;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// returns full range of a link at some location
|
|
252
|
+
- (NSRange)getFullLinkRangeAt:(NSUInteger)location {
|
|
253
|
+
NSRange manualLinkRange = NSMakeRange(0, 0);
|
|
254
|
+
NSRange automaticLinkRange = NSMakeRange(0, 0);
|
|
255
|
+
NSRange inputRange = NSMakeRange(0, self.input->textView.textStorage.length);
|
|
256
|
+
|
|
257
|
+
// get the previous index if possible when at the very end of input
|
|
258
|
+
NSUInteger searchLocation = location;
|
|
259
|
+
if (searchLocation == self.input->textView.textStorage.length) {
|
|
260
|
+
if (searchLocation == 0) {
|
|
261
|
+
return NSMakeRange(0, 0);
|
|
262
|
+
}
|
|
263
|
+
searchLocation = searchLocation - 1;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
LinkData *manualData =
|
|
267
|
+
[self.input->textView.textStorage attribute:ManualLinkAttributeName
|
|
268
|
+
atIndex:searchLocation
|
|
269
|
+
longestEffectiveRange:&manualLinkRange
|
|
270
|
+
inRange:inputRange];
|
|
271
|
+
LinkData *automaticData =
|
|
272
|
+
[self.input->textView.textStorage attribute:AutomaticLinkAttributeName
|
|
273
|
+
atIndex:searchLocation
|
|
274
|
+
longestEffectiveRange:&automaticLinkRange
|
|
275
|
+
inRange:inputRange];
|
|
276
|
+
|
|
277
|
+
return manualData == nullptr
|
|
278
|
+
? automaticData == nullptr ? NSMakeRange(0, 0) : automaticLinkRange
|
|
279
|
+
: manualLinkRange;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// handles detecting and removing automatic links
|
|
283
|
+
- (void)handleAutomaticLinks:(NSString *)word inRange:(NSRange)wordRange {
|
|
284
|
+
LinkRegexConfig *linkRegexConfig = [self.input->config linkRegexConfig];
|
|
285
|
+
|
|
286
|
+
// no automatic links with isDisabled
|
|
287
|
+
if (linkRegexConfig.isDisabled) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
InlineCodeStyle *inlineCodeStyle =
|
|
292
|
+
[self.input->stylesDict objectForKey:@([InlineCodeStyle getType])];
|
|
293
|
+
MentionStyle *mentionStyle =
|
|
294
|
+
[self.input->stylesDict objectForKey:@([MentionStyle getType])];
|
|
295
|
+
CodeBlockStyle *codeBlockStyle =
|
|
296
|
+
[self.input->stylesDict objectForKey:@([CodeBlockStyle getType])];
|
|
297
|
+
|
|
298
|
+
// we don't recognize links along mentions, inline code or codeblocks
|
|
299
|
+
if (mentionStyle != nullptr && [mentionStyle any:wordRange]) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (inlineCodeStyle != nullptr && [inlineCodeStyle any:wordRange]) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (codeBlockStyle != nullptr && [codeBlockStyle any:wordRange]) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// remove connected different links
|
|
310
|
+
[self removeConnectedLinksIfNeeded:word range:wordRange];
|
|
311
|
+
|
|
312
|
+
// we don't recognize automatic links along manual ones
|
|
313
|
+
__block BOOL manualLinkPresent = NO;
|
|
314
|
+
[self.input->textView.textStorage
|
|
315
|
+
enumerateAttribute:ManualLinkAttributeName
|
|
316
|
+
inRange:wordRange
|
|
317
|
+
options:0
|
|
318
|
+
usingBlock:^(id value, NSRange subrange, BOOL *stop) {
|
|
319
|
+
if ([self styleCondition:value range:subrange]) {
|
|
320
|
+
manualLinkPresent = YES;
|
|
321
|
+
*stop = YES;
|
|
322
|
+
}
|
|
323
|
+
}];
|
|
324
|
+
if (manualLinkPresent) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// all conditions are met; try matching the word to a proper regex
|
|
329
|
+
|
|
330
|
+
NSString *regexPassedUrl = nullptr;
|
|
331
|
+
NSRange matchingRange = NSMakeRange(0, word.length);
|
|
332
|
+
|
|
333
|
+
if (linkRegexConfig.isDefault) {
|
|
334
|
+
// use default regex
|
|
335
|
+
regexPassedUrl = [self tryMatchingDefaultLinkRegex:word
|
|
336
|
+
matchRange:matchingRange];
|
|
337
|
+
} else {
|
|
338
|
+
// use user defined regex if it exists
|
|
339
|
+
NSRegularExpression *userRegex = [self.input->config parsedLinkRegex];
|
|
340
|
+
|
|
341
|
+
if (userRegex == nullptr) {
|
|
342
|
+
// fallback to default regex
|
|
343
|
+
regexPassedUrl = [self tryMatchingDefaultLinkRegex:word
|
|
344
|
+
matchRange:matchingRange];
|
|
345
|
+
} else if ([userRegex numberOfMatchesInString:word
|
|
346
|
+
options:0
|
|
347
|
+
range:matchingRange]) {
|
|
348
|
+
regexPassedUrl = word;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (regexPassedUrl != nullptr) {
|
|
353
|
+
// add style only if needed
|
|
354
|
+
BOOL addStyle = YES;
|
|
355
|
+
if ([self detect:wordRange]) {
|
|
356
|
+
LinkData *currentData = [self getLinkDataAt:wordRange.location];
|
|
357
|
+
if (currentData != nullptr && currentData.url != nullptr &&
|
|
358
|
+
[currentData.url isEqualToString:regexPassedUrl]) {
|
|
359
|
+
addStyle = NO;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (addStyle) {
|
|
363
|
+
LinkData *newData = [[LinkData alloc] init];
|
|
364
|
+
newData.text = word;
|
|
365
|
+
newData.url = regexPassedUrl;
|
|
366
|
+
newData.isManual = NO;
|
|
367
|
+
|
|
368
|
+
[self addLink:newData range:wordRange withSelection:NO];
|
|
369
|
+
|
|
370
|
+
// emit onLinkDetected if style was added
|
|
371
|
+
[self.input emitOnLinkDetectedEvent:newData range:wordRange];
|
|
372
|
+
}
|
|
373
|
+
} else if ([self any:wordRange]) {
|
|
374
|
+
// there was some automatic link (because anyOccurence is true and we are
|
|
375
|
+
// sure there are no manual links) still, it didn't pass any regex - needs
|
|
376
|
+
// to be removed
|
|
377
|
+
[self remove:wordRange withDirtyRange:YES];
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
- (NSString *)tryMatchingDefaultLinkRegex:(NSString *)word
|
|
382
|
+
matchRange:(NSRange)range {
|
|
383
|
+
if ([[LinkStyle fullRegex] numberOfMatchesInString:word
|
|
384
|
+
options:0
|
|
385
|
+
range:range] ||
|
|
386
|
+
[[LinkStyle wwwRegex] numberOfMatchesInString:word
|
|
387
|
+
options:0
|
|
388
|
+
range:range] ||
|
|
389
|
+
[[LinkStyle bareRegex] numberOfMatchesInString:word
|
|
390
|
+
options:0
|
|
391
|
+
range:range]) {
|
|
392
|
+
return word;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return nullptr;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// handles refreshing manual links
|
|
399
|
+
- (void)handleManualLinks:(NSString *)word inRange:(NSRange)wordRange {
|
|
400
|
+
// look for manual links within the word
|
|
401
|
+
__block LinkData *manualLinkMinValue = nullptr;
|
|
402
|
+
__block LinkData *manualLinkMaxValue = nullptr;
|
|
403
|
+
__block NSInteger manualLinkMinIdx = -1;
|
|
404
|
+
__block NSInteger manualLinkMaxIdx = -1;
|
|
405
|
+
|
|
406
|
+
[self.input->textView.textStorage
|
|
407
|
+
enumerateAttribute:ManualLinkAttributeName
|
|
408
|
+
inRange:wordRange
|
|
409
|
+
options:0
|
|
410
|
+
usingBlock:^(id value, NSRange range, BOOL *stop) {
|
|
411
|
+
LinkData *linkDataValue = (LinkData *)value;
|
|
412
|
+
if (linkDataValue != nullptr) {
|
|
413
|
+
NSInteger linkMin = range.location;
|
|
414
|
+
NSInteger linkMax = range.location + range.length - 1;
|
|
415
|
+
if (manualLinkMinIdx == -1 || linkMin < manualLinkMinIdx) {
|
|
416
|
+
manualLinkMinIdx = linkMin;
|
|
417
|
+
manualLinkMinValue = linkDataValue;
|
|
418
|
+
}
|
|
419
|
+
if (manualLinkMaxIdx == -1 || linkMax > manualLinkMaxIdx) {
|
|
420
|
+
manualLinkMaxIdx = linkMax;
|
|
421
|
+
manualLinkMaxValue = linkDataValue;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}];
|
|
425
|
+
|
|
426
|
+
// no manual links
|
|
427
|
+
if (manualLinkMinIdx == -1 || manualLinkMaxIdx == -1) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// heuristic for refreshing manual links:
|
|
432
|
+
// we update the Manual attribute between the bounds of existing ones
|
|
433
|
+
// we do that only if the bounds point to the same url
|
|
434
|
+
// this way manual link gets "extended" only if some characters were added
|
|
435
|
+
// inside it
|
|
436
|
+
if ([manualLinkMinValue isEqualToLinkData:manualLinkMaxValue]) {
|
|
437
|
+
NSRange newRange =
|
|
438
|
+
NSMakeRange(manualLinkMinIdx, manualLinkMaxIdx - manualLinkMinIdx + 1);
|
|
439
|
+
[self applyLinkMetaWithData:manualLinkMinValue range:newRange];
|
|
440
|
+
[self.input->attributesManager addDirtyRange:newRange];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// MARK: - Private non-standard methods
|
|
445
|
+
|
|
446
|
+
// determines whether a given range contains only links pointing to one url
|
|
447
|
+
// assumes the whole range is links only already
|
|
448
|
+
- (BOOL)isSingleLinkIn:(NSRange)range {
|
|
449
|
+
return [self all:range].count == 1;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
- (void)removeConnectedLinksIfNeeded:(NSString *)word range:(NSRange)wordRange {
|
|
453
|
+
BOOL anyAutomatic =
|
|
454
|
+
[OccurenceUtils any:AutomaticLinkAttributeName
|
|
455
|
+
withInput:self.input
|
|
456
|
+
inRange:wordRange
|
|
457
|
+
withCondition:^BOOL(id _Nullable value, NSRange subrange) {
|
|
458
|
+
return [self styleCondition:value range:subrange];
|
|
459
|
+
}];
|
|
460
|
+
BOOL anyManual =
|
|
461
|
+
[OccurenceUtils any:ManualLinkAttributeName
|
|
462
|
+
withInput:self.input
|
|
463
|
+
inRange:wordRange
|
|
464
|
+
withCondition:^BOOL(id _Nullable value, NSRange subrange) {
|
|
465
|
+
return [self styleCondition:value range:subrange];
|
|
466
|
+
}];
|
|
467
|
+
|
|
468
|
+
// both manual and automatic links are somewhere - delete!
|
|
469
|
+
if (anyAutomatic && anyManual) {
|
|
470
|
+
[self remove:wordRange withDirtyRange:YES];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// we are now sure there is only one type of link there - and make sure it
|
|
474
|
+
// covers the whole word
|
|
475
|
+
BOOL onlyLinks = [OccurenceUtils
|
|
476
|
+
detectMultiple:@[ ManualLinkAttributeName, AutomaticLinkAttributeName ]
|
|
477
|
+
withInput:self.input
|
|
478
|
+
inRange:wordRange
|
|
479
|
+
withCondition:^BOOL(id _Nullable value, NSRange r) {
|
|
480
|
+
return [self styleCondition:value range:r];
|
|
481
|
+
}];
|
|
482
|
+
|
|
483
|
+
// only one link might be present!
|
|
484
|
+
if (onlyLinks && ![self isSingleLinkIn:wordRange]) {
|
|
485
|
+
[self remove:wordRange withDirtyRange:YES];
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
+ (NSRegularExpression *)fullRegex {
|
|
490
|
+
static NSRegularExpression *regex;
|
|
491
|
+
static dispatch_once_t onceToken;
|
|
492
|
+
dispatch_once(&onceToken, ^{
|
|
493
|
+
regex =
|
|
494
|
+
[NSRegularExpression regularExpressionWithPattern:
|
|
495
|
+
@"http(s)?:\\/\\/"
|
|
496
|
+
@"www\\.[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-"
|
|
497
|
+
@"z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)"
|
|
498
|
+
options:0
|
|
499
|
+
error:nullptr];
|
|
500
|
+
});
|
|
501
|
+
return regex;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
+ (NSRegularExpression *)wwwRegex {
|
|
505
|
+
static NSRegularExpression *regex;
|
|
506
|
+
static dispatch_once_t onceToken;
|
|
507
|
+
dispatch_once(&onceToken, ^{
|
|
508
|
+
regex =
|
|
509
|
+
[NSRegularExpression regularExpressionWithPattern:
|
|
510
|
+
@"www\\.[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-"
|
|
511
|
+
@"z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)"
|
|
512
|
+
options:0
|
|
513
|
+
error:nullptr];
|
|
514
|
+
});
|
|
515
|
+
return regex;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
+ (NSRegularExpression *)bareRegex {
|
|
519
|
+
static NSRegularExpression *regex;
|
|
520
|
+
static dispatch_once_t onceToken;
|
|
521
|
+
dispatch_once(&onceToken, ^{
|
|
522
|
+
regex =
|
|
523
|
+
[NSRegularExpression regularExpressionWithPattern:
|
|
524
|
+
@"[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-z]{2,"
|
|
525
|
+
@"6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)"
|
|
526
|
+
options:0
|
|
527
|
+
error:nullptr];
|
|
528
|
+
});
|
|
529
|
+
return regex;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
@end
|