Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smart url parsing #2141

Merged
merged 6 commits into from
Sep 28, 2023
Merged

Smart url parsing #2141

merged 6 commits into from
Sep 28, 2023

Conversation

Trombach
Copy link
Contributor

@Trombach Trombach commented Sep 24, 2023

Description

This PR resolves #2116

Update: The behaviour is now a bit more similar to how Github handles this. I have also updated the video to show the new behaviour

Adds logic to detect if a paste event contains a URL. If true the URL will be formatted with the appropriate markdown. Open to suggestions on how to handle text selection after the paste event. The current implementation is demonstrated in the videos below.

It might also be better to implement this in the same way github does this, only adding formatting if text is already selected and otherwise just pasting the plain link, which might make things easier to read in the editor if no alternative link text is desired.

Screenshots

Before

Screencast.from.2023-09-24.17-30-03.webm

After

Screencast.from.2023-09-26.21-59-39.webm

@SleeplessOne1917
Copy link
Member

It might also be better to implement this in the same way github does this, only adding formatting if text is already selected and otherwise just pasting the plain link, which might make things easier to read in the editor if no alternative link text is desired.

This is the better approach in my opinion. I'll wait for others to chime in on how it should be done before checking out the code.

@dessalines
Copy link
Member

I agree with sleepless, it'd be better to detect selected text first, then a paste event can turn it into a markdown link.

Comment on lines 405 to 411
i.setState({
content: `${
i.state.content ? i.state.content.substring(0, selectionStart) : ""
}[${selectedText}](${url.toString()})${
i.state.content ? i.state.content.substring(selectionEnd) : ""
}`,
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure inferno has similar issues to react when trying to set state using a previous value of that state. Try this:

Suggested change
i.setState({
content: `${
i.state.content ? i.state.content.substring(0, selectionStart) : ""
}[${selectedText}](${url.toString()})${
i.state.content ? i.state.content.substring(selectionEnd) : ""
}`,
});
i.setState(({content}) => ({
content: `${content?.substring(0, selectionStart) ?? ""}[${selectedText}](${url.toString()})${content?.substring(selectionEnd) ?? ""}`
}));

You will probably need to format this with prettier still.

if (textarea instanceof HTMLTextAreaElement) {
event.preventDefault();
const { selectionStart, selectionEnd } = textarea;
const selectedText = i.getSelectedText() || url.toString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the return value of getSelectedText can be null or undefined, it is slightly clearer to use ?? instead of ||.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually used || specifically since getSelectedText can't return null or undefined but could return "". I wanted to fallback to the url in that case, but since the consensus seems to be that the smart formatting should not be applied if no text is selected this fallback will become obsolete.

@Trombach
Copy link
Contributor Author

@SleeplessOne1917 @dessalines Thanks for the initial feedback. I have updated the PR and brought the behaviour closer to what Github does. I have updated the video as well

}
}

isValidUrl(value: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should either be renamed or inlined. Seeing a url returned from what the name makes seem should be a boolean threw me through a loop for a second.

Copy link
Member

@dessalines dessalines Sep 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, make sure the return type is explicitly named: : bool

Also, double check using grep to see if we already have this function... seems like we should.

const url = i.isValidUrl(event.clipboardData.getData("text"));
if (url) {
i.handleUrlPaste(url, i, event);
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return statement is unnecessary since it's at the end of the function anyway.

Copy link
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't wait to move all this to rust so I can make everyone stop doing early returns ;)

IE return if (condition) { } else if (condition) { } else { }

const { selectionStart, selectionEnd } = textarea;

// if no selection, just insert url
if (selectionStart === selectionEnd) return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it doing anything here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment explains it. If no text is selected (i.e. the curser is in one position and therefore selectionStart === selectionEnd) we don't want to apply formatting

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, it has to do with event.preventDefault() not being called.

}
}

isValidUrl(value: string) {
Copy link
Member

@dessalines dessalines Sep 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, make sure the return type is explicitly named: : bool

Also, double check using grep to see if we already have this function... seems like we should.

}

isValidUrl(value: string) {
if (!value) return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't necessary, you aren't passing in string | undefined, so we can assume its there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the beauty of javascript and "" being falsy, it does something :) It actually prevents a constructor call to URL if you pass in an empty string which would never be a valid URL. I'm moving to the validUrl helper function, so it won't be relevant.

Copy link
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this and it works great, nice job!

const { selectionStart, selectionEnd } = textarea;

// if no selection, just insert url
if (selectionStart === selectionEnd) return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, it has to do with event.preventDefault() not being called.

@dessalines dessalines enabled auto-merge (squash) September 28, 2023 12:32
@dessalines dessalines merged commit 8a2cd12 into LemmyNet:main Sep 28, 2023
@Trombach Trombach deleted the smart-url-paste branch September 28, 2023 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Smart link formatting
3 participants