mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-11-22 14:18:32 +03:00
Merge pull request #2216 from ecency/sa/add-link-in-post
Insert URL Modal
This commit is contained in:
commit
bb54274837
@ -416,6 +416,8 @@ PODS:
|
||||
- React-Core
|
||||
- RNCAsyncStorage (1.12.1):
|
||||
- React-Core
|
||||
- RNCClipboard (1.8.5):
|
||||
- React-Core
|
||||
- RNCPushNotificationIOS (1.8.0):
|
||||
- React-Core
|
||||
- RNFastImage (8.3.4):
|
||||
@ -529,6 +531,7 @@ DEPENDENCIES:
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
|
||||
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
|
||||
- RNFastImage (from `../node_modules/react-native-fast-image`)
|
||||
- "RNFBAnalytics (from `../node_modules/@react-native-firebase/analytics`)"
|
||||
@ -674,6 +677,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/rn-fetch-blob"
|
||||
RNCAsyncStorage:
|
||||
:path: "../node_modules/@react-native-community/async-storage"
|
||||
RNCClipboard:
|
||||
:path: "../node_modules/@react-native-clipboard/clipboard"
|
||||
RNCPushNotificationIOS:
|
||||
:path: "../node_modules/@react-native-community/push-notification-ios"
|
||||
RNFastImage:
|
||||
@ -781,6 +786,7 @@ SPEC CHECKSUMS:
|
||||
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
|
||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
|
||||
RNCClipboard: cc054ad1e8a33d2a74cd13e565588b4ca928d8fd
|
||||
RNCPushNotificationIOS: 61a7c72bd1ebad3568025957d001e0f0e7b32191
|
||||
RNFastImage: d4870d58f5936111c56218dbd7fcfc18e65b58ff
|
||||
RNFBAnalytics: 6414e9fe1f36c3074f39cd6265b3def777dbfbdb
|
||||
|
@ -37,6 +37,7 @@
|
||||
"@hiveio/dhive": "^1.0.1",
|
||||
"@native-html/iframe-plugin": "^2.6.1",
|
||||
"@native-html/table-plugin": "^5.3.1",
|
||||
"@react-native-clipboard/clipboard": "^1.8.5",
|
||||
"@react-native-community/async-storage": "^1.11.0",
|
||||
"@react-native-community/cameraroll": "^1.3.0",
|
||||
"@react-native-community/cli-platform-ios": "^4.10.1",
|
||||
@ -104,7 +105,7 @@
|
||||
"react-native-linear-gradient": "^2.4.2",
|
||||
"react-native-matomo-sdk": "feruzm/react-native-matomo-sdk",
|
||||
"react-native-media-controls": "^2.3.0",
|
||||
"react-native-modal": "^11.5.6",
|
||||
"react-native-modal": "11.5.6",
|
||||
"react-native-modal-dropdown": "^1.0.2",
|
||||
"react-native-modal-popover": "^2.1.0",
|
||||
"react-native-modal-translucent": "^5.0.0",
|
||||
|
@ -69,7 +69,7 @@ import { HorizontalIconList } from './horizontalIconList/horizontalIconListView'
|
||||
import { PopoverWrapper } from './popoverWrapper/popoverWrapperView';
|
||||
import CommunitiesList from './communitiesList';
|
||||
import SubscribedCommunitiesList from './subscribedCommunitiesList';
|
||||
|
||||
import { InsertLinkModal } from './insertLinkModal/insertLinkModal';
|
||||
// View
|
||||
import { Comment } from './comment';
|
||||
import { Comments } from './comments';
|
||||
@ -240,6 +240,7 @@ export {
|
||||
QuickReplyModal,
|
||||
Tooltip,
|
||||
VideoPlayer,
|
||||
InsertLinkModal,
|
||||
QRModal,
|
||||
SimpleChart,
|
||||
};
|
||||
|
306
src/components/insertLinkModal/insertLinkModal.tsx
Normal file
306
src/components/insertLinkModal/insertLinkModal.tsx
Normal file
@ -0,0 +1,306 @@
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import {
|
||||
Platform,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ActivityIndicator,
|
||||
Dimensions,
|
||||
} from 'react-native';
|
||||
import { MainButton, PostBody, TextButton } from '..';
|
||||
import styles from './insertLinkModalStyles';
|
||||
import ActionSheet from 'react-native-actions-sheet';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import TextInput from '../textInput';
|
||||
import { delay } from '../../utils/editor';
|
||||
import { isStringWebLink } from '../markdownEditor/view/formats/utils';
|
||||
import { renderPostBody } from '@ecency/render-helper';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import applyWebLinkFormat from '../markdownEditor/view/formats/applyWebLinkFormat';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
|
||||
interface InsertLinkModalProps {
|
||||
handleOnInsertLink: ({
|
||||
snippetText,
|
||||
selection,
|
||||
}: {
|
||||
snippetText: string;
|
||||
selection: { start: number; end: number };
|
||||
}) => void;
|
||||
handleOnSheetClose: () => void;
|
||||
}
|
||||
const screenWidth = Dimensions.get('window').width - 58;
|
||||
const previewWidth = (10 / 16) * Dimensions.get('window').width;
|
||||
|
||||
export const InsertLinkModal = forwardRef(
|
||||
({ handleOnInsertLink, handleOnSheetClose }: InsertLinkModalProps, ref) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [label, setLabel] = useState('');
|
||||
const [url, setUrl] = useState('');
|
||||
const [isUrlValid, setIsUrlValid] = useState(true);
|
||||
const [selectedText, setSelectedText] = useState('');
|
||||
const [formattedText, setFormattedText] = useState('');
|
||||
const [selection, setSelection] = useState({ start: 0, end: 0 });
|
||||
const [selectedUrlType, setSelectedUrlType] = useState(0);
|
||||
const [previewBody, setPreviewBody] = useState('');
|
||||
const sheetModalRef = useRef<ActionSheet>();
|
||||
const labelInputRef = useRef(null);
|
||||
const urlInputRef = useRef(null);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
showModal: async ({ selectedText, selection }) => {
|
||||
if (selectedText) {
|
||||
setSelectedText(selectedText);
|
||||
setSelection(selection);
|
||||
if (selection && selection.start !== selection.end) {
|
||||
if (isStringWebLink(selectedText)) {
|
||||
setUrl(selectedText);
|
||||
} else {
|
||||
setLabel(selectedText);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fetchCopiedText();
|
||||
setSelection(selection);
|
||||
}
|
||||
|
||||
sheetModalRef.current?.setModalVisible(true);
|
||||
await delay(1500);
|
||||
labelInputRef.current?.focus();
|
||||
},
|
||||
hideModal: () => {
|
||||
sheetModalRef.current?.setModalVisible(false);
|
||||
},
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (isStringWebLink(url)) {
|
||||
setIsUrlValid(true);
|
||||
}
|
||||
if (url) {
|
||||
const labelText =
|
||||
selectedUrlType === 2 ? url.split('/').pop() : selectedUrlType === 1 ? '' : label;
|
||||
applyWebLinkFormat({
|
||||
item: { text: labelText, url: url },
|
||||
text: '',
|
||||
selection: { start: 0, end: 0 },
|
||||
setTextAndSelection: _setFormattedTextAndSelection,
|
||||
isImage: selectedUrlType === 2,
|
||||
isVideo: selectedUrlType === 1,
|
||||
});
|
||||
} else {
|
||||
setPreviewBody('');
|
||||
}
|
||||
}, [label, url, selectedUrlType]);
|
||||
|
||||
const fetchCopiedText = async () => {
|
||||
const text = await Clipboard.getString();
|
||||
if (isStringWebLink(text)) {
|
||||
setUrl(text);
|
||||
}
|
||||
};
|
||||
|
||||
const _setFormattedTextAndSelection = ({ selection, text }) => {
|
||||
setPreviewBody(renderPostBody(text, true, Platform.OS === 'ios' ? false : true));
|
||||
setFormattedText(text);
|
||||
};
|
||||
|
||||
const _handleLabelChange = (text) => {
|
||||
setLabel(text);
|
||||
};
|
||||
const _handleUrlChange = (text) => {
|
||||
setUrl(text);
|
||||
};
|
||||
|
||||
const _handleOnCloseSheet = () => {
|
||||
labelInputRef.current?.blur();
|
||||
setLabel('');
|
||||
setUrl('');
|
||||
setSelectedUrlType(0);
|
||||
setPreviewBody('');
|
||||
setIsUrlValid(true);
|
||||
setSelectedText('');
|
||||
setFormattedText('');
|
||||
handleOnSheetClose();
|
||||
};
|
||||
|
||||
const _handleInsert = () => {
|
||||
if (!isStringWebLink(url)) {
|
||||
setIsUrlValid(false);
|
||||
return;
|
||||
}
|
||||
handleOnInsertLink({ snippetText: formattedText, selection: selection });
|
||||
setIsUrlValid(true);
|
||||
};
|
||||
const _renderFloatingPanel = () => {
|
||||
return (
|
||||
<View style={styles.floatingContainer}>
|
||||
<TextButton
|
||||
style={styles.cancelButton}
|
||||
onPress={() => sheetModalRef.current?.setModalVisible(false)}
|
||||
text={'Cancel'}
|
||||
/>
|
||||
<MainButton
|
||||
style={styles.insertBtn}
|
||||
onPress={() => _handleInsert()}
|
||||
iconName="plus"
|
||||
iconType="MaterialCommunityIcons"
|
||||
iconColor="white"
|
||||
text={'Insert Link'}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const URL_TYPES = [
|
||||
{
|
||||
id: 0,
|
||||
title: intl.formatMessage({
|
||||
id: 'editor.plain',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: intl.formatMessage({
|
||||
id: 'editor.video',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: intl.formatMessage({
|
||||
id: 'editor.image',
|
||||
}),
|
||||
},
|
||||
];
|
||||
const LinkTypeOptions = URL_TYPES.map((item) => {
|
||||
const selected = item.id === selectedUrlType;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
setSelectedUrlType(item.id);
|
||||
if (item.id === 0) {
|
||||
labelInputRef.current?.focus();
|
||||
} else {
|
||||
labelInputRef.current?.blur();
|
||||
urlInputRef.current?.focus();
|
||||
}
|
||||
}}
|
||||
style={selected ? styles.optionBtnSelected : styles.optionBtn}
|
||||
>
|
||||
<Text style={selected ? styles.optionBtnTextSelected : styles.optionBtnText}>
|
||||
{item.title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
|
||||
const _renderLabelInput = () => (
|
||||
<>
|
||||
<Text style={styles.inputLabel}>
|
||||
{intl.formatMessage({
|
||||
id: 'editor.label',
|
||||
})}
|
||||
</Text>
|
||||
<TextInput
|
||||
style={[styles.input, selectedUrlType !== 0 && styles.disabled]}
|
||||
value={label}
|
||||
onChangeText={_handleLabelChange}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'editor.enter_label_placeholder',
|
||||
})}
|
||||
placeholderTextColor="#c1c5c7"
|
||||
autoCapitalize="none"
|
||||
editable={selectedUrlType === 0}
|
||||
innerRef={labelInputRef}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
const _renderInputs = () => (
|
||||
<View style={styles.inputsContainer}>
|
||||
<Text style={styles.inputLabel}>
|
||||
{intl.formatMessage({
|
||||
id: 'editor.link_type_text',
|
||||
})}
|
||||
</Text>
|
||||
<View style={styles.optionsRow}>{LinkTypeOptions}</View>
|
||||
{_renderLabelInput()}
|
||||
<Text style={styles.inputLabel}>
|
||||
{intl.formatMessage({
|
||||
id: 'editor.url',
|
||||
})}
|
||||
</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
value={url}
|
||||
onChangeText={_handleUrlChange}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'editor.enter_url_placeholder',
|
||||
})}
|
||||
placeholderTextColor="#c1c5c7"
|
||||
autoCapitalize="none"
|
||||
keyboardType="url"
|
||||
innerRef={urlInputRef}
|
||||
/>
|
||||
{!isUrlValid && (
|
||||
<Text style={styles.validText}>
|
||||
{intl.formatMessage({
|
||||
id: 'editor.invalid_url_error',
|
||||
})}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
const _renderPreview = () => {
|
||||
return (
|
||||
<>
|
||||
<View style={styles.previewContainer}>
|
||||
<Text style={styles.previewText}>
|
||||
{intl.formatMessage({
|
||||
id: 'editor.preview',
|
||||
})}
|
||||
</Text>
|
||||
<ScrollView
|
||||
style={styles.previewWrapper}
|
||||
contentContainerStyle={styles.previewContentContainer}
|
||||
>
|
||||
<View style={styles.preview} pointerEvents="none">
|
||||
{previewBody ? (
|
||||
<PostBody
|
||||
body={previewBody}
|
||||
onLoadEnd={() => setIsLoading(false)}
|
||||
width={screenWidth}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
</ScrollView>
|
||||
{isLoading && <ActivityIndicator color={'$primaryBlue'} />}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
const _renderContent = (
|
||||
<ScrollView style={styles.container} keyboardShouldPersistTaps={'handled'}>
|
||||
{_renderInputs()}
|
||||
{_renderPreview()}
|
||||
{_renderFloatingPanel()}
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
return (
|
||||
<ActionSheet
|
||||
ref={sheetModalRef}
|
||||
gestureEnabled={true}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
containerStyle={styles.sheetContent}
|
||||
keyboardHandlerEnabled
|
||||
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
|
||||
onClose={_handleOnCloseSheet}
|
||||
>
|
||||
{_renderContent}
|
||||
</ActionSheet>
|
||||
);
|
||||
},
|
||||
);
|
121
src/components/insertLinkModal/insertLinkModalStyles.ts
Normal file
121
src/components/insertLinkModal/insertLinkModalStyles.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import { ViewStyle, Dimensions } from 'react-native';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
const previewHeight = (10 / 16) * Dimensions.get('window').width;
|
||||
export default EStyleSheet.create({
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 999,
|
||||
},
|
||||
modalStyle: {
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
margin: 0,
|
||||
paddingTop: 32,
|
||||
paddingBottom: 16,
|
||||
},
|
||||
container: {
|
||||
paddingVertical: 8,
|
||||
},
|
||||
bodyWrapper: {
|
||||
flex: 3,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
floatingContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 16,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
} as ViewStyle,
|
||||
insertBtn: {
|
||||
marginLeft: 16,
|
||||
width: 170,
|
||||
},
|
||||
inputsContainer: {
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
inputLabel: {
|
||||
color: '$primaryBlack',
|
||||
fontWeight: '600',
|
||||
textAlign: 'left',
|
||||
},
|
||||
input: {
|
||||
borderWidth: 1,
|
||||
borderColor: '$borderColor',
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 10,
|
||||
color: '$primaryBlack',
|
||||
marginVertical: 8,
|
||||
height: 50,
|
||||
},
|
||||
validText: {
|
||||
color: '$primaryRed',
|
||||
marginVertical: 4,
|
||||
},
|
||||
optionsRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginVertical: 12,
|
||||
},
|
||||
optionBtnSelected: {
|
||||
maxWidth: 75,
|
||||
borderWidth: 1,
|
||||
borderColor: '$primaryBlue',
|
||||
backgroundColor: '$primaryBlue',
|
||||
borderRadius: 15,
|
||||
paddingVertical: 4,
|
||||
paddingHorizontal: 12,
|
||||
marginRight: 8,
|
||||
},
|
||||
optionBtnTextSelected: {
|
||||
textAlign: 'center',
|
||||
color: '$white',
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
optionBtn: {
|
||||
maxWidth: 75,
|
||||
borderWidth: 1,
|
||||
borderColor: '$primaryBlue',
|
||||
borderRadius: 15,
|
||||
paddingVertical: 4,
|
||||
paddingHorizontal: 12,
|
||||
marginRight: 8,
|
||||
},
|
||||
optionBtnText: {
|
||||
textAlign: 'center',
|
||||
color: '$primaryBlue',
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
previewContainer: {},
|
||||
previewText: {
|
||||
color: '$primaryBlack',
|
||||
fontWeight: '600',
|
||||
textAlign: 'left',
|
||||
paddingLeft: 16,
|
||||
marginVertical: 8,
|
||||
},
|
||||
previewWrapper: {
|
||||
height: previewHeight,
|
||||
marginHorizontal: 16,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: '$borderColor',
|
||||
},
|
||||
previewContentContainer: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
preview: {
|
||||
paddingLeft: 12,
|
||||
paddingRight: 12,
|
||||
},
|
||||
disabled: {
|
||||
backgroundColor: '$modalBackground',
|
||||
},
|
||||
});
|
@ -1,11 +1,10 @@
|
||||
import {replaceBetween } from './utils';
|
||||
|
||||
export default async ({ text, selection, setTextAndSelection, snippetText}) => {
|
||||
|
||||
const newText = replaceBetween(text, selection, `\n${snippetText}\n`);
|
||||
export default async ({ text, selection, setTextAndSelection, snippetText}) => {
|
||||
const newText = replaceBetween(text, selection, `${snippetText}`);
|
||||
const newSelection = {
|
||||
start: selection.start + 1,
|
||||
end: selection.start + 1 + (snippetText && snippetText.length),
|
||||
start: selection.start,
|
||||
end: selection.start + (snippetText && snippetText.length),
|
||||
};
|
||||
setTextAndSelection({ text: newText, selection: newSelection });
|
||||
};
|
@ -3,30 +3,52 @@ import { isStringWebLink, replaceBetween } from './utils';
|
||||
export const writeUrlTextHere = 'https://example.com';
|
||||
export const writeTextHereString = 'Text here';
|
||||
|
||||
export default async ({ text, selection, setTextAndSelection, item, isImage = null }) => {
|
||||
export default async ({
|
||||
text,
|
||||
selection,
|
||||
setTextAndSelection,
|
||||
item,
|
||||
isImage = null,
|
||||
isVideo = null,
|
||||
}) => {
|
||||
const imagePrefix = isImage ? '!' : '';
|
||||
const itemText = item ? item.text : writeTextHereString;
|
||||
const itemUrl = item ? item.url : writeUrlTextHere;
|
||||
const isRawUrl = item && !item.text;
|
||||
let newText;
|
||||
let newSelection;
|
||||
const selectedText = text.substring(selection.start, selection.end);
|
||||
|
||||
if (selection.start !== selection.end) {
|
||||
if (isStringWebLink(selectedText)) {
|
||||
newText = replaceBetween(text, selection, `\n${imagePrefix}[${itemText}](${selectedText})\n`);
|
||||
newText = replaceBetween(text, selection, `${imagePrefix}[${itemText}](${selectedText})`);
|
||||
newSelection = {
|
||||
start: selection.start + 1,
|
||||
end: selection.start + 1 + itemText && itemText.length,
|
||||
// start: selection.start + 1,
|
||||
// end: selection.start + 1 + itemText && itemText.length,
|
||||
start: newText.length,
|
||||
end: newText.length,
|
||||
};
|
||||
} else {
|
||||
newText = replaceBetween(text, selection, `\n${imagePrefix}[${selectedText}](${itemUrl})\n`);
|
||||
newText = replaceBetween(text, selection, `${imagePrefix}[${selectedText}](${itemUrl})`);
|
||||
newSelection = {
|
||||
start: selection.end + 3,
|
||||
end: selection.end + 3 + itemUrl.length,
|
||||
// start: selection.end + 3,
|
||||
// end: selection.end + 3 + itemUrl.length,
|
||||
start: newText.length,
|
||||
end: newText.length,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
newText = replaceBetween(text, selection, `\n${imagePrefix}[${itemText}](${itemUrl})\n`);
|
||||
newText = replaceBetween(
|
||||
text,
|
||||
selection,
|
||||
isVideo
|
||||
? `\n${itemUrl}\n`
|
||||
: isRawUrl
|
||||
? `${itemUrl}`
|
||||
: isImage
|
||||
? `\n${imagePrefix}[${itemText}](${itemUrl})\n`
|
||||
: `${imagePrefix}[${itemText}](${itemUrl})`,
|
||||
);
|
||||
if (isImage) {
|
||||
const newIndex = newText && newText.indexOf(itemUrl) + 2 + itemUrl.length;
|
||||
newSelection = {
|
||||
@ -35,8 +57,10 @@ export default async ({ text, selection, setTextAndSelection, item, isImage = nu
|
||||
};
|
||||
} else {
|
||||
newSelection = {
|
||||
start: selection.start + 1,
|
||||
end: selection.start + 1 + (itemText && itemText.length),
|
||||
start: newText.length,
|
||||
end: newText.length,
|
||||
// start: hasLabel ? selection.start + 1 : 0,
|
||||
// end: hasLabel ? selection.start + 1 + (itemText && itemText.length) : 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import { Icon } from '../../icon';
|
||||
// Utils
|
||||
import Formats from './formats/formats';
|
||||
import applyMediaLink from './formats/applyMediaLink';
|
||||
import applyWebLinkFormat from './formats/applyWebLinkFormat';
|
||||
|
||||
// Actions
|
||||
import { toggleAccountsBottomSheet } from '../../../redux/actions/uiAction';
|
||||
@ -37,6 +38,7 @@ import {
|
||||
SnippetsModal,
|
||||
UploadsGalleryModal,
|
||||
Tooltip,
|
||||
InsertLinkModal,
|
||||
} from '../../index';
|
||||
|
||||
import { ThemeContainer } from '../../../containers';
|
||||
@ -90,6 +92,7 @@ const MarkdownEditorView = ({
|
||||
const galleryRef = useRef(null);
|
||||
const clearRef = useRef(null);
|
||||
const uploadsGalleryModalRef = useRef(null);
|
||||
const insertLinkModalRef = useRef(null);
|
||||
const tooltipRef = useRef(null);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
@ -232,6 +235,7 @@ const MarkdownEditorView = ({
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const _setTextAndSelection = useCallback(({ selection: _selection, text: _text }) => {
|
||||
console.log('_text : ', _text);
|
||||
inputRef.current.setNativeProps({
|
||||
text: _text,
|
||||
});
|
||||
@ -255,6 +259,7 @@ const MarkdownEditorView = ({
|
||||
_changeText(_text);
|
||||
});
|
||||
|
||||
console.log('text : ', text);
|
||||
const _renderPreview = () => (
|
||||
<ScrollView style={styles.previewContainer}>
|
||||
{text ? (
|
||||
@ -270,7 +275,7 @@ const MarkdownEditorView = ({
|
||||
text,
|
||||
selection,
|
||||
setTextAndSelection: _setTextAndSelection,
|
||||
snippetText,
|
||||
snippetText: `\n${snippetText}\n`,
|
||||
});
|
||||
};
|
||||
|
||||
@ -290,6 +295,26 @@ const MarkdownEditorView = ({
|
||||
}
|
||||
};
|
||||
|
||||
const _handleOnAddLinkPress = () => {
|
||||
insertLinkModalRef.current?.showModal({
|
||||
selectedText: text.slice(selection.start, selection.end),
|
||||
selection: selection,
|
||||
});
|
||||
inputRef.current?.blur();
|
||||
};
|
||||
const _handleOnAddLinkSheetClose = () => {
|
||||
inputRef.current?.focus();
|
||||
};
|
||||
const _handleInsertLink = ({ snippetText, selection }) => {
|
||||
applySnippet({
|
||||
text,
|
||||
selection,
|
||||
setTextAndSelection: _setTextAndSelection,
|
||||
snippetText,
|
||||
});
|
||||
|
||||
insertLinkModalRef.current?.hideModal();
|
||||
};
|
||||
const _renderMarkupButton = ({ item }) => (
|
||||
<View style={styles.buttonWrapper}>
|
||||
<IconButton
|
||||
@ -355,7 +380,8 @@ const MarkdownEditorView = ({
|
||||
iconType="FontAwesome"
|
||||
name="link"
|
||||
onPress={() =>
|
||||
Formats[3].onPress({ text, selection, setTextAndSelection: _setTextAndSelection })
|
||||
// Formats[3].onPress({ text, selection, setTextAndSelection: _setTextAndSelection })
|
||||
_handleOnAddLinkPress()
|
||||
}
|
||||
/>
|
||||
<IconButton
|
||||
@ -509,6 +535,12 @@ const MarkdownEditorView = ({
|
||||
uploadedImage={uploadedImage}
|
||||
/>
|
||||
|
||||
<InsertLinkModal
|
||||
ref={insertLinkModalRef}
|
||||
handleOnInsertLink={_handleInsertLink}
|
||||
handleOnSheetClose={_handleOnAddLinkSheetClose}
|
||||
/>
|
||||
|
||||
<OptionsModal
|
||||
ref={galleryRef}
|
||||
options={[
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
import ModalBox from 'react-native-modal';
|
||||
import { default as ModalBox } from 'react-native-modal';
|
||||
import { IconButton } from '../../iconButton';
|
||||
import styles from './modalStyles';
|
||||
|
||||
|
@ -22,7 +22,8 @@ import { PostHtmlRenderer, VideoPlayer } from '../../..';
|
||||
|
||||
const WIDTH = Dimensions.get('window').width;
|
||||
|
||||
const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
|
||||
const PostBody = ({ navigation, body, dispatch, onLoadEnd, width }) => {
|
||||
console.log('body : ', body);
|
||||
const [isImageModalOpen, setIsImageModalOpen] = useState(false);
|
||||
|
||||
const [postImages, setPostImages] = useState([]);
|
||||
@ -331,7 +332,7 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
|
||||
<View>
|
||||
<PostHtmlRenderer
|
||||
body={html}
|
||||
contentWidth={WIDTH - 32}
|
||||
contentWidth={width ? width : WIDTH - 32}
|
||||
onLoaded={_handleLoadEnd}
|
||||
onElementIsImage={_onElementIsImage}
|
||||
setSelectedImage={_handleSetSelectedImage}
|
||||
@ -348,7 +349,7 @@ const PostBody = ({ navigation, body, dispatch, onLoadEnd }) => {
|
||||
};
|
||||
|
||||
const areEqual = (prevProps, nextProps) => {
|
||||
if (prevProps.body !== nextProps.body) {
|
||||
if (prevProps.body === nextProps.body) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -13,7 +13,7 @@ export default EStyleSheet.create({
|
||||
flex: 1,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
minHeight: 50,
|
||||
// flex: 1,
|
||||
// minHeight: 50,
|
||||
},
|
||||
});
|
||||
|
@ -368,7 +368,17 @@
|
||||
"done":"DONE",
|
||||
"draft_save_title":"Saving Draft",
|
||||
"draft_update":"Update current draft",
|
||||
"draft_save_new":"Save as new draft"
|
||||
"draft_save_new":"Save as new draft",
|
||||
"label":"Label",
|
||||
"enter_label_placeholder":"Enter Label (Optional)",
|
||||
"url": "URL",
|
||||
"enter_url_placeholder":"Enter URL",
|
||||
"link_type_text":"Type of Link",
|
||||
"preview":"Preview",
|
||||
"invalid_url_error":"Please insert valid url",
|
||||
"plain":"Plain",
|
||||
"video":"Video",
|
||||
"image":"Image"
|
||||
},
|
||||
"snippets":{
|
||||
"label_no_snippets":"No Snippets Found",
|
||||
|
@ -232,3 +232,5 @@ export const createPatch = (text1, text2) => {
|
||||
|
||||
return patch;
|
||||
};
|
||||
|
||||
export const delay = ms => new Promise(res => setTimeout(res, ms));
|
||||
|
13
yarn.lock
13
yarn.lock
@ -1482,6 +1482,11 @@
|
||||
dependencies:
|
||||
merge-options "^3.0.4"
|
||||
|
||||
"@react-native-clipboard/clipboard@^1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-clipboard/clipboard/-/clipboard-1.8.5.tgz#b11276e38ef288b0fd70c0a38506e2deecc5fa5a"
|
||||
integrity sha512-o2RPDwP9JMnLece1Qq6a3Fsz/VxfA9auLckkGOor7WcI82DWaWiJ6Uiyu7H1xpaUyqWc+ypVKRX680GYS36HjA==
|
||||
|
||||
"@react-native-community/async-storage@1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/async-storage/-/async-storage-1.5.0.tgz#647ffcd832272068b0be57332e08d73036ed391f"
|
||||
@ -8734,10 +8739,10 @@ react-native-modal-translucent@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/react-native-modal-translucent/-/react-native-modal-translucent-5.0.0.tgz#8b35cfa4189dce776c77a925b00ad19d965bd0a2"
|
||||
integrity sha512-xhJAlq4uCE7jPEIPxGS1WNiRIm5DCrZEO3SF88moTOm6b4/wfFEANf+lMsVkQf9b9dsQ6Em4nq4uAoejtbHb2A==
|
||||
|
||||
react-native-modal@^11.5.6:
|
||||
version "11.7.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-modal/-/react-native-modal-11.7.0.tgz#6637d757eeac6eda85f7017a9dfdee0c0fe3a34c"
|
||||
integrity sha512-0AeAugUrn12DaJK+k2XGmt8ZIUyWgl1nRdipfwHZDnzFSM8g1oqpf7rHxjOqhimHtmzSj4xJ//ZOn1DWe9aC5Q==
|
||||
react-native-modal@11.5.6:
|
||||
version "11.5.6"
|
||||
resolved "https://registry.yarnpkg.com/react-native-modal/-/react-native-modal-11.5.6.tgz#bb25a78c35a5e24f45de060e5f64284397d38a87"
|
||||
integrity sha512-APGNfbvgC4hXbJqcSADu79GLoMKIHUmgR3fDQ7rCGZNBypkStSP8imZ4PKK/OzIZZfjGU9aP49jhMgGbhY9KHA==
|
||||
dependencies:
|
||||
prop-types "^15.6.2"
|
||||
react-native-animatable "1.3.3"
|
||||
|
Loading…
Reference in New Issue
Block a user