@atlaskit/editor-plugin-interactivity
Version:
Interactivity plugin for @atlaskit/editor-core
105 lines (102 loc) • 5.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.interactivityPlugin = void 0;
var _react = require("react");
var _monitoring = require("@atlaskit/editor-common/monitoring");
var _fireInteractivityEvent = require("./analytics/fire-interactivity-event");
var _interactivityCollector = require("./collector/interactivity-collector");
/**
* Reports session-to-date interaction latency distributions for full page editor sessions
* as the `editor interactivity` operational event.
*
* The session runs for as long as the plugin's hook stays mounted, which is one editor
* mount: `MountPluginHooks` in editor-core keys hook fibers by plugin name, so a preset
* reconfigure — which destroys and recreates ProseMirror plugin views — leaves this hook,
* and the session, in place.
*/
var interactivityPlugin = exports.interactivityPlugin = function interactivityPlugin(_ref) {
var api = _ref.api;
return {
name: 'interactivity',
usePluginHook: function usePluginHook(_ref2) {
var editorView = _ref2.editorView,
wrapperElement = _ref2.wrapperElement;
var collectorRef = (0, _react.useRef)(undefined);
(0, _react.useEffect)(function () {
try {
var _api$contextIdentifie2, _api$editorViewMode2;
var collector = new _interactivityCollector.InteractivityCollector({
emit: function emit(snapshot) {
var _api$analytics;
return (0, _fireInteractivityEvent.fireInteractivityEvent)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, snapshot);
},
getObjectId: function getObjectId() {
var _api$contextIdentifie;
return api === null || api === void 0 || (_api$contextIdentifie = api.contextIdentifier) === null || _api$contextIdentifie === void 0 || (_api$contextIdentifie = _api$contextIdentifie.sharedState.currentState()) === null || _api$contextIdentifie === void 0 || (_api$contextIdentifie = _api$contextIdentifie.contextIdentifierProvider) === null || _api$contextIdentifie === void 0 ? void 0 : _api$contextIdentifie.objectId;
},
getSessionMode: function getSessionMode() {
var _api$editorViewMode;
var mode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode;
if (mode === undefined) {
return undefined;
}
return mode === 'view' ? 'reading' : 'editing';
},
// A destroyed view still answers, with the document it was destroyed with, so
// both report nothing rather than a size the editor no longer has.
getNodeSize: function getNodeSize() {
return editorView.isDestroyed ? undefined : editorView.state.doc.nodeSize;
},
// `getElementsByTagName` counts descendants in the browser engine, so this
// cannot overflow the stack on very large documents.
getEditorDomSize: function getEditorDomSize() {
return editorView.isDestroyed ? undefined : editorView.dom.getElementsByTagName('*').length;
}
});
// Effects run in declaration order, so the one below always finds it.
collectorRef.current = collector;
if (!collector.start()) {
return;
}
// Confluence live pages navigate and switch between reading and editing without
// remounting the editor. A session covers one document in one mode, so either
// change ends it and starts the next.
var unsubscribeFromObjectId = api === null || api === void 0 || (_api$contextIdentifie2 = api.contextIdentifier) === null || _api$contextIdentifie2 === void 0 ? void 0 : _api$contextIdentifie2.sharedState.onChange(function () {
return collector.onObjectIdChanged();
});
var unsubscribeFromViewMode = api === null || api === void 0 || (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 ? void 0 : _api$editorViewMode2.sharedState.onChange(function () {
return collector.onViewModeChanged();
});
return function () {
unsubscribeFromObjectId === null || unsubscribeFromObjectId === void 0 || unsubscribeFromObjectId();
unsubscribeFromViewMode === null || unsubscribeFromViewMode === void 0 || unsubscribeFromViewMode();
collector.stop();
};
} catch (error) {
// Instrumentation must not fail the editor around it, but a failure that hits every
// browser of one engine would be invisible without this.
void (0, _monitoring.logException)(error, {
location: 'editor-plugin-interactivity/start'
});
return;
}
// `api` is deliberately not a dependency: a preset reconfigure hands out a new
// proxy object, but the one captured here keeps resolving plugins from the same
// live registry, and restarting the session on a reconfigure would split one
// editor session in two.
}, [editorView]);
(0, _react.useEffect)(function () {
try {
var _collectorRef$current;
(_collectorRef$current = collectorRef.current) === null || _collectorRef$current === void 0 || _collectorRef$current.setEditorRoot(wrapperElement);
} catch (error) {
void (0, _monitoring.logException)(error, {
location: 'editor-plugin-interactivity/observe'
});
}
}, [wrapperElement]);
}
};
};