@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,956 @@
|
|
|
1
|
+
package com.swmansion.enriched.common.parser;
|
|
2
|
+
|
|
3
|
+
import android.text.Editable;
|
|
4
|
+
import android.text.Layout;
|
|
5
|
+
import android.text.Spannable;
|
|
6
|
+
import android.text.SpannableStringBuilder;
|
|
7
|
+
import android.text.Spanned;
|
|
8
|
+
import android.text.TextUtils;
|
|
9
|
+
import android.text.style.AlignmentSpan;
|
|
10
|
+
import android.text.style.ParagraphStyle;
|
|
11
|
+
import com.swmansion.enriched.common.EnrichedConstants;
|
|
12
|
+
import com.swmansion.enriched.common.spans.EnrichedBoldSpan;
|
|
13
|
+
import com.swmansion.enriched.common.spans.EnrichedCheckboxListSpan;
|
|
14
|
+
import com.swmansion.enriched.common.spans.EnrichedCodeBlockSpan;
|
|
15
|
+
import com.swmansion.enriched.common.spans.EnrichedH1Span;
|
|
16
|
+
import com.swmansion.enriched.common.spans.EnrichedH2Span;
|
|
17
|
+
import com.swmansion.enriched.common.spans.EnrichedH3Span;
|
|
18
|
+
import com.swmansion.enriched.common.spans.EnrichedH4Span;
|
|
19
|
+
import com.swmansion.enriched.common.spans.EnrichedH5Span;
|
|
20
|
+
import com.swmansion.enriched.common.spans.EnrichedH6Span;
|
|
21
|
+
import com.swmansion.enriched.common.spans.EnrichedImageSpan;
|
|
22
|
+
import com.swmansion.enriched.common.spans.EnrichedInlineCodeSpan;
|
|
23
|
+
import com.swmansion.enriched.common.spans.EnrichedItalicSpan;
|
|
24
|
+
import com.swmansion.enriched.common.spans.EnrichedLinkSpan;
|
|
25
|
+
import com.swmansion.enriched.common.spans.EnrichedMentionSpan;
|
|
26
|
+
import com.swmansion.enriched.common.spans.EnrichedOrderedListSpan;
|
|
27
|
+
import com.swmansion.enriched.common.spans.EnrichedStrikeThroughSpan;
|
|
28
|
+
import com.swmansion.enriched.common.spans.EnrichedUnderlineSpan;
|
|
29
|
+
import com.swmansion.enriched.common.spans.EnrichedUnorderedListSpan;
|
|
30
|
+
import com.swmansion.enriched.common.spans.interfaces.EnrichedBlockSpan;
|
|
31
|
+
import com.swmansion.enriched.common.spans.interfaces.EnrichedInlineSpan;
|
|
32
|
+
import com.swmansion.enriched.common.spans.interfaces.EnrichedParagraphSpan;
|
|
33
|
+
import com.swmansion.enriched.common.spans.interfaces.EnrichedZeroWidthSpaceSpan;
|
|
34
|
+
import java.io.IOException;
|
|
35
|
+
import java.io.StringReader;
|
|
36
|
+
import java.util.HashMap;
|
|
37
|
+
import java.util.Map;
|
|
38
|
+
import org.ccil.cowan.tagsoup.HTMLSchema;
|
|
39
|
+
import org.ccil.cowan.tagsoup.Parser;
|
|
40
|
+
import org.xml.sax.Attributes;
|
|
41
|
+
import org.xml.sax.ContentHandler;
|
|
42
|
+
import org.xml.sax.InputSource;
|
|
43
|
+
import org.xml.sax.Locator;
|
|
44
|
+
import org.xml.sax.SAXException;
|
|
45
|
+
import org.xml.sax.SAXNotRecognizedException;
|
|
46
|
+
import org.xml.sax.SAXNotSupportedException;
|
|
47
|
+
import org.xml.sax.XMLReader;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Most of the code in this file is copied from the Android source code and adjusted to our needs.
|
|
51
|
+
* For the reference see <a
|
|
52
|
+
* href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/text/Html.java">docs</a>
|
|
53
|
+
*/
|
|
54
|
+
public class EnrichedParser {
|
|
55
|
+
/** Retrieves images for HTML <img> tags. */
|
|
56
|
+
private EnrichedParser() {}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Lazy initialization holder for HTML parser. This class will a) be preloaded by the zygote, or
|
|
60
|
+
* b) not loaded until absolutely necessary.
|
|
61
|
+
*/
|
|
62
|
+
private static class HtmlParser {
|
|
63
|
+
private static final HTMLSchema schema = new HTMLSchema();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public static <T> Spanned fromHtml(String source, T style, EnrichedSpanFactory<T> spanFactory) {
|
|
67
|
+
Parser parser = new Parser();
|
|
68
|
+
try {
|
|
69
|
+
parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
|
|
70
|
+
} catch (SAXNotRecognizedException | SAXNotSupportedException e) {
|
|
71
|
+
// Should not happen.
|
|
72
|
+
throw new RuntimeException(e);
|
|
73
|
+
}
|
|
74
|
+
HtmlToSpannedConverter converter =
|
|
75
|
+
new HtmlToSpannedConverter(source, style, parser, spanFactory);
|
|
76
|
+
return converter.convert();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public static String toHtml(Spanned text) {
|
|
80
|
+
StringBuilder out = new StringBuilder();
|
|
81
|
+
withinHtml(out, text);
|
|
82
|
+
String outString = out.toString();
|
|
83
|
+
// Codeblocks and blockquotes appends a newline character by default, so we have to remove it
|
|
84
|
+
String normalizedCodeBlock = outString.replaceAll("</codeblock>\\n<br>", "</codeblock>");
|
|
85
|
+
String normalizedBlockQuote =
|
|
86
|
+
normalizedCodeBlock.replaceAll("</blockquote>\\n<br>", "</blockquote>");
|
|
87
|
+
return "<html>\n" + normalizedBlockQuote + "</html>";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public static String toHtmlWithDefault(CharSequence text) {
|
|
91
|
+
if (text instanceof Spanned) {
|
|
92
|
+
return toHtml((Spanned) text);
|
|
93
|
+
}
|
|
94
|
+
return "<html>\n<p></p>\n</html>";
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Returns an HTML escaped representation of the given plain text. */
|
|
98
|
+
public static String escapeHtml(CharSequence text) {
|
|
99
|
+
StringBuilder out = new StringBuilder();
|
|
100
|
+
withinStyle(out, text, 0, text.length());
|
|
101
|
+
return out.toString();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private static void withinHtml(StringBuilder out, Spanned text) {
|
|
105
|
+
withinDiv(out, text, 0, text.length());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private static void withinDiv(StringBuilder out, Spanned text, int start, int end) {
|
|
109
|
+
int next;
|
|
110
|
+
for (int i = start; i < end; i = next) {
|
|
111
|
+
next = text.nextSpanTransition(i, end, EnrichedBlockSpan.class);
|
|
112
|
+
EnrichedBlockSpan[] blocks = text.getSpans(i, next, EnrichedBlockSpan.class);
|
|
113
|
+
String tag = "unknown";
|
|
114
|
+
if (blocks.length > 0) {
|
|
115
|
+
tag = blocks[0] instanceof EnrichedCodeBlockSpan ? "codeblock" : "blockquote";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Each block appends a newline by default.
|
|
119
|
+
// If we set up a new block, we have to remove the last character.
|
|
120
|
+
if (out.length() >= 5 && out.substring(out.length() - 5).equals("<br>\n")) {
|
|
121
|
+
out.replace(out.length() - 5, out.length(), "");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for (EnrichedBlockSpan ignored : blocks) {
|
|
125
|
+
out.append("<").append(tag).append(">\n");
|
|
126
|
+
}
|
|
127
|
+
withinBlock(out, text, i, next);
|
|
128
|
+
for (EnrichedBlockSpan ignored : blocks) {
|
|
129
|
+
out.append("</").append(tag).append(">\n");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private static String getBlockTag(EnrichedParagraphSpan[] spans) {
|
|
135
|
+
for (EnrichedParagraphSpan span : spans) {
|
|
136
|
+
if (span instanceof EnrichedUnorderedListSpan) {
|
|
137
|
+
return "ul";
|
|
138
|
+
} else if (span instanceof EnrichedOrderedListSpan) {
|
|
139
|
+
return "ol";
|
|
140
|
+
} else if (span instanceof EnrichedCheckboxListSpan) {
|
|
141
|
+
return "ul data-type=\"checkbox\"";
|
|
142
|
+
} else if (span instanceof EnrichedH1Span) {
|
|
143
|
+
return "h1";
|
|
144
|
+
} else if (span instanceof EnrichedH2Span) {
|
|
145
|
+
return "h2";
|
|
146
|
+
} else if (span instanceof EnrichedH3Span) {
|
|
147
|
+
return "h3";
|
|
148
|
+
} else if (span instanceof EnrichedH4Span) {
|
|
149
|
+
return "h4";
|
|
150
|
+
} else if (span instanceof EnrichedH5Span) {
|
|
151
|
+
return "h5";
|
|
152
|
+
} else if (span instanceof EnrichedH6Span) {
|
|
153
|
+
return "h6";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return "p";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private static void withinBlock(StringBuilder out, Spanned text, int start, int end) {
|
|
161
|
+
boolean isInUlList = false;
|
|
162
|
+
boolean isInOlList = false;
|
|
163
|
+
boolean isInCheckboxList = false;
|
|
164
|
+
|
|
165
|
+
int next;
|
|
166
|
+
for (int i = start; i <= end; i = next) {
|
|
167
|
+
next = TextUtils.indexOf(text, '\n', i, end);
|
|
168
|
+
if (next < 0) {
|
|
169
|
+
next = end;
|
|
170
|
+
}
|
|
171
|
+
if (next == i) {
|
|
172
|
+
if (isInUlList) {
|
|
173
|
+
// Current paragraph is no longer a list item; close the previously opened list
|
|
174
|
+
isInUlList = false;
|
|
175
|
+
out.append("</ul>\n");
|
|
176
|
+
} else if (isInOlList) {
|
|
177
|
+
// Current paragraph is no longer a list item; close the previously opened list
|
|
178
|
+
isInOlList = false;
|
|
179
|
+
out.append("</ol>\n");
|
|
180
|
+
} else if (isInCheckboxList) {
|
|
181
|
+
// Current paragraph is no longer a list item; close the previously opened list
|
|
182
|
+
isInCheckboxList = false;
|
|
183
|
+
out.append("</ul>\n");
|
|
184
|
+
}
|
|
185
|
+
out.append("<br>\n");
|
|
186
|
+
} else {
|
|
187
|
+
EnrichedParagraphSpan[] paragraphStyles =
|
|
188
|
+
text.getSpans(i, next, EnrichedParagraphSpan.class);
|
|
189
|
+
String tag = getBlockTag(paragraphStyles);
|
|
190
|
+
boolean isUlListItem = tag.equals("ul");
|
|
191
|
+
boolean isOlListItem = tag.equals("ol");
|
|
192
|
+
boolean isCheckboxListItem = tag.equals("ul data-type=\"checkbox\"");
|
|
193
|
+
|
|
194
|
+
if (isInUlList && !isUlListItem) {
|
|
195
|
+
// Current paragraph is no longer a list item; close the previously opened list
|
|
196
|
+
isInUlList = false;
|
|
197
|
+
out.append("</ul>\n");
|
|
198
|
+
} else if (isInOlList && !isOlListItem) {
|
|
199
|
+
// Current paragraph is no longer a list item; close the previously opened list
|
|
200
|
+
isInOlList = false;
|
|
201
|
+
out.append("</ol>\n");
|
|
202
|
+
} else if (isInCheckboxList && !isCheckboxListItem) {
|
|
203
|
+
// Current paragraph is no longer a list item; close the previously opened list
|
|
204
|
+
isInCheckboxList = false;
|
|
205
|
+
out.append("</ul>\n");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (isUlListItem && !isInUlList) {
|
|
209
|
+
// Current paragraph is the first item in a list
|
|
210
|
+
isInUlList = true;
|
|
211
|
+
out.append("<ul").append(">\n");
|
|
212
|
+
} else if (isOlListItem && !isInOlList) {
|
|
213
|
+
// Current paragraph is the first item in a list
|
|
214
|
+
isInOlList = true;
|
|
215
|
+
out.append("<ol").append(">\n");
|
|
216
|
+
} else if (isCheckboxListItem && !isInCheckboxList) {
|
|
217
|
+
// Current paragraph is the first item in a list
|
|
218
|
+
isInCheckboxList = true;
|
|
219
|
+
out.append("<ul data-type=\"checkbox\">\n");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
boolean isList = isUlListItem || isOlListItem || isCheckboxListItem;
|
|
223
|
+
String tagType = isList ? "li" : tag;
|
|
224
|
+
|
|
225
|
+
out.append("<");
|
|
226
|
+
out.append(tagType);
|
|
227
|
+
|
|
228
|
+
if (isCheckboxListItem) {
|
|
229
|
+
EnrichedCheckboxListSpan[] checkboxSpans =
|
|
230
|
+
text.getSpans(i, next, EnrichedCheckboxListSpan.class);
|
|
231
|
+
if (checkboxSpans.length > 0) {
|
|
232
|
+
boolean isChecked = checkboxSpans[0].isChecked();
|
|
233
|
+
if (isChecked) out.append(" checked");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
out.append(">");
|
|
238
|
+
withinParagraph(out, text, i, next);
|
|
239
|
+
out.append("</");
|
|
240
|
+
out.append(tagType);
|
|
241
|
+
out.append(">\n");
|
|
242
|
+
if (next == end && isInUlList) {
|
|
243
|
+
isInUlList = false;
|
|
244
|
+
out.append("</ul>\n");
|
|
245
|
+
} else if (next == end && isInOlList) {
|
|
246
|
+
isInOlList = false;
|
|
247
|
+
out.append("</ol>\n");
|
|
248
|
+
} else if (next == end && isInCheckboxList) {
|
|
249
|
+
isInCheckboxList = false;
|
|
250
|
+
out.append("</ul>\n");
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
next++;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private static void withinParagraph(StringBuilder out, Spanned text, int start, int end) {
|
|
258
|
+
int next;
|
|
259
|
+
for (int i = start; i < end; i = next) {
|
|
260
|
+
next = text.nextSpanTransition(i, end, EnrichedInlineSpan.class);
|
|
261
|
+
EnrichedInlineSpan[] style = text.getSpans(i, next, EnrichedInlineSpan.class);
|
|
262
|
+
for (int j = 0; j < style.length; j++) {
|
|
263
|
+
if (style[j] instanceof EnrichedBoldSpan) {
|
|
264
|
+
out.append("<b>");
|
|
265
|
+
}
|
|
266
|
+
if (style[j] instanceof EnrichedItalicSpan) {
|
|
267
|
+
out.append("<i>");
|
|
268
|
+
}
|
|
269
|
+
if (style[j] instanceof EnrichedUnderlineSpan) {
|
|
270
|
+
out.append("<u>");
|
|
271
|
+
}
|
|
272
|
+
if (style[j] instanceof EnrichedInlineCodeSpan) {
|
|
273
|
+
out.append("<code>");
|
|
274
|
+
}
|
|
275
|
+
if (style[j] instanceof EnrichedStrikeThroughSpan) {
|
|
276
|
+
out.append("<s>");
|
|
277
|
+
}
|
|
278
|
+
if (style[j] instanceof EnrichedLinkSpan) {
|
|
279
|
+
out.append("<a href=\"");
|
|
280
|
+
out.append(((EnrichedLinkSpan) style[j]).getUrl());
|
|
281
|
+
out.append("\">");
|
|
282
|
+
}
|
|
283
|
+
if (style[j] instanceof EnrichedMentionSpan) {
|
|
284
|
+
out.append("<mention text=\"");
|
|
285
|
+
out.append(((EnrichedMentionSpan) style[j]).getText());
|
|
286
|
+
out.append("\"");
|
|
287
|
+
|
|
288
|
+
out.append(" indicator=\"");
|
|
289
|
+
out.append(((EnrichedMentionSpan) style[j]).getIndicator());
|
|
290
|
+
out.append("\"");
|
|
291
|
+
|
|
292
|
+
Map<String, String> attributes = ((EnrichedMentionSpan) style[j]).getAttributes();
|
|
293
|
+
for (Map.Entry<String, String> entry : attributes.entrySet()) {
|
|
294
|
+
out.append(" ");
|
|
295
|
+
out.append(entry.getKey());
|
|
296
|
+
out.append("=\"");
|
|
297
|
+
out.append(entry.getValue());
|
|
298
|
+
out.append("\"");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
out.append(">");
|
|
302
|
+
}
|
|
303
|
+
if (style[j] instanceof EnrichedImageSpan) {
|
|
304
|
+
out.append("<img src=\"");
|
|
305
|
+
out.append(((EnrichedImageSpan) style[j]).getSource());
|
|
306
|
+
out.append("\"");
|
|
307
|
+
|
|
308
|
+
out.append(" width=\"");
|
|
309
|
+
out.append(((EnrichedImageSpan) style[j]).getWidth());
|
|
310
|
+
out.append("\"");
|
|
311
|
+
|
|
312
|
+
out.append(" height=\"");
|
|
313
|
+
out.append(((EnrichedImageSpan) style[j]).getHeight());
|
|
314
|
+
|
|
315
|
+
out.append("\"/>");
|
|
316
|
+
// Don't output the placeholder character underlying the image.
|
|
317
|
+
i = next;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
withinStyle(out, text, i, next);
|
|
321
|
+
for (int j = style.length - 1; j >= 0; j--) {
|
|
322
|
+
if (style[j] instanceof EnrichedLinkSpan) {
|
|
323
|
+
out.append("</a>");
|
|
324
|
+
}
|
|
325
|
+
if (style[j] instanceof EnrichedMentionSpan) {
|
|
326
|
+
out.append("</mention>");
|
|
327
|
+
}
|
|
328
|
+
if (style[j] instanceof EnrichedStrikeThroughSpan) {
|
|
329
|
+
out.append("</s>");
|
|
330
|
+
}
|
|
331
|
+
if (style[j] instanceof EnrichedUnderlineSpan) {
|
|
332
|
+
out.append("</u>");
|
|
333
|
+
}
|
|
334
|
+
if (style[j] instanceof EnrichedInlineCodeSpan) {
|
|
335
|
+
out.append("</code>");
|
|
336
|
+
}
|
|
337
|
+
if (style[j] instanceof EnrichedBoldSpan) {
|
|
338
|
+
out.append("</b>");
|
|
339
|
+
}
|
|
340
|
+
if (style[j] instanceof EnrichedItalicSpan) {
|
|
341
|
+
out.append("</i>");
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private static void withinStyle(StringBuilder out, CharSequence text, int start, int end) {
|
|
348
|
+
for (int i = start; i < end; i++) {
|
|
349
|
+
char c = text.charAt(i);
|
|
350
|
+
if (c == EnrichedConstants.ZWS) {
|
|
351
|
+
// Do not output zero-width space characters.
|
|
352
|
+
continue;
|
|
353
|
+
} else if (c == '<') {
|
|
354
|
+
out.append("<");
|
|
355
|
+
} else if (c == '>') {
|
|
356
|
+
out.append(">");
|
|
357
|
+
} else if (c == '&') {
|
|
358
|
+
out.append("&");
|
|
359
|
+
} else if (c >= 0xD800 && c <= 0xDFFF) {
|
|
360
|
+
if (c < 0xDC00 && i + 1 < end) {
|
|
361
|
+
char d = text.charAt(i + 1);
|
|
362
|
+
if (d >= 0xDC00 && d <= 0xDFFF) {
|
|
363
|
+
i++;
|
|
364
|
+
int codepoint = 0x010000 | (int) c - 0xD800 << 10 | (int) d - 0xDC00;
|
|
365
|
+
out.append("&#").append(codepoint).append(";");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
} else if (c > 0x7E || c < ' ') {
|
|
369
|
+
out.append("&#").append((int) c).append(";");
|
|
370
|
+
} else if (c == ' ') {
|
|
371
|
+
while (i + 1 < end && text.charAt(i + 1) == ' ') {
|
|
372
|
+
out.append(" ");
|
|
373
|
+
i++;
|
|
374
|
+
}
|
|
375
|
+
out.append(' ');
|
|
376
|
+
} else {
|
|
377
|
+
out.append(c);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
class HtmlToSpannedConverter<T> implements ContentHandler {
|
|
384
|
+
private final EnrichedSpanFactory<T> mSpanFactory;
|
|
385
|
+
private final T mStyle;
|
|
386
|
+
private final String mSource;
|
|
387
|
+
private final XMLReader mReader;
|
|
388
|
+
private final SpannableStringBuilder mSpannableStringBuilder;
|
|
389
|
+
private static Integer currentOrderedListItemIndex = 0;
|
|
390
|
+
private static Boolean isInOrderedList = false;
|
|
391
|
+
private static Boolean isInCheckboxList = false;
|
|
392
|
+
private static Boolean isEmptyTag = false;
|
|
393
|
+
|
|
394
|
+
public HtmlToSpannedConverter(
|
|
395
|
+
String source, T style, Parser parser, EnrichedSpanFactory<T> spanFactory) {
|
|
396
|
+
mStyle = style;
|
|
397
|
+
mSource = source;
|
|
398
|
+
mSpannableStringBuilder = new SpannableStringBuilder();
|
|
399
|
+
mReader = parser;
|
|
400
|
+
mSpanFactory = spanFactory;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
public Spanned convert() {
|
|
404
|
+
mReader.setContentHandler(this);
|
|
405
|
+
try {
|
|
406
|
+
mReader.parse(new InputSource(new StringReader(mSource)));
|
|
407
|
+
} catch (IOException e) {
|
|
408
|
+
// We are reading from a string. There should not be IO problems.
|
|
409
|
+
throw new RuntimeException(e);
|
|
410
|
+
} catch (SAXException e) {
|
|
411
|
+
// TagSoup doesn't throw parse exceptions.
|
|
412
|
+
throw new RuntimeException(e);
|
|
413
|
+
}
|
|
414
|
+
// Fix flags and range for paragraph-type markup.
|
|
415
|
+
Object[] obj =
|
|
416
|
+
mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class);
|
|
417
|
+
for (int i = 0; i < obj.length; i++) {
|
|
418
|
+
int start = mSpannableStringBuilder.getSpanStart(obj[i]);
|
|
419
|
+
int end = mSpannableStringBuilder.getSpanEnd(obj[i]);
|
|
420
|
+
// If the last line of the range is blank, back off by one.
|
|
421
|
+
if (end - 2 >= 0) {
|
|
422
|
+
if (mSpannableStringBuilder.charAt(end - 1) == '\n'
|
|
423
|
+
&& mSpannableStringBuilder.charAt(end - 2) == '\n') {
|
|
424
|
+
end--;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (end == start) {
|
|
428
|
+
mSpannableStringBuilder.removeSpan(obj[i]);
|
|
429
|
+
} else {
|
|
430
|
+
// TODO: verify if Spannable.SPAN_EXCLUSIVE_EXCLUSIVE does not break anything.
|
|
431
|
+
// Previously it was SPAN_PARAGRAPH. I've changed that in order to fix ranges for list
|
|
432
|
+
// items.
|
|
433
|
+
mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Assign zero-width space character to the proper spans.
|
|
438
|
+
EnrichedZeroWidthSpaceSpan[] zeroWidthSpaceSpans =
|
|
439
|
+
mSpannableStringBuilder.getSpans(
|
|
440
|
+
0, mSpannableStringBuilder.length(), EnrichedZeroWidthSpaceSpan.class);
|
|
441
|
+
for (EnrichedZeroWidthSpaceSpan zeroWidthSpaceSpan : zeroWidthSpaceSpans) {
|
|
442
|
+
int start = mSpannableStringBuilder.getSpanStart(zeroWidthSpaceSpan);
|
|
443
|
+
int end = mSpannableStringBuilder.getSpanEnd(zeroWidthSpaceSpan);
|
|
444
|
+
|
|
445
|
+
if (mSpannableStringBuilder.charAt(start) != EnrichedConstants.ZWS) {
|
|
446
|
+
// Insert zero-width space character at the start if it's not already present.
|
|
447
|
+
mSpannableStringBuilder.insert(start, EnrichedConstants.ZWS_STRING);
|
|
448
|
+
end++; // Adjust end position due to insertion.
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
mSpannableStringBuilder.removeSpan(zeroWidthSpaceSpan);
|
|
452
|
+
mSpannableStringBuilder.setSpan(
|
|
453
|
+
zeroWidthSpaceSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return mSpannableStringBuilder;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private void handleStartTag(String tag, Attributes attributes) {
|
|
460
|
+
if (tag.equalsIgnoreCase("br")) {
|
|
461
|
+
// We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
|
|
462
|
+
// so we can safely emit the linebreaks when we handle the close tag.
|
|
463
|
+
} else if (tag.equalsIgnoreCase("p")) {
|
|
464
|
+
isEmptyTag = true;
|
|
465
|
+
startBlockElement(mSpannableStringBuilder);
|
|
466
|
+
} else if (tag.equalsIgnoreCase("ul")) {
|
|
467
|
+
isInOrderedList = false;
|
|
468
|
+
String dataType = attributes.getValue("", "data-type");
|
|
469
|
+
isInCheckboxList = "checkbox".equals(dataType);
|
|
470
|
+
startBlockElement(mSpannableStringBuilder);
|
|
471
|
+
} else if (tag.equalsIgnoreCase("ol")) {
|
|
472
|
+
isInOrderedList = true;
|
|
473
|
+
currentOrderedListItemIndex = 0;
|
|
474
|
+
startBlockElement(mSpannableStringBuilder);
|
|
475
|
+
} else if (tag.equalsIgnoreCase("li")) {
|
|
476
|
+
isEmptyTag = true;
|
|
477
|
+
startLi(mSpannableStringBuilder, attributes);
|
|
478
|
+
} else if (tag.equalsIgnoreCase("b")) {
|
|
479
|
+
start(mSpannableStringBuilder, new Bold());
|
|
480
|
+
} else if (tag.equalsIgnoreCase("i")) {
|
|
481
|
+
start(mSpannableStringBuilder, new Italic());
|
|
482
|
+
} else if (tag.equalsIgnoreCase("blockquote")) {
|
|
483
|
+
isEmptyTag = true;
|
|
484
|
+
startBlockquote(mSpannableStringBuilder);
|
|
485
|
+
} else if (tag.equalsIgnoreCase("codeblock")) {
|
|
486
|
+
isEmptyTag = true;
|
|
487
|
+
startCodeBlock(mSpannableStringBuilder);
|
|
488
|
+
} else if (tag.equalsIgnoreCase("a")) {
|
|
489
|
+
startA(mSpannableStringBuilder, attributes);
|
|
490
|
+
} else if (tag.equalsIgnoreCase("u")) {
|
|
491
|
+
start(mSpannableStringBuilder, new Underline());
|
|
492
|
+
} else if (tag.equalsIgnoreCase("s")) {
|
|
493
|
+
start(mSpannableStringBuilder, new Strikethrough());
|
|
494
|
+
} else if (tag.equalsIgnoreCase("strike")) {
|
|
495
|
+
start(mSpannableStringBuilder, new Strikethrough());
|
|
496
|
+
} else if (tag.equalsIgnoreCase("h1")) {
|
|
497
|
+
startHeading(mSpannableStringBuilder, 1);
|
|
498
|
+
} else if (tag.equalsIgnoreCase("h2")) {
|
|
499
|
+
startHeading(mSpannableStringBuilder, 2);
|
|
500
|
+
} else if (tag.equalsIgnoreCase("h3")) {
|
|
501
|
+
startHeading(mSpannableStringBuilder, 3);
|
|
502
|
+
} else if (tag.equalsIgnoreCase("h4")) {
|
|
503
|
+
startHeading(mSpannableStringBuilder, 4);
|
|
504
|
+
} else if (tag.equalsIgnoreCase("h5")) {
|
|
505
|
+
startHeading(mSpannableStringBuilder, 5);
|
|
506
|
+
} else if (tag.equalsIgnoreCase("h6")) {
|
|
507
|
+
startHeading(mSpannableStringBuilder, 6);
|
|
508
|
+
} else if (tag.equalsIgnoreCase("img")) {
|
|
509
|
+
startImg(mSpannableStringBuilder, attributes, mSpanFactory);
|
|
510
|
+
} else if (tag.equalsIgnoreCase("code")) {
|
|
511
|
+
start(mSpannableStringBuilder, new Code());
|
|
512
|
+
} else if (tag.equalsIgnoreCase("mention")) {
|
|
513
|
+
startMention(mSpannableStringBuilder, attributes);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
private void handleEndTag(String tag) {
|
|
518
|
+
if (tag.equalsIgnoreCase("br")) {
|
|
519
|
+
handleBr(mSpannableStringBuilder);
|
|
520
|
+
} else if (tag.equalsIgnoreCase("p")) {
|
|
521
|
+
endBlockElement(mSpannableStringBuilder);
|
|
522
|
+
} else if (tag.equalsIgnoreCase("ul")) {
|
|
523
|
+
endBlockElement(mSpannableStringBuilder);
|
|
524
|
+
} else if (tag.equalsIgnoreCase("li")) {
|
|
525
|
+
endLi(mSpannableStringBuilder, mStyle, mSpanFactory);
|
|
526
|
+
} else if (tag.equalsIgnoreCase("b")) {
|
|
527
|
+
end(mSpannableStringBuilder, Bold.class, mSpanFactory.createBoldSpan(mStyle));
|
|
528
|
+
} else if (tag.equalsIgnoreCase("i")) {
|
|
529
|
+
end(mSpannableStringBuilder, Italic.class, mSpanFactory.createItalicSpan(mStyle));
|
|
530
|
+
} else if (tag.equalsIgnoreCase("blockquote")) {
|
|
531
|
+
endBlockquote(mSpannableStringBuilder, mStyle, mSpanFactory);
|
|
532
|
+
} else if (tag.equalsIgnoreCase("codeblock")) {
|
|
533
|
+
endCodeBlock(mSpannableStringBuilder, mStyle, mSpanFactory);
|
|
534
|
+
} else if (tag.equalsIgnoreCase("a")) {
|
|
535
|
+
endA(mSpannableStringBuilder, mStyle, mSpanFactory);
|
|
536
|
+
} else if (tag.equalsIgnoreCase("u")) {
|
|
537
|
+
end(mSpannableStringBuilder, Underline.class, mSpanFactory.createUnderlineSpan(mStyle));
|
|
538
|
+
} else if (tag.equalsIgnoreCase("s")) {
|
|
539
|
+
end(
|
|
540
|
+
mSpannableStringBuilder,
|
|
541
|
+
Strikethrough.class,
|
|
542
|
+
mSpanFactory.createStrikeThroughSpan(mStyle));
|
|
543
|
+
} else if (tag.equalsIgnoreCase("h1")) {
|
|
544
|
+
endHeading(mSpannableStringBuilder, mStyle, mSpanFactory, 1);
|
|
545
|
+
} else if (tag.equalsIgnoreCase("h2")) {
|
|
546
|
+
endHeading(mSpannableStringBuilder, mStyle, mSpanFactory, 2);
|
|
547
|
+
} else if (tag.equalsIgnoreCase("h3")) {
|
|
548
|
+
endHeading(mSpannableStringBuilder, mStyle, mSpanFactory, 3);
|
|
549
|
+
} else if (tag.equalsIgnoreCase("h4")) {
|
|
550
|
+
endHeading(mSpannableStringBuilder, mStyle, mSpanFactory, 4);
|
|
551
|
+
} else if (tag.equalsIgnoreCase("h5")) {
|
|
552
|
+
endHeading(mSpannableStringBuilder, mStyle, mSpanFactory, 5);
|
|
553
|
+
} else if (tag.equalsIgnoreCase("h6")) {
|
|
554
|
+
endHeading(mSpannableStringBuilder, mStyle, mSpanFactory, 6);
|
|
555
|
+
} else if (tag.equalsIgnoreCase("code")) {
|
|
556
|
+
end(mSpannableStringBuilder, Code.class, mSpanFactory.createInlineCodeSpan(mStyle));
|
|
557
|
+
} else if (tag.equalsIgnoreCase("mention")) {
|
|
558
|
+
endMention(mSpannableStringBuilder, mStyle, mSpanFactory);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private static void appendNewlines(Editable text, int minNewline) {
|
|
563
|
+
final int len = text.length();
|
|
564
|
+
if (len == 0) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
int existingNewlines = 0;
|
|
568
|
+
for (int i = len - 1; i >= 0 && text.charAt(i) == '\n'; i--) {
|
|
569
|
+
existingNewlines++;
|
|
570
|
+
}
|
|
571
|
+
for (int j = existingNewlines; j < minNewline; j++) {
|
|
572
|
+
text.append("\n");
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
private static void startBlockElement(Editable text) {
|
|
577
|
+
appendNewlines(text, 1);
|
|
578
|
+
start(text, new Newline(1));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
private static void endBlockElement(Editable text) {
|
|
582
|
+
Newline n = getLast(text, Newline.class);
|
|
583
|
+
if (n != null) {
|
|
584
|
+
appendNewlines(text, n.mNumNewlines);
|
|
585
|
+
text.removeSpan(n);
|
|
586
|
+
}
|
|
587
|
+
Alignment a = getLast(text, Alignment.class);
|
|
588
|
+
if (a != null) {
|
|
589
|
+
setSpanFromMark(text, a, new AlignmentSpan.Standard(a.mAlignment));
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
private static void handleBr(Editable text) {
|
|
594
|
+
text.append('\n');
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private void startLi(Editable text, Attributes attributes) {
|
|
598
|
+
startBlockElement(text);
|
|
599
|
+
|
|
600
|
+
if (isInOrderedList) {
|
|
601
|
+
currentOrderedListItemIndex++;
|
|
602
|
+
start(text, new List("ordered", currentOrderedListItemIndex, false));
|
|
603
|
+
} else if (isInCheckboxList) {
|
|
604
|
+
String isChecked = attributes.getValue("", "checked");
|
|
605
|
+
start(text, new List("checked", 0, "checked".equals(isChecked)));
|
|
606
|
+
} else {
|
|
607
|
+
start(text, new List("unordered", 0, false));
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
private static <T> void endLi(Editable text, T style, EnrichedSpanFactory<T> spanFactory) {
|
|
612
|
+
endBlockElement(text);
|
|
613
|
+
|
|
614
|
+
List l = getLast(text, List.class);
|
|
615
|
+
if (l != null) {
|
|
616
|
+
if (l.mType.equals("ordered")) {
|
|
617
|
+
setParagraphSpanFromMark(text, l, spanFactory.createOrderedListSpan(l.mIndex, style));
|
|
618
|
+
} else if (l.mType.equals("checked")) {
|
|
619
|
+
setParagraphSpanFromMark(text, l, spanFactory.createCheckboxListSpan(l.mChecked, style));
|
|
620
|
+
} else {
|
|
621
|
+
setParagraphSpanFromMark(text, l, spanFactory.createUnorderedListSpan(style));
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
endBlockElement(text);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private void startBlockquote(Editable text) {
|
|
629
|
+
startBlockElement(text);
|
|
630
|
+
start(text, new Blockquote());
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private static <T> void endBlockquote(
|
|
634
|
+
Editable text, T style, EnrichedSpanFactory<T> spanFactory) {
|
|
635
|
+
endBlockElement(text);
|
|
636
|
+
Blockquote last = getLast(text, Blockquote.class);
|
|
637
|
+
setParagraphSpanFromMark(text, last, spanFactory.createBlockQuoteSpan(style));
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private void startCodeBlock(Editable text) {
|
|
641
|
+
startBlockElement(text);
|
|
642
|
+
start(text, new CodeBlock());
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private static <T> void endCodeBlock(Editable text, T style, EnrichedSpanFactory<T> spanFactory) {
|
|
646
|
+
endBlockElement(text);
|
|
647
|
+
CodeBlock last = getLast(text, CodeBlock.class);
|
|
648
|
+
setParagraphSpanFromMark(text, last, spanFactory.createCodeBlockSpan(style));
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
private void startHeading(Editable text, int level) {
|
|
652
|
+
startBlockElement(text);
|
|
653
|
+
|
|
654
|
+
switch (level) {
|
|
655
|
+
case 1:
|
|
656
|
+
start(text, new H1());
|
|
657
|
+
break;
|
|
658
|
+
case 2:
|
|
659
|
+
start(text, new H2());
|
|
660
|
+
break;
|
|
661
|
+
case 3:
|
|
662
|
+
start(text, new H3());
|
|
663
|
+
break;
|
|
664
|
+
case 4:
|
|
665
|
+
start(text, new H4());
|
|
666
|
+
break;
|
|
667
|
+
case 5:
|
|
668
|
+
start(text, new H5());
|
|
669
|
+
break;
|
|
670
|
+
case 6:
|
|
671
|
+
start(text, new H6());
|
|
672
|
+
break;
|
|
673
|
+
default:
|
|
674
|
+
throw new IllegalArgumentException("Unsupported heading level: " + level);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
private static <T> void endHeading(
|
|
679
|
+
Editable text, T style, EnrichedSpanFactory<T> spanFactory, int level) {
|
|
680
|
+
endBlockElement(text);
|
|
681
|
+
|
|
682
|
+
switch (level) {
|
|
683
|
+
case 1:
|
|
684
|
+
H1 lastH1 = getLast(text, H1.class);
|
|
685
|
+
setParagraphSpanFromMark(text, lastH1, spanFactory.createH1Span(style));
|
|
686
|
+
break;
|
|
687
|
+
case 2:
|
|
688
|
+
H2 lastH2 = getLast(text, H2.class);
|
|
689
|
+
setParagraphSpanFromMark(text, lastH2, spanFactory.createH2Span(style));
|
|
690
|
+
break;
|
|
691
|
+
case 3:
|
|
692
|
+
H3 lastH3 = getLast(text, H3.class);
|
|
693
|
+
setParagraphSpanFromMark(text, lastH3, spanFactory.createH3Span(style));
|
|
694
|
+
break;
|
|
695
|
+
case 4:
|
|
696
|
+
H4 lastH4 = getLast(text, H4.class);
|
|
697
|
+
setParagraphSpanFromMark(text, lastH4, spanFactory.createH4Span(style));
|
|
698
|
+
break;
|
|
699
|
+
case 5:
|
|
700
|
+
H5 lastH5 = getLast(text, H5.class);
|
|
701
|
+
setParagraphSpanFromMark(text, lastH5, spanFactory.createH5Span(style));
|
|
702
|
+
break;
|
|
703
|
+
case 6:
|
|
704
|
+
H6 lastH6 = getLast(text, H6.class);
|
|
705
|
+
setParagraphSpanFromMark(text, lastH6, spanFactory.createH6Span(style));
|
|
706
|
+
break;
|
|
707
|
+
default:
|
|
708
|
+
throw new IllegalArgumentException("Unsupported heading level: " + level);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private static <T> T getLast(Spanned text, Class<T> kind) {
|
|
713
|
+
/*
|
|
714
|
+
* This knows that the last returned object from getSpans()
|
|
715
|
+
* will be the most recently added.
|
|
716
|
+
*/
|
|
717
|
+
T[] objs = text.getSpans(0, text.length(), kind);
|
|
718
|
+
if (objs.length == 0) {
|
|
719
|
+
return null;
|
|
720
|
+
} else {
|
|
721
|
+
return objs[objs.length - 1];
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
private static void setSpanFromMark(Spannable text, Object mark, Object... spans) {
|
|
726
|
+
int where = text.getSpanStart(mark);
|
|
727
|
+
text.removeSpan(mark);
|
|
728
|
+
int len = text.length();
|
|
729
|
+
if (where != len) {
|
|
730
|
+
for (Object span : spans) {
|
|
731
|
+
text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
private static void setParagraphSpanFromMark(Editable text, Object mark, Object... spans) {
|
|
737
|
+
int where = text.getSpanStart(mark);
|
|
738
|
+
text.removeSpan(mark);
|
|
739
|
+
int len = text.length();
|
|
740
|
+
|
|
741
|
+
// Block spans require at least one character to be applied.
|
|
742
|
+
if (isEmptyTag) {
|
|
743
|
+
text.append(EnrichedConstants.ZWS);
|
|
744
|
+
len++;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Adjust the end position to exclude the newline character, if present
|
|
748
|
+
if (len > 0 && text.charAt(len - 1) == '\n') {
|
|
749
|
+
len--;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (where != len) {
|
|
753
|
+
for (Object span : spans) {
|
|
754
|
+
text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
private static void start(Editable text, Object mark) {
|
|
760
|
+
int len = text.length();
|
|
761
|
+
text.setSpan(mark, len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
private static void end(Editable text, Class kind, Object repl) {
|
|
765
|
+
Object obj = getLast(text, kind);
|
|
766
|
+
if (obj != null) {
|
|
767
|
+
setSpanFromMark(text, obj, repl);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
private static <T> void startImg(
|
|
772
|
+
Editable text, Attributes attributes, EnrichedSpanFactory<T> spanFactory) {
|
|
773
|
+
String src = attributes.getValue("", "src");
|
|
774
|
+
String width = attributes.getValue("", "width");
|
|
775
|
+
String height = attributes.getValue("", "height");
|
|
776
|
+
|
|
777
|
+
int len = text.length();
|
|
778
|
+
text.append("");
|
|
779
|
+
text.setSpan(
|
|
780
|
+
spanFactory.createImageSpan(src, Integer.parseInt(width), Integer.parseInt(height)),
|
|
781
|
+
len,
|
|
782
|
+
text.length(),
|
|
783
|
+
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
private static void startA(Editable text, Attributes attributes) {
|
|
787
|
+
String href = attributes.getValue("", "href");
|
|
788
|
+
start(text, new Href(href));
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
private static <T> void endA(Editable text, T style, EnrichedSpanFactory<T> spanFactory) {
|
|
792
|
+
Href h = getLast(text, Href.class);
|
|
793
|
+
if (h != null) {
|
|
794
|
+
if (h.mHref != null) {
|
|
795
|
+
setSpanFromMark(text, h, spanFactory.createLinkSpan(h.mHref, style));
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
private static void startMention(Editable mention, Attributes attributes) {
|
|
801
|
+
String text = attributes.getValue("", "text");
|
|
802
|
+
String indicator = attributes.getValue("", "indicator");
|
|
803
|
+
|
|
804
|
+
Map<String, String> attributesMap = new HashMap<>();
|
|
805
|
+
for (int i = 0; i < attributes.getLength(); i++) {
|
|
806
|
+
String localName = attributes.getLocalName(i);
|
|
807
|
+
|
|
808
|
+
if (!"text".equals(localName) && !"indicator".equals(localName)) {
|
|
809
|
+
attributesMap.put(localName, attributes.getValue(i));
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
start(mention, new Mention(indicator, text, attributesMap));
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
private static <T> void endMention(Editable text, T style, EnrichedSpanFactory<T> spanFactory) {
|
|
817
|
+
Mention m = getLast(text, Mention.class);
|
|
818
|
+
|
|
819
|
+
if (m == null) return;
|
|
820
|
+
if (m.mText == null) return;
|
|
821
|
+
|
|
822
|
+
setSpanFromMark(
|
|
823
|
+
text, m, spanFactory.createMentionSpan(m.mText, m.mIndicator, m.mAttributes, style));
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
public void setDocumentLocator(Locator locator) {}
|
|
827
|
+
|
|
828
|
+
public void startDocument() {}
|
|
829
|
+
|
|
830
|
+
public void endDocument() {}
|
|
831
|
+
|
|
832
|
+
public void startPrefixMapping(String prefix, String uri) {}
|
|
833
|
+
|
|
834
|
+
public void endPrefixMapping(String prefix) {}
|
|
835
|
+
|
|
836
|
+
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
|
837
|
+
handleStartTag(localName, attributes);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
public void endElement(String uri, String localName, String qName) {
|
|
841
|
+
handleEndTag(localName);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
public void characters(char[] ch, int start, int length) {
|
|
845
|
+
StringBuilder sb = new StringBuilder();
|
|
846
|
+
if (length > 0) isEmptyTag = false;
|
|
847
|
+
|
|
848
|
+
/*
|
|
849
|
+
* Ignore whitespace that immediately follows other whitespace;
|
|
850
|
+
* newlines count as spaces.
|
|
851
|
+
*/
|
|
852
|
+
for (int i = 0; i < length; i++) {
|
|
853
|
+
char c = ch[i + start];
|
|
854
|
+
if (c == ' ' || c == '\n') {
|
|
855
|
+
char pred;
|
|
856
|
+
int len = sb.length();
|
|
857
|
+
if (len == 0) {
|
|
858
|
+
len = mSpannableStringBuilder.length();
|
|
859
|
+
if (len == 0) {
|
|
860
|
+
pred = '\n';
|
|
861
|
+
} else {
|
|
862
|
+
pred = mSpannableStringBuilder.charAt(len - 1);
|
|
863
|
+
}
|
|
864
|
+
} else {
|
|
865
|
+
pred = sb.charAt(len - 1);
|
|
866
|
+
}
|
|
867
|
+
if (pred != ' ' && pred != '\n') {
|
|
868
|
+
sb.append(' ');
|
|
869
|
+
}
|
|
870
|
+
} else {
|
|
871
|
+
sb.append(c);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
mSpannableStringBuilder.append(sb);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
public void ignorableWhitespace(char[] ch, int start, int length) {}
|
|
878
|
+
|
|
879
|
+
public void processingInstruction(String target, String data) {}
|
|
880
|
+
|
|
881
|
+
public void skippedEntity(String name) {}
|
|
882
|
+
|
|
883
|
+
private static class H1 {}
|
|
884
|
+
|
|
885
|
+
private static class H2 {}
|
|
886
|
+
|
|
887
|
+
private static class H3 {}
|
|
888
|
+
|
|
889
|
+
private static class H4 {}
|
|
890
|
+
|
|
891
|
+
private static class H5 {}
|
|
892
|
+
|
|
893
|
+
private static class H6 {}
|
|
894
|
+
|
|
895
|
+
private static class Bold {}
|
|
896
|
+
|
|
897
|
+
private static class Italic {}
|
|
898
|
+
|
|
899
|
+
private static class Underline {}
|
|
900
|
+
|
|
901
|
+
private static class Code {}
|
|
902
|
+
|
|
903
|
+
private static class CodeBlock {}
|
|
904
|
+
|
|
905
|
+
private static class Strikethrough {}
|
|
906
|
+
|
|
907
|
+
private static class Blockquote {}
|
|
908
|
+
|
|
909
|
+
private static class List {
|
|
910
|
+
public int mIndex;
|
|
911
|
+
public String mType;
|
|
912
|
+
public boolean mChecked;
|
|
913
|
+
|
|
914
|
+
public List(String type, int index, boolean checked) {
|
|
915
|
+
mType = type;
|
|
916
|
+
mIndex = index;
|
|
917
|
+
mChecked = checked;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
private static class Mention {
|
|
922
|
+
public Map<String, String> mAttributes;
|
|
923
|
+
public String mIndicator;
|
|
924
|
+
public String mText;
|
|
925
|
+
|
|
926
|
+
public Mention(String indicator, String text, Map<String, String> attributes) {
|
|
927
|
+
mIndicator = indicator;
|
|
928
|
+
mAttributes = attributes;
|
|
929
|
+
mText = text;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
private static class Href {
|
|
934
|
+
public String mHref;
|
|
935
|
+
|
|
936
|
+
public Href(String href) {
|
|
937
|
+
mHref = href;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
private static class Newline {
|
|
942
|
+
private final int mNumNewlines;
|
|
943
|
+
|
|
944
|
+
public Newline(int numNewlines) {
|
|
945
|
+
mNumNewlines = numNewlines;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
private static class Alignment {
|
|
950
|
+
private final Layout.Alignment mAlignment;
|
|
951
|
+
|
|
952
|
+
public Alignment(Layout.Alignment alignment) {
|
|
953
|
+
mAlignment = alignment;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|