|
@@ -123,3 +123,121 @@ ShortcutEventHandler backquoteToCodeHandler = (editorState, event) {
|
|
|
|
|
|
return KeyEventResult.handled;
|
|
return KeyEventResult.handled;
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+// convert ~~abc~~ to strikethrough abc.
|
|
|
|
+ShortcutEventHandler doubleTildeToStrikethrough = (editorState, event) {
|
|
|
|
+ final selectionService = editorState.service.selectionService;
|
|
|
|
+ final selection = selectionService.currentSelection.value;
|
|
|
|
+ final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
|
|
|
|
+ if (selection == null || !selection.isSingle || textNodes.length != 1) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ final textNode = textNodes.first;
|
|
|
|
+ final text = textNode.toRawString().substring(0, selection.end.offset);
|
|
|
|
+
|
|
|
|
+ // make sure the last two characters are ~~.
|
|
|
|
+ if (text.length < 2 || text[selection.end.offset - 1] != '~') {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // find all the index of `~`.
|
|
|
|
+ final tildeIndexes = <int>[];
|
|
|
|
+ for (var i = 0; i < text.length; i++) {
|
|
|
|
+ if (text[i] == '~') {
|
|
|
|
+ tildeIndexes.add(i);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tildeIndexes.length < 3) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // make sure the second to last and third to last tildes are connected.
|
|
|
|
+ final thirdToLastTildeIndex = tildeIndexes[tildeIndexes.length - 3];
|
|
|
|
+ final secondToLastTildeIndex = tildeIndexes[tildeIndexes.length - 2];
|
|
|
|
+ final lastTildeIndex = tildeIndexes[tildeIndexes.length - 1];
|
|
|
|
+ if (secondToLastTildeIndex != thirdToLastTildeIndex + 1 ||
|
|
|
|
+ lastTildeIndex == secondToLastTildeIndex + 1) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // delete the last three tildes.
|
|
|
|
+ // update the style of the text surround by `~~ ~~` to strikethrough.
|
|
|
|
+ // and update the cursor position.
|
|
|
|
+ TransactionBuilder(editorState)
|
|
|
|
+ ..deleteText(textNode, lastTildeIndex, 1)
|
|
|
|
+ ..deleteText(textNode, thirdToLastTildeIndex, 2)
|
|
|
|
+ ..formatText(
|
|
|
|
+ textNode,
|
|
|
|
+ thirdToLastTildeIndex,
|
|
|
|
+ selection.end.offset - thirdToLastTildeIndex - 2,
|
|
|
|
+ {
|
|
|
|
+ BuiltInAttributeKey.strikethrough: true,
|
|
|
|
+ },
|
|
|
|
+ )
|
|
|
|
+ ..afterSelection = Selection.collapsed(
|
|
|
|
+ Position(
|
|
|
|
+ path: textNode.path,
|
|
|
|
+ offset: selection.end.offset - 3,
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ ..commit();
|
|
|
|
+
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/// To create a link, enclose the link text in brackets (e.g., [link text]).
|
|
|
|
+/// Then, immediately follow it with the URL in parentheses (e.g., (https://example.com)).
|
|
|
|
+ShortcutEventHandler markdownLinkToLinkHandler = (editorState, event) {
|
|
|
|
+ final selectionService = editorState.service.selectionService;
|
|
|
|
+ final selection = selectionService.currentSelection.value;
|
|
|
|
+ final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
|
|
|
|
+ if (selection == null || !selection.isSingle || textNodes.length != 1) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // find all of the indexs for important characters
|
|
|
|
+ final textNode = textNodes.first;
|
|
|
|
+ final text = textNode.toRawString();
|
|
|
|
+ final firstOpeningBracket = text.indexOf('[');
|
|
|
|
+ final firstClosingBracket = text.indexOf(']');
|
|
|
|
+
|
|
|
|
+ // use regex to validate the format of the link
|
|
|
|
+ // note: this enforces that the link has http or https
|
|
|
|
+ final regexp = RegExp(r'\[([\w\s\d]+)\]\(((?:\/|https?:\/\/)[\w\d./?=#]+)$');
|
|
|
|
+ final match = regexp.firstMatch(text);
|
|
|
|
+ if (match == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // extract the text and the url of the link
|
|
|
|
+ final linkText = match.group(1);
|
|
|
|
+ final linkUrl = match.group(2);
|
|
|
|
+
|
|
|
|
+ // Delete the initial opening bracket,
|
|
|
|
+ // update the href attribute of the text surrounded by [ ] to the url,
|
|
|
|
+ // delete everything after the text,
|
|
|
|
+ // and update the cursor position.
|
|
|
|
+ TransactionBuilder(editorState)
|
|
|
|
+ ..deleteText(textNode, firstOpeningBracket, 1)
|
|
|
|
+ ..formatText(
|
|
|
|
+ textNode,
|
|
|
|
+ firstOpeningBracket,
|
|
|
|
+ firstClosingBracket - firstOpeningBracket - 1,
|
|
|
|
+ {
|
|
|
|
+ BuiltInAttributeKey.href: linkUrl,
|
|
|
|
+ },
|
|
|
|
+ )
|
|
|
|
+ ..deleteText(textNode, firstClosingBracket - 1,
|
|
|
|
+ selection.end.offset - firstClosingBracket)
|
|
|
|
+ ..afterSelection = Selection.collapsed(
|
|
|
|
+ Position(
|
|
|
|
+ path: textNode.path,
|
|
|
|
+ offset: firstOpeningBracket + linkText!.length,
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ ..commit();
|
|
|
|
+
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|