mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-08 20:46:16 +08:00
Simplify client hooks messaging
This commit is contained in:
parent
ab182ffecb
commit
2b6ce4a92a
4 changed files with 87 additions and 112 deletions
|
@ -85,13 +85,23 @@ const Cell = {
|
||||||
|
|
||||||
this.subscriptions = [
|
this.subscriptions = [
|
||||||
globalPubsub.subscribe(
|
globalPubsub.subscribe(
|
||||||
"navigation",
|
"navigation:focus_changed",
|
||||||
this.handleNavigationEvent.bind(this),
|
({ focusableId, scroll }) =>
|
||||||
|
this.handleElementFocused(focusableId, scroll),
|
||||||
|
),
|
||||||
|
globalPubsub.subscribe("navigation:insert_mode_changed", ({ enabled }) =>
|
||||||
|
this.handleInsertModeChanged(enabled),
|
||||||
|
),
|
||||||
|
globalPubsub.subscribe("cells:cell_moved", ({ cellId }) =>
|
||||||
|
this.handleCellMoved(cellId),
|
||||||
),
|
),
|
||||||
globalPubsub.subscribe("cells", this.handleCellsEvent.bind(this)),
|
|
||||||
globalPubsub.subscribe(
|
globalPubsub.subscribe(
|
||||||
`cells:${this.props.cellId}`,
|
`cells:${this.props.cellId}:dispatch_queue_evaluation`,
|
||||||
this.handleCellEvent.bind(this),
|
({ dispatch }) => this.handleDispatchQueueEvaluation(dispatch),
|
||||||
|
),
|
||||||
|
globalPubsub.subscribe(
|
||||||
|
`cells:${this.props.cellId}:jump_to_line`,
|
||||||
|
({ line, offset = 0 }) => this.handleJumpToLine(line, offset),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -138,30 +148,6 @@ const Cell = {
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleNavigationEvent(event) {
|
|
||||||
if (event.type === "element_focused") {
|
|
||||||
this.handleElementFocused(event.focusableId, event.scroll);
|
|
||||||
} else if (event.type === "insert_mode_changed") {
|
|
||||||
this.handleInsertModeChanged(event.enabled);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleCellsEvent(event) {
|
|
||||||
if (event.type === "cell_moved") {
|
|
||||||
this.handleCellMoved(event.cellId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleCellEvent(event) {
|
|
||||||
if (event.type === "dispatch_queue_evaluation") {
|
|
||||||
this.handleDispatchQueueEvaluation(event.dispatch);
|
|
||||||
} else if (event.type === "jump_to_line") {
|
|
||||||
if (this.isFocused) {
|
|
||||||
this.currentEditor().moveCursorToLine(event.line, event.offset || 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleElementFocused(focusableId, scroll) {
|
handleElementFocused(focusableId, scroll) {
|
||||||
if (this.props.cellId === focusableId) {
|
if (this.props.cellId === focusableId) {
|
||||||
this.isFocused = true;
|
this.isFocused = true;
|
||||||
|
@ -355,8 +341,7 @@ const Cell = {
|
||||||
handleDispatchQueueEvaluation(dispatch) {
|
handleDispatchQueueEvaluation(dispatch) {
|
||||||
if (this.props.type === "smart" && this.props.smartCellJsViewRef) {
|
if (this.props.type === "smart" && this.props.smartCellJsViewRef) {
|
||||||
// Ensure the smart cell UI is reflected on the server, before the evaluation
|
// Ensure the smart cell UI is reflected on the server, before the evaluation
|
||||||
globalPubsub.broadcast(`js_views:${this.props.smartCellJsViewRef}`, {
|
globalPubsub.broadcast(`js_views:${this.props.smartCellJsViewRef}:sync`, {
|
||||||
type: "sync",
|
|
||||||
callback: dispatch,
|
callback: dispatch,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -364,6 +349,12 @@ const Cell = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleJumpToLine(line, offset) {
|
||||||
|
if (this.isFocused) {
|
||||||
|
this.currentEditor().moveCursorToLine(line, offset);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
scrollEditorCursorIntoViewIfNeeded() {
|
scrollEditorCursorIntoViewIfNeeded() {
|
||||||
const element = this.currentEditor().getElementAtCursor();
|
const element = this.currentEditor().getElementAtCursor();
|
||||||
|
|
||||||
|
@ -381,9 +372,9 @@ const Cell = {
|
||||||
const cursor = this.currentEditor().getCurrentCursorPosition();
|
const cursor = this.currentEditor().getCurrentCursorPosition();
|
||||||
if (cursor === null) return;
|
if (cursor === null) return;
|
||||||
|
|
||||||
globalPubsub.broadcast("history", {
|
globalPubsub.broadcast("navigation:cursor_moved", {
|
||||||
...cursor,
|
line: cursor.line,
|
||||||
type: "navigation",
|
offset: cursor.offset,
|
||||||
cellId: this.props.cellId,
|
cellId: this.props.cellId,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,10 +26,16 @@ const Headline = {
|
||||||
|
|
||||||
this.initializeHeadingEl();
|
this.initializeHeadingEl();
|
||||||
|
|
||||||
this.navigationSubscription = globalPubsub.subscribe(
|
this.subscriptions = [
|
||||||
"navigation",
|
globalPubsub.subscribe(
|
||||||
this.handleNavigationEvent.bind(this),
|
"navigation:focus_changed",
|
||||||
);
|
({ focusableId, scroll }) =>
|
||||||
|
this.handleElementFocused(focusableId, scroll),
|
||||||
|
),
|
||||||
|
globalPubsub.subscribe("navigation:insert_mode_changed", ({ enabled }) =>
|
||||||
|
this.handleInsertModeChanged(enabled),
|
||||||
|
),
|
||||||
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
|
@ -38,7 +44,7 @@ const Headline = {
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.navigationSubscription.destroy();
|
this.subscriptions.forEach((subscription) => subscription.destroy());
|
||||||
},
|
},
|
||||||
|
|
||||||
getProps() {
|
getProps() {
|
||||||
|
@ -80,14 +86,6 @@ const Headline = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleNavigationEvent(event) {
|
|
||||||
if (event.type === "element_focused") {
|
|
||||||
this.handleElementFocused(event.focusableId, event.scroll);
|
|
||||||
} else if (event.type === "insert_mode_changed") {
|
|
||||||
this.handleInsertModeChanged(event.enabled);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleElementFocused(focusableId, scroll) {
|
handleElementFocused(focusableId, scroll) {
|
||||||
if (this.props.id === focusableId) {
|
if (this.props.id === focusableId) {
|
||||||
this.isFocused = true;
|
this.isFocused = true;
|
||||||
|
|
|
@ -132,12 +132,15 @@ const JSView = {
|
||||||
|
|
||||||
this.subscriptions = [
|
this.subscriptions = [
|
||||||
globalPubsub.subscribe(
|
globalPubsub.subscribe(
|
||||||
`js_views:${this.props.ref}`,
|
`js_views:${this.props.ref}:sync`,
|
||||||
this.handleJSViewEvent.bind(this),
|
({ callback }) => this.handleSync(callback),
|
||||||
),
|
),
|
||||||
globalPubsub.subscribe(
|
globalPubsub.subscribe(
|
||||||
"navigation",
|
`js_views:${this.props.ref}:secret_selected`,
|
||||||
this.handleNavigationEvent.bind(this),
|
({ secretName }) => this.handleSecretSelected(secretName),
|
||||||
|
),
|
||||||
|
globalPubsub.subscribe("navigation:focus_changed", ({ focusableId }) =>
|
||||||
|
this.handleElementFocused(focusableId),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -248,11 +251,10 @@ const JSView = {
|
||||||
// dispatched to trigger reposition. This way we don't need to
|
// dispatched to trigger reposition. This way we don't need to
|
||||||
// use deep MutationObserver, which would be expensive, especially
|
// use deep MutationObserver, which would be expensive, especially
|
||||||
// with code editor
|
// with code editor
|
||||||
const jsViewSubscription = globalPubsub.subscribe("js_views", (event) => {
|
const jsViewSubscription = globalPubsub.subscribe(
|
||||||
if (event.type === "reposition") {
|
"js_views:reposition",
|
||||||
this.repositionIframe();
|
(event) => this.repositionIframe(),
|
||||||
}
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// Emulate mouse enter and leave on the placeholder. Note that we
|
// Emulate mouse enter and leave on the placeholder. Note that we
|
||||||
// intentionally use bubbling to notify all parents that may have
|
// intentionally use bubbling to notify all parents that may have
|
||||||
|
@ -467,36 +469,33 @@ const JSView = {
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
|
||||||
handleJSViewEvent(event) {
|
handleSync(callback) {
|
||||||
if (event.type === "sync") {
|
|
||||||
// First, we invoke optional synchronization callback in the iframe,
|
// First, we invoke optional synchronization callback in the iframe,
|
||||||
// that may send any deferred UI changes to the server. Then, we
|
// that may send any deferred UI changes to the server. Then, we
|
||||||
// do a ping to synchronize with the server
|
// do a ping to synchronize with the server
|
||||||
this.syncCallbackQueue.push(event.callback);
|
this.syncCallbackQueue.push(callback);
|
||||||
this.postMessage({ type: "sync" });
|
this.postMessage({ type: "sync" });
|
||||||
} else if (event.type == "secretSelected") {
|
|
||||||
this.postMessage({
|
|
||||||
type: "secretSelected",
|
|
||||||
secretName: event.secretName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleNavigationEvent(event) {
|
handleSecretSelected(secretName) {
|
||||||
if (event.type === "element_focused") {
|
this.postMessage({ type: "secretSelected", secretName });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleElementFocused(focusableId) {
|
||||||
// If a parent focusable element is focused, mirror the attribute
|
// If a parent focusable element is focused, mirror the attribute
|
||||||
// to the iframe element. This way if we need to apply style rules
|
// to the iframe element. This way if we need to apply style rules
|
||||||
// (such as opacity) to focused elements, we can target the iframe
|
// (such as opacity) to focused elements, we can target the iframe
|
||||||
// elements placed elsewhere in the DOM
|
// elements placed elsewhere in the DOM
|
||||||
|
|
||||||
const focusableEl = this.el.closest(`[data-focusable-id]`);
|
const parentFocusableEl = this.el.closest(`[data-focusable-id]`);
|
||||||
const focusableId = focusableEl ? focusableEl.dataset.focusableId : null;
|
const parentFocusableId = parentFocusableEl
|
||||||
|
? parentFocusableEl.dataset.focusableId
|
||||||
|
: null;
|
||||||
|
|
||||||
this.iframe.toggleAttribute(
|
this.iframe.toggleAttribute(
|
||||||
"data-js-focused",
|
"data-js-focused",
|
||||||
focusableId === event.focusableId,
|
parentFocusableId === focusableId,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,11 @@ const Session = {
|
||||||
globalPubsub.subscribe("jump_to_editor", ({ line, file }) =>
|
globalPubsub.subscribe("jump_to_editor", ({ line, file }) =>
|
||||||
this.jumpToLine(file, line),
|
this.jumpToLine(file, line),
|
||||||
),
|
),
|
||||||
globalPubsub.subscribe("history", this.handleHistoryEvent.bind(this)),
|
globalPubsub.subscribe(
|
||||||
|
"navigation:cursor_moved",
|
||||||
|
({ cellId, line, offset }) =>
|
||||||
|
this.cursorHistory.push(cellId, line, offset),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
this.initializeDragAndDrop();
|
this.initializeDragAndDrop();
|
||||||
|
@ -951,10 +955,10 @@ const Session = {
|
||||||
// If an evaluable cell is focused, we forward the evaluation
|
// If an evaluable cell is focused, we forward the evaluation
|
||||||
// request to that cell, so it can synchronize itself before
|
// request to that cell, so it can synchronize itself before
|
||||||
// sending the request to the server
|
// sending the request to the server
|
||||||
globalPubsub.broadcast(`cells:${this.focusedId}`, {
|
globalPubsub.broadcast(
|
||||||
type: "dispatch_queue_evaluation",
|
`cells:${this.focusedId}:dispatch_queue_evaluation`,
|
||||||
dispatch,
|
{ dispatch },
|
||||||
});
|
);
|
||||||
} else {
|
} else {
|
||||||
dispatch();
|
dispatch();
|
||||||
}
|
}
|
||||||
|
@ -1085,8 +1089,7 @@ const Session = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
globalPubsub.broadcast("navigation", {
|
globalPubsub.broadcast("navigation:focus_changed", {
|
||||||
type: "element_focused",
|
|
||||||
focusableId: focusableId,
|
focusableId: focusableId,
|
||||||
scroll,
|
scroll,
|
||||||
});
|
});
|
||||||
|
@ -1105,8 +1108,7 @@ const Session = {
|
||||||
this.el.removeAttribute("data-js-insert-mode");
|
this.el.removeAttribute("data-js-insert-mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
globalPubsub.broadcast("navigation", {
|
globalPubsub.broadcast("navigation:insert_mode_changed", {
|
||||||
type: "insert_mode_changed",
|
|
||||||
enabled: insertModeEnabled,
|
enabled: insertModeEnabled,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1265,7 +1267,7 @@ const Session = {
|
||||||
this.repositionJSViews();
|
this.repositionJSViews();
|
||||||
|
|
||||||
if (this.focusedId === cellId) {
|
if (this.focusedId === cellId) {
|
||||||
globalPubsub.broadcast("cells", { type: "cell_moved", cellId });
|
globalPubsub.broadcast("cells:cell_moved", { cellId });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1323,8 +1325,7 @@ const Session = {
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSecretSelected(select_secret_ref, secretName) {
|
handleSecretSelected(select_secret_ref, secretName) {
|
||||||
globalPubsub.broadcast(`js_views:${select_secret_ref}`, {
|
globalPubsub.broadcast(`js_views:${select_secret_ref}:secret_selected`, {
|
||||||
type: "secretSelected",
|
|
||||||
secretName,
|
secretName,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1344,14 +1345,8 @@ const Session = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleHistoryEvent(event) {
|
|
||||||
if (event.type === "navigation") {
|
|
||||||
this.cursorHistory.push(event.cellId, event.line, event.offset);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
repositionJSViews() {
|
repositionJSViews() {
|
||||||
globalPubsub.broadcast("js_views", { type: "reposition" });
|
globalPubsub.broadcast("js_views:reposition", {});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1476,7 +1471,7 @@ const Session = {
|
||||||
this.setFocusedEl(cellId, { scroll: false });
|
this.setFocusedEl(cellId, { scroll: false });
|
||||||
this.setInsertMode(true);
|
this.setInsertMode(true);
|
||||||
|
|
||||||
globalPubsub.broadcast(`cells:${cellId}`, { type: "jump_to_line", line });
|
globalPubsub.broadcast(`cells:${cellId}:jump_to_line`, { line });
|
||||||
},
|
},
|
||||||
|
|
||||||
cursorHistoryGoBack() {
|
cursorHistoryGoBack() {
|
||||||
|
@ -1485,11 +1480,7 @@ const Session = {
|
||||||
this.setFocusedEl(cellId, { scroll: false });
|
this.setFocusedEl(cellId, { scroll: false });
|
||||||
this.setInsertMode(true);
|
this.setInsertMode(true);
|
||||||
|
|
||||||
globalPubsub.broadcast(`cells:${cellId}`, {
|
globalPubsub.broadcast(`cells:${cellId}:jump_to_line`, { line, offset });
|
||||||
type: "jump_to_line",
|
|
||||||
line,
|
|
||||||
offset,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1499,11 +1490,7 @@ const Session = {
|
||||||
this.setFocusedEl(cellId, { scroll: false });
|
this.setFocusedEl(cellId, { scroll: false });
|
||||||
this.setInsertMode(true);
|
this.setInsertMode(true);
|
||||||
|
|
||||||
globalPubsub.broadcast(`cells:${cellId}`, {
|
globalPubsub.broadcast(`cells:${cellId}:jump_to_line`, { line, offset });
|
||||||
type: "jump_to_line",
|
|
||||||
line,
|
|
||||||
offset,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue