Skip to content
Open
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
29 changes: 28 additions & 1 deletion src/lib/Command.svelte.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { insert_default_node, break_text_node } from './transforms.svelte.js';
import {
insert_default_node,
insert_default_node_before,
break_text_node
} from './transforms.svelte.js';
import { can_switch_annotation_type } from './doc_utils.js';
import { is_selection_collapsed, is_mobile_browser, get_char_length } from './utils.js';

Expand Down Expand Up @@ -327,3 +331,26 @@ export class InsertDefaultNodeCommand extends Command {
this.context.session.apply(tr);
}
}

/**
* Command that inserts a default node before the current node.
* Only works in text selections, where "the current node" is well defined.
*/
export class InsertDefaultNodeBeforeCommand extends Command {
is_enabled() {
const selection = this.context.session.selection;
if (!this.context.editable) return false;
if (selection?.type === 'text') return true;
if (selection?.type === 'node' && selection.anchor_offset === selection.focus_offset) {
return selection.anchor_offset > 0;
}
return false;
}

execute() {
const tr = this.context.session.tr;
if (insert_default_node_before(tr)) {
this.context.session.apply(tr);
}
}
}
42 changes: 42 additions & 0 deletions src/lib/transforms.svelte.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,45 @@ export function insert_default_node(tr) {
throw new Error(`No inserter function available for default node type '${default_type}'`);
}
}

export function insert_default_node_before(tr) {
const selection = tr.selection;

let node_array_path;
let insert_offset;

if (selection?.type === 'text') {
// "Current node" is the node containing the text. Insert at its index.
const node_path = selection.path.slice(0, -1);
node_array_path = node_path.slice(0, -1);
if (tr.inspect(node_array_path)?.type !== 'node_array') return false;
insert_offset = parseInt(node_path.at(-1), 10);
} else if (selection?.type === 'node' && selection.anchor_offset === selection.focus_offset) {
// In a node gap, "current node" is the node above the caret (offset - 1).
// Inserting before it means inserting at offset - 1.
if (selection.anchor_offset === 0) return false;
node_array_path = selection.path;
insert_offset = selection.anchor_offset - 1;
} else {
return false;
}

const node_array_node = tr.get(node_array_path.slice(0, -1));
const property_name = node_array_path.at(-1);
const property_definition = tr.schema[node_array_node.type].properties[property_name];
const default_type = get_default_node_type(property_definition);

if (!tr.config?.inserters?.[default_type]) {
throw new Error(`No inserter function available for default node type '${default_type}'`);
}

tr.set_selection({
type: 'node',
path: node_array_path,
anchor_offset: insert_offset,
focus_offset: insert_offset
});

tr.config.inserters[default_type](tr);
return true;
}
3 changes: 3 additions & 0 deletions src/routes/create_demo_session.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Session,
SelectAllCommand,
InsertDefaultNodeCommand,
InsertDefaultNodeBeforeCommand,
AddNewLineCommand,
BreakTextNodeCommand,
ToggleAnnotationCommand,
Expand Down Expand Up @@ -751,6 +752,7 @@ export const session_config = {
const commands = {
select_all: new SelectAllCommand(context),
insert_default_node: new InsertDefaultNodeCommand(context),
insert_default_node_before: new InsertDefaultNodeBeforeCommand(context),
add_new_line: new AddNewLineCommand(context),
break_text_node: new BreakTextNodeCommand(context),
toggle_strong: new ToggleAnnotationCommand('strong', context),
Expand All @@ -773,6 +775,7 @@ export const session_config = {
// In case of a node caret, fall back to inserting a default node. This is needed
// because on iOS selecting a node caret triggers auto capitalization (shift pressed)
'shift+enter': [commands.add_new_line, commands.insert_default_node],
'meta+shift+enter,ctrl+shift+enter': [commands.insert_default_node_before],
'meta+b,ctrl+b': [commands.toggle_strong],
'meta+i,ctrl+i': [commands.toggle_emphasis],
'meta+u,ctrl+u': [commands.toggle_highlight],
Expand Down