@atlaskit/editor-plugin-code-block
Version:
Code block plugin for @atlaskit/editor-core
138 lines (133 loc) • 7.54 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.syncPendingDetectionTimers = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _analytics = require("@atlaskit/editor-common/analytics");
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
var _actions = require("../pm-plugins/actions");
var _autoDetectState = require("../pm-plugins/auto-detect-state");
var _autoDetectState2 = require("./auto-detect-state");
var _languageDetect = require("./language-detect");
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 AUTO_DETECT_DEBOUNCE_MS = 500;
// Stored positions are mapped through transactions; verify the localId before using them.
var getCodeBlockFromEntry = function getCodeBlockFromEntry(view, localId, entry) {
var node = view.state.doc.nodeAt(entry.pos);
var codeBlockType = view.state.schema.nodes.codeBlock;
if ((node === null || node === void 0 ? void 0 : node.type) === codeBlockType && node.attrs.localId === localId) {
return {
node: node,
pos: entry.pos
};
}
return null;
};
// Runs after debounce, so it must re-read current editor state before applying language changes.
var runPendingDetection = function runPendingDetection(view, localId, api) {
var _api$core;
var pluginState = _autoDetectState.autoDetectPluginKey.getState(view.state);
var entry = pluginState === null || pluginState === void 0 ? void 0 : pluginState.languageDetectionMap[localId];
if (!(entry !== null && entry !== void 0 && entry.isPending)) {
return;
}
var found = getCodeBlockFromEntry(view, localId, entry);
if (!found) {
return;
}
var detectedLanguage = (0, _languageDetect.detectLanguage)(found.node.textContent);
var detectionResult = detectedLanguage ? 'detected' : 'noneDetected';
var detectionPhase = entry.detectionResult ? 'redetection' : 'initial';
// Keep a previous auto-detected language when the latest snippet is too weak to classify.
var shouldPreserveAutoDetectedLanguage = !detectedLanguage && Boolean(entry.autoDetectedLanguage) && found.node.attrs.language === entry.autoDetectedLanguage;
var nextEntry = _objectSpread(_objectSpread({}, (0, _autoDetectState2.createAutoDetectEntry)(found.node, found.pos, false, entry)), {}, {
detectionResult: detectionResult,
autoDetectedLanguage: detectedLanguage !== null && detectedLanguage !== void 0 ? detectedLanguage : entry.autoDetectedLanguage
});
// If there is no confident detection, record the result without clearing user-visible language.
var shouldOnlyUpdateDetectionState = !detectedLanguage && (!found.node.attrs.language || shouldPreserveAutoDetectedLanguage);
var hasDetectedLanguageChange = Boolean(detectedLanguage) && found.node.attrs.language !== detectedLanguage;
var shouldClearStaleLanguage = !detectedLanguage && Boolean(found.node.attrs.language) && !shouldPreserveAutoDetectedLanguage;
var shouldUpdateNodeLanguage = (0, _platformFeatureFlags.fg)('platform_editor_code_block_dogfooding_patch') ? hasDetectedLanguageChange || shouldClearStaleLanguage : !shouldOnlyUpdateDetectionState;
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref) {
var tr = _ref.tr;
if (shouldUpdateNodeLanguage) {
tr.setNodeMarkup(found.pos, undefined, _objectSpread(_objectSpread({}, found.node.attrs), {}, {
language: detectedLanguage
}), found.node.marks);
}
tr.setMeta(_autoDetectState.autoDetectPluginKey, {
type: _actions.ACTIONS.SET_AUTO_DETECT_ENTRY,
data: {
localId: localId,
entry: nextEntry
}
});
// When platform_editor_code_block_dogfooding_patch is cleaned up, merge this with the previous shouldUpdateNodeLanguage check.
if (!(0, _platformFeatureFlags.fg)('platform_editor_code_block_dogfooding_patch') || shouldUpdateNodeLanguage) {
var _api$analytics;
api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
action: _analytics.ACTION.LANGUAGE_AUTO_DETECTED,
actionSubject: _analytics.ACTION_SUBJECT.CODE_BLOCK,
attributes: _objectSpread({
language: detectedLanguage !== null && detectedLanguage !== void 0 ? detectedLanguage : 'none',
detectionResult: detectionResult
}, (0, _platformFeatureFlags.fg)('platform_editor_code_block_dogfooding_patch') ? {
detectionPhase: detectionPhase
} : {}),
eventType: _analytics.EVENT_TYPE.TRACK
})(tr);
}
// Language detection runs in the background and should not move the viewport.
return tr.setMeta('scrollIntoView', false);
});
};
var clearTimer = function clearTimer(timers, localId) {
var scheduledDetection = timers.get(localId);
if (scheduledDetection) {
clearTimeout(scheduledDetection.timer);
timers.delete(localId);
}
};
// Keeps one debounce timer per pending code block and drops timers for stale entries.
var syncPendingDetectionTimers = exports.syncPendingDetectionTimers = function syncPendingDetectionTimers(view, timers, api) {
var _pluginState$language;
var pluginState = _autoDetectState.autoDetectPluginKey.getState(view.state);
var pendingEntries = Object.entries((_pluginState$language = pluginState === null || pluginState === void 0 ? void 0 : pluginState.languageDetectionMap) !== null && _pluginState$language !== void 0 ? _pluginState$language : {}).filter(function (_ref2) {
var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
entry = _ref3[1];
return entry.isPending;
});
var pendingLocalIds = new Set(pendingEntries.map(function (_ref4) {
var _ref5 = (0, _slicedToArray2.default)(_ref4, 1),
localId = _ref5[0];
return localId;
}));
pendingEntries.forEach(function (_ref6) {
var _ref7 = (0, _slicedToArray2.default)(_ref6, 2),
localId = _ref7[0],
entry = _ref7[1];
var scheduledDetection = timers.get(localId);
if ((scheduledDetection === null || scheduledDetection === void 0 ? void 0 : scheduledDetection.lastObservedText) === entry.lastObservedText) {
return;
}
clearTimer(timers, localId);
var timer = setTimeout(function () {
timers.delete(localId);
runPendingDetection(view, localId, api);
}, AUTO_DETECT_DEBOUNCE_MS);
timers.set(localId, {
lastObservedText: entry.lastObservedText,
timer: timer
});
});
timers.forEach(function (_, localId) {
if (!pendingLocalIds.has(localId)) {
clearTimer(timers, localId);
}
});
};