UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

144 lines 5.13 kB
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '../analytics'; const whitelistedAttributes = ['align', 'annotationType', 'extensionKey', 'extensionType', 'layout', 'type', 'localId', 'mode', 'language', 'timestamp', 'state', 'originalWidth', 'originalHeight', 'height', 'width', 'shortName', 'level', 'userType', 'order', 'panelType', 'color', 'style', 'isNumberColumnEnabled', 'colspan', 'rowspan', 'colwidth', 'background']; function concatAncestorHierarchy(node, ancestoryHierarchy) { const { name } = node.type; // Space concatenator used to reduce analytics payload size return ancestoryHierarchy ? `${ancestoryHierarchy} ${name}` : name; } const sanitizeMarks = (marks = []) => { let sanitizedMarks = []; marks.forEach(mark => { if (mark.attrs) { const attrs = sanitizeAttributes(mark.attrs); sanitizedMarks.push({ ...mark, attrs }); } else { sanitizedMarks.push({ ...mark }); } }); return sanitizedMarks; }; const sanitizeAttributes = (attrs = {}) => { let sanitizedAttrs = Object.assign({}, attrs); Object.keys(attrs).filter(key => !whitelistedAttributes.includes(key)).forEach(key => { sanitizedAttrs[key] !== null ? sanitizedAttrs[key] = '' : sanitizedAttrs[key] = 'null'; }); return sanitizedAttrs; }; const trackUnsupportedContentTooltipActionFor = (action, dispatchAnalyticsEvent, unsupportedContentType, originalNodeType) => { dispatchAnalyticsEvent({ action: action, actionSubjectId: unsupportedContentType, actionSubject: ACTION_SUBJECT.TOOLTIP, eventType: EVENT_TYPE.UI, attributes: { unsupportedNodeType: originalNodeType } }); }; export const findAndTrackUnsupportedContentNodes = (node, schema, dispatchAnalyticsEvent, ancestorHierarchy = '') => { const { type: nodeType, marks: nodeMarks } = node; const { unsupportedMark, unsupportedNodeAttribute } = schema.marks; const { unsupportedInline, unsupportedBlock } = schema.nodes; const parentType = ancestorHierarchy.split(' ').pop() || ''; if (nodeMarks.length) { nodeMarks.forEach(mark => { if (mark.type === unsupportedMark) { const { originalValue } = mark.attrs || {}; const { type } = originalValue || {}; const unsupportedNode = { type: type || '', ancestry: ancestorHierarchy, parentType: parentType, marks: [], attrs: originalValue.attrs || {} }; fireUnsupportedEvent(dispatchAnalyticsEvent, ACTION_SUBJECT_ID.UNSUPPORTED_MARK, unsupportedNode); } else if (mark.type === unsupportedNodeAttribute) { const { unsupported } = mark.attrs || {}; const unsupportedNodeAttribute = { type: nodeType.name || '', ancestry: ancestorHierarchy, parentType: parentType, marks: [], attrs: unsupported || {} }; fireUnsupportedEvent(dispatchAnalyticsEvent, ACTION_SUBJECT_ID.UNSUPPORTED_NODE_ATTRIBUTE, unsupportedNodeAttribute); } }); } if (nodeType === unsupportedInline || nodeType === unsupportedBlock) { const { originalValue } = node.attrs || {}; const { marks } = originalValue || []; const { attrs } = originalValue || {}; const { type } = originalValue || {}; const unsupportedNode = { type: type || '', ancestry: ancestorHierarchy, parentType: parentType, marks: marks || [], attrs: attrs || {} }; const actionSubjectId = nodeType === unsupportedInline ? ACTION_SUBJECT_ID.UNSUPPORTED_INLINE : ACTION_SUBJECT_ID.UNSUPPORTED_BLOCK; fireUnsupportedEvent(dispatchAnalyticsEvent, actionSubjectId, unsupportedNode); } else { // Recursive check for nested content node.content.forEach(childNode => findAndTrackUnsupportedContentNodes(childNode, schema, dispatchAnalyticsEvent, concatAncestorHierarchy(node, ancestorHierarchy))); } }; export const fireUnsupportedEvent = (dispatchAnalyticsEvent, actionSubjectId, unsupportedNode, errorCode) => { const sanitizedAttrs = sanitizeAttributes(unsupportedNode.attrs); const sanitizedMarks = sanitizeMarks(unsupportedNode.marks); const sanitizedUnsupportedNode = { type: unsupportedNode.type, ancestry: unsupportedNode.ancestry, parentType: unsupportedNode.parentType, attrs: sanitizedAttrs, marks: sanitizedMarks }; const payload = { action: ACTION.UNSUPPORTED_CONTENT_ENCOUNTERED, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId, attributes: { unsupportedNode: sanitizedUnsupportedNode, ...(!!errorCode && { errorCode }) }, eventType: EVENT_TYPE.TRACK }; dispatchAnalyticsEvent(payload); }; export const trackUnsupportedContentTooltipDisplayedFor = (dispatchAnalyticsEvent, unsupportedContentType, originalNodeType) => { trackUnsupportedContentTooltipActionFor(ACTION.UNSUPPORTED_TOOLTIP_VIEWED, dispatchAnalyticsEvent, unsupportedContentType, originalNodeType); };