Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Add insert link button to the format bar #5879

Merged
merged 8 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion res/css/views/rooms/_MessageComposerFormatBar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

.mx_MessageComposerFormatBar {
display: none;
width: calc(32px * 5);
width: calc(32px * 6);
height: 32px;
position: absolute;
cursor: pointer;
Expand Down Expand Up @@ -87,6 +87,11 @@ limitations under the License.
.mx_MessageComposerFormatBar_buttonIconCode::after {
mask-image: url('$(res)/img/element-icons/room/format-bar/code.svg');
}

.mx_MessageComposerFormatBar_buttonIconInsertLink::after {
mask-image: url('$(res)/img/element-icons/link.svg');
mask-size: 18px;
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
}
}

.mx_MessageComposerFormatBar_buttonTooltip {
Expand Down
4 changes: 4 additions & 0 deletions src/components/views/rooms/BasicMessageComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
formatRangeAsCode,
toggleInlineFormat,
replaceRangeAndMoveCaret,
formatRangeAsLink,
} from '../../../editor/operations';
import { getCaretOffsetAndText, getRangeForSelection } from '../../../editor/dom';
import Autocomplete, { generateCompletionDomId } from '../rooms/Autocomplete';
Expand Down Expand Up @@ -706,6 +707,9 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
case Formatting.Quote:
formatRangeAsQuote(range);
break;
case Formatting.InsertLink:
formatRangeAsLink(range);
break;
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/components/views/rooms/MessageComposerFormatBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum Formatting {
Strikethrough = "strikethrough",
Code = "code",
Quote = "quote",
InsertLink = "insert_link",
}

interface IProps {
Expand Down Expand Up @@ -57,6 +58,7 @@ export default class MessageComposerFormatBar extends React.PureComponent<IProps
<FormatButton label={_t("Strikethrough")} onClick={() => this.props.onAction(Formatting.Strikethrough)} icon="Strikethrough" visible={this.state.visible} />
<FormatButton label={_t("Code block")} onClick={() => this.props.onAction(Formatting.Code)} icon="Code" visible={this.state.visible} />
<FormatButton label={_t("Quote")} onClick={() => this.props.onAction(Formatting.Quote)} icon="Quote" shortcut={this.props.shortcuts.quote} visible={this.state.visible} />
<FormatButton label={_t("Insert link")} onClick={() => this.props.onAction(Formatting.InsertLink)} icon="InsertLink" visible={this.state.visible} />
</div>);
}

Expand Down
13 changes: 11 additions & 2 deletions src/editor/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ export function replaceRangeAndExpandSelection(range: Range, newParts: Part[]):
});
}

export function replaceRangeAndMoveCaret(range: Range, newParts: Part[]): void {
export function replaceRangeAndMoveCaret(range: Range, newParts: Part[], offset = 0): void {
const { model } = range;
model.transform(() => {
const oldLen = range.length;
const addedLen = range.replace(newParts);
const firstOffset = range.start.asOffset(model);
const lastOffset = firstOffset.add(oldLen + addedLen);
const lastOffset = firstOffset.add(oldLen + addedLen + offset);
return lastOffset.asPosition(model);
});
}
Expand Down Expand Up @@ -103,6 +103,15 @@ export function formatRangeAsCode(range: Range): void {
replaceRangeAndExpandSelection(range, parts);
}

export function formatRangeAsLink(range: Range) {
const { model, parts } = range;
const { partCreator } = model;
parts.unshift(partCreator.plain("["));
parts.push(partCreator.plain("]()"));
// We set offset to -1 here so that the caret lands between the brackets
replaceRangeAndMoveCaret(range, parts, -1);
}

// parts helper methods
const isBlank = part => !part.text || !/\S/.test(part.text);
const isNL = part => part.type === Type.Newline;
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,7 @@
"Strikethrough": "Strikethrough",
"Code block": "Code block",
"Quote": "Quote",
"Insert link": "Insert link",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Only the two of you are in this conversation, unless either of you invites anyone to join.",
"This is the beginning of your direct message history with <displayName/>.": "This is the beginning of your direct message history with <displayName/>.",
"Topic: %(topic)s (<a>edit</a>)": "Topic: %(topic)s (<a>edit</a>)",
Expand Down