[Glitch] Profile editing: Add warning for links
Port 12c6c6dcf9a6875db03dbb9d66eed897c1d964e3 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
3ed3ce4e05
commit
006b06199f
@ -18,6 +18,7 @@ import {
|
|||||||
useAppDispatch,
|
useAppDispatch,
|
||||||
useAppSelector,
|
useAppSelector,
|
||||||
} from '@/flavours/glitch/store';
|
} from '@/flavours/glitch/store';
|
||||||
|
import { isUrlWithoutProtocol } from '@/flavours/glitch/utils/checks';
|
||||||
|
|
||||||
import { ConfirmationModal } from '../../ui/components/confirmation_modals';
|
import { ConfirmationModal } from '../../ui/components/confirmation_modals';
|
||||||
import type { DialogModalProps } from '../../ui/components/dialog_modal';
|
import type { DialogModalProps } from '../../ui/components/dialog_modal';
|
||||||
@ -48,7 +49,7 @@ const messages = defineMessages({
|
|||||||
},
|
},
|
||||||
editValueHint: {
|
editValueHint: {
|
||||||
id: 'account_edit.field_edit_modal.value_hint',
|
id: 'account_edit.field_edit_modal.value_hint',
|
||||||
defaultMessage: 'E.g. “example.me”',
|
defaultMessage: 'E.g. “https://example.me”',
|
||||||
},
|
},
|
||||||
limitHeader: {
|
limitHeader: {
|
||||||
id: 'account_edit.field_edit_modal.limit_header',
|
id: 'account_edit.field_edit_modal.limit_header',
|
||||||
@ -109,6 +110,10 @@ export const EditFieldModal: FC<DialogModalProps & { fieldKey?: string }> = ({
|
|||||||
);
|
);
|
||||||
return hasLink && hasEmoji;
|
return hasLink && hasEmoji;
|
||||||
}, [customEmojiCodes, newLabel, newValue]);
|
}, [customEmojiCodes, newLabel, newValue]);
|
||||||
|
const hasLinkWithoutProtocol = useMemo(
|
||||||
|
() => isUrlWithoutProtocol(newValue),
|
||||||
|
[newValue],
|
||||||
|
);
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const handleSave = useCallback(() => {
|
const handleSave = useCallback(() => {
|
||||||
@ -175,6 +180,19 @@ export const EditFieldModal: FC<DialogModalProps & { fieldKey?: string }> = ({
|
|||||||
/>
|
/>
|
||||||
</Callout>
|
</Callout>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{hasLinkWithoutProtocol && (
|
||||||
|
<Callout variant='warning'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account_edit.field_edit_modal.url_warning'
|
||||||
|
defaultMessage='To add a link, please include {protocol} at the beginning.'
|
||||||
|
description='{protocol} is https://'
|
||||||
|
values={{
|
||||||
|
protocol: <code>https://</code>,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Callout>
|
||||||
|
)}
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
21
app/javascript/flavours/glitch/utils/checks.test.ts
Normal file
21
app/javascript/flavours/glitch/utils/checks.test.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { isUrlWithoutProtocol } from './checks';
|
||||||
|
|
||||||
|
describe('isUrlWithoutProtocol', () => {
|
||||||
|
test.concurrent.each([
|
||||||
|
['example.com', true],
|
||||||
|
['sub.domain.co.uk', true],
|
||||||
|
['example', false], // No dot
|
||||||
|
['example..com', false], // Consecutive dots
|
||||||
|
['example.com.', false], // Trailing dot
|
||||||
|
['example.c', false], // TLD too short
|
||||||
|
['example.123', false], // Numeric TLDs are not valid
|
||||||
|
['example.com/path', true], // Paths are allowed
|
||||||
|
['example.com?query=string', true], // Query strings are allowed
|
||||||
|
['example.com#fragment', true], // Fragments are allowed
|
||||||
|
['example .com', false], // Spaces are not allowed
|
||||||
|
['example://com', false], // Protocol inside the string is not allowed
|
||||||
|
['example.com^', false], // Invalid characters not allowed
|
||||||
|
])('should return %s for input "%s"', (input, expected) => {
|
||||||
|
expect(isUrlWithoutProtocol(input)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -9,3 +9,29 @@ export function isValidUrl(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the input string is probably a URL without a protocol. Note this is not full URL validation,
|
||||||
|
* and is mostly used to detect link-like inputs.
|
||||||
|
* @see https://www.xjavascript.com/blog/check-if-a-javascript-string-is-a-url/
|
||||||
|
* @param input The input string to check
|
||||||
|
*/
|
||||||
|
export function isUrlWithoutProtocol(input: string): boolean {
|
||||||
|
if (!input.length || input.includes(' ') || input.includes('://')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = new URL(`http://${input}`);
|
||||||
|
const { host } = url;
|
||||||
|
return (
|
||||||
|
host !== '' && // Host is not empty
|
||||||
|
host.includes('.') && // Host contains at least one dot
|
||||||
|
!host.endsWith('.') && // No trailing dot
|
||||||
|
!host.includes('..') && // No consecutive dots
|
||||||
|
/\.[\w]{2,}$/.test(host) // TLD is at least 2 characters
|
||||||
|
);
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user