UNPKG

@atlaskit/editor-plugin-base

Version:

Base plugin for @atlaskit/editor-core

209 lines (204 loc) 12.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.frozenEditorPluginKey = exports.default = exports.NORMAL_SEVERITY_THRESHOLD = exports.DEGRADED_SEVERITY_THRESHOLD = exports.DEFAULT_TRACK_SEVERITY_THRESHOLD_NORMAL = exports.DEFAULT_TRACK_SEVERITY_THRESHOLD_DEGRADED = exports.DEFAULT_FREEZE_THRESHOLD = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _analytics = require("@atlaskit/editor-common/analytics"); var _countNodes = require("@atlaskit/editor-common/count-nodes"); var _isPerformanceApiAvailable = require("@atlaskit/editor-common/is-performance-api-available"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _analytics2 = require("@atlaskit/editor-common/utils/analytics"); var _state = require("@atlaskit/editor-prosemirror/state"); var _frozenEditor = require("./utils/frozen-editor"); var _inputLatencyTracking = _interopRequireDefault(require("./utils/input-latency-tracking")); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var frozenEditorPluginKey = exports.frozenEditorPluginKey = new _state.PluginKey('frozenEditor'); var DEFAULT_KEYSTROKE_SAMPLING_LIMIT = 100; var DEFAULT_SLOW_THRESHOLD = 300; var DEFAULT_FREEZE_THRESHOLD = exports.DEFAULT_FREEZE_THRESHOLD = 600; var NORMAL_SEVERITY_THRESHOLD = exports.NORMAL_SEVERITY_THRESHOLD = 2000; var DEGRADED_SEVERITY_THRESHOLD = exports.DEGRADED_SEVERITY_THRESHOLD = 3000; var DEFAULT_TRACK_SEVERITY_ENABLED = false; var DEFAULT_TRACK_SEVERITY_THRESHOLD_NORMAL = exports.DEFAULT_TRACK_SEVERITY_THRESHOLD_NORMAL = 100; var DEFAULT_TRACK_SEVERITY_THRESHOLD_DEGRADED = exports.DEFAULT_TRACK_SEVERITY_THRESHOLD_DEGRADED = 500; var dispatchLongTaskEvent = function dispatchLongTaskEvent(contextIdentifierPlugin) { return function (dispatchAnalyticsEvent, view, time, getNodeCount, interactionType, severity) { var _contextIdentifierPlu; var state = view.state; var nodesCount = getNodeCount(state); return dispatchAnalyticsEvent({ action: _analytics.ACTION.BROWSER_FREEZE, actionSubject: _analytics.ACTION_SUBJECT.EDITOR, attributes: _objectSpread(_objectSpread({ objectId: contextIdentifierPlugin === null || contextIdentifierPlugin === void 0 || (_contextIdentifierPlu = contextIdentifierPlugin.sharedState.currentState()) === null || _contextIdentifierPlu === void 0 || (_contextIdentifierPlu = _contextIdentifierPlu.contextIdentifierProvider) === null || _contextIdentifierPlu === void 0 ? void 0 : _contextIdentifierPlu.objectId, freezeTime: time, nodeSize: state.doc.nodeSize }, nodesCount), {}, { interactionType: interactionType, severity: severity }), eventType: _analytics.EVENT_TYPE.OPERATIONAL }); }; }; var _default = exports.default = function _default(contextIdentifierPlugin) { return function (dispatchAnalyticsEvent, inputTracking, browserFreezeTracking) { var interactionType; var inputLatencyTracker = null; if (browserFreezeTracking !== null && browserFreezeTracking !== void 0 && browserFreezeTracking.trackInteractionType) { interactionType = (0, _frozenEditor.setInteractionType)(_analytics.BROWSER_FREEZE_INTERACTION_TYPE.LOADING); } var samplingRate = inputTracking && typeof inputTracking.samplingRate === 'number' ? inputTracking.samplingRate : DEFAULT_KEYSTROKE_SAMPLING_LIMIT; // TODO: ED-26959 - get right values here based on appearance var slowThreshold = DEFAULT_SLOW_THRESHOLD; // TODO: ED-26959 - get right values here based on appearance var freezeThreshold = DEFAULT_FREEZE_THRESHOLD; var allowCountNodes = inputTracking && inputTracking.countNodes; var prevNodeCountState = null; var prevNodeCount = {}; // Cache the result as we were calling this multiple times // and has potential to be expensive var getNodeCount = function getNodeCount(state) { if (state === prevNodeCountState) { return prevNodeCount; } prevNodeCount = allowCountNodes ? (0, _countNodes.countNodes)(state) : {}; prevNodeCountState = state; return prevNodeCount; }; var shouldTrackSeverity = (inputTracking === null || inputTracking === void 0 ? void 0 : inputTracking.trackSeverity) || DEFAULT_TRACK_SEVERITY_ENABLED; var severityThresholdNormal = (inputTracking === null || inputTracking === void 0 ? void 0 : inputTracking.severityNormalThreshold) || DEFAULT_TRACK_SEVERITY_THRESHOLD_NORMAL; var severityThresholdDegraded = (inputTracking === null || inputTracking === void 0 ? void 0 : inputTracking.severityDegradedThreshold) || DEFAULT_TRACK_SEVERITY_THRESHOLD_DEGRADED; var createDispatchSample = function createDispatchSample(action, view) { return function (time, severity) { var _contextIdentifierPlu2; var state = view.state; var nodesCount = getNodeCount(state); var samplePayload = { action: action, actionSubject: _analytics.ACTION_SUBJECT.EDITOR, attributes: _objectSpread(_objectSpread({ time: time, nodeSize: state.doc.nodeSize }, nodesCount), {}, { objectId: contextIdentifierPlugin === null || contextIdentifierPlugin === void 0 || (_contextIdentifierPlu2 = contextIdentifierPlugin.sharedState.currentState()) === null || _contextIdentifierPlu2 === void 0 || (_contextIdentifierPlu2 = _contextIdentifierPlu2.contextIdentifierProvider) === null || _contextIdentifierPlu2 === void 0 ? void 0 : _contextIdentifierPlu2.objectId, severity: shouldTrackSeverity ? severity : undefined }), eventType: _analytics.EVENT_TYPE.OPERATIONAL }; dispatchAnalyticsEvent(samplePayload); }; }; var createDispatchAverage = function createDispatchAverage(action, view) { return function (_ref, severity) { var _contextIdentifierPlu3; var mean = _ref.mean, median = _ref.median, sampleSize = _ref.sampleSize; var state = view.state; var nodeCount = getNodeCount(state); var averagePayload = { action: action, actionSubject: _analytics.ACTION_SUBJECT.EDITOR, attributes: _objectSpread(_objectSpread({ mean: mean, median: median, sampleSize: sampleSize }, nodeCount), {}, { nodeSize: state.doc.nodeSize, severity: shouldTrackSeverity ? severity : undefined, objectId: contextIdentifierPlugin === null || contextIdentifierPlugin === void 0 || (_contextIdentifierPlu3 = contextIdentifierPlugin.sharedState.currentState()) === null || _contextIdentifierPlu3 === void 0 || (_contextIdentifierPlu3 = _contextIdentifierPlu3.contextIdentifierProvider) === null || _contextIdentifierPlu3 === void 0 ? void 0 : _contextIdentifierPlu3.objectId }), eventType: _analytics.EVENT_TYPE.OPERATIONAL }; dispatchAnalyticsEvent(averagePayload); }; }; return new _safePlugin.SafePlugin({ key: frozenEditorPluginKey, props: (0, _isPerformanceApiAvailable.isPerformanceAPIAvailable)() ? { handleTextInput: function handleTextInput(view) { if (browserFreezeTracking !== null && browserFreezeTracking !== void 0 && browserFreezeTracking.trackInteractionType) { interactionType = _analytics.BROWSER_FREEZE_INTERACTION_TYPE.TYPING; } if (inputLatencyTracker) { var end = inputLatencyTracker.start(); // This is called after all handleTextInput events are executed which means first handleTextInput time incorporates following handleTextInput processing time // Also this is called before browser rendering so it doesn't count it. requestAnimationFrame(end); } return false; }, handleDOMEvents: browserFreezeTracking !== null && browserFreezeTracking !== void 0 && browserFreezeTracking.trackInteractionType ? { click: function click() { interactionType = (0, _frozenEditor.setInteractionType)(_analytics.BROWSER_FREEZE_INTERACTION_TYPE.CLICKING); return false; }, paste: function paste() { interactionType = (0, _frozenEditor.setInteractionType)(_analytics.BROWSER_FREEZE_INTERACTION_TYPE.PASTING); return false; } } : undefined } : undefined, view: function view(_view) { if (!(0, _isPerformanceApiAvailable.isPerformanceObserverAvailable)()) { return {}; } inputLatencyTracker = new _inputLatencyTracking.default({ samplingRate: samplingRate, slowThreshold: slowThreshold, normalThreshold: severityThresholdNormal, degradedThreshold: severityThresholdDegraded, dispatchSample: createDispatchSample(_analytics.ACTION.INPUT_PERF_SAMPLING, _view), dispatchAverage: createDispatchAverage(_analytics.ACTION.INPUT_PERF_SAMPLING_AVG, _view), onSlowInput: function onSlowInput(time) { var _contextIdentifierPlu4; var state = _view.state; var nodesCount = getNodeCount(state); dispatchAnalyticsEvent({ action: _analytics.ACTION.SLOW_INPUT, actionSubject: _analytics.ACTION_SUBJECT.EDITOR, attributes: _objectSpread(_objectSpread({ time: time, nodeSize: state.doc.nodeSize }, nodesCount), {}, { objectId: contextIdentifierPlugin === null || contextIdentifierPlugin === void 0 || (_contextIdentifierPlu4 = contextIdentifierPlugin.sharedState.currentState()) === null || _contextIdentifierPlu4 === void 0 || (_contextIdentifierPlu4 = _contextIdentifierPlu4.contextIdentifierProvider) === null || _contextIdentifierPlu4 === void 0 ? void 0 : _contextIdentifierPlu4.objectId }), eventType: _analytics.EVENT_TYPE.OPERATIONAL }); } }); var observer; try { observer = new PerformanceObserver(function (list) { var perfEntries = list.getEntries(); for (var i = 0; i < perfEntries.length; i++) { var duration = perfEntries[i].duration; if (duration > freezeThreshold) { dispatchLongTaskEvent(contextIdentifierPlugin)(dispatchAnalyticsEvent, _view, duration, getNodeCount, browserFreezeTracking !== null && browserFreezeTracking !== void 0 && browserFreezeTracking.trackInteractionType ? interactionType : undefined, (0, _analytics2.getAnalyticsEventSeverity)(duration, // Ignored via go/ees007 // eslint-disable-next-line @atlaskit/editor/enforce-todo-comment-format //TODO: get right values here severityThresholdNormal, severityThresholdDegraded)); } } }); // register observer for long task notifications observer.observe({ entryTypes: ['longtask'] }); } catch (e) {} return { destroy: function destroy() { var _inputLatencyTracker, _observer; (_inputLatencyTracker = inputLatencyTracker) === null || _inputLatencyTracker === void 0 || _inputLatencyTracker.flush(); (_observer = observer) === null || _observer === void 0 || _observer.disconnect(); } }; } }); }; };