@atlaskit/adf-schema
Version:
Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs
183 lines (178 loc) • 5.39 kB
JavaScript
import { N30 } from '../../utils/colors';
/**
* @name media_node
*/
export var defaultAttrs = {
id: {
default: ''
},
type: {
default: 'file'
},
collection: {
default: ''
},
occurrenceKey: {
default: null
},
alt: {
default: ''
},
width: {
default: null
},
height: {
default: null
},
url: {
default: null
},
__fileName: {
default: null
},
__fileSize: {
default: null
},
__fileMimeType: {
default: null
},
__displayType: {
default: null
},
__contextId: {
default: null
},
__mediaTraceId: {
default: null
},
__external: {
default: false
}
};
export var createMediaSpec = function createMediaSpec(attributes) {
var inline = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var domNodeType = inline ? 'span' : 'div';
var nodeName = inline ? 'mediaInline' : 'media';
var parseDOM = [{
tag: "".concat(domNodeType, "[data-node-type=\"").concat(nodeName, "\"]"),
getAttrs: function getAttrs(dom) {
var attrs = {};
if (attributes) {
Object.keys(attributes).forEach(function (k) {
var key = camelCaseToKebabCase(k).replace(/^__/, '');
var value = dom.getAttribute("data-".concat(key)) || '';
if (value) {
attrs[k] = value;
}
});
}
// Need to do validation & type conversion manually
if (attrs.__fileSize) {
attrs.__fileSize = +attrs.__fileSize;
}
var width = Number(attrs.width);
if (typeof width !== 'undefined' && !isNaN(width)) {
attrs.width = width;
}
var height = Number(attrs.height);
if (typeof height !== 'undefined' && !isNaN(height)) {
attrs.height = height;
}
return attrs;
}
},
// Don't match data URI
{
tag: 'img[src^="data:image"]',
ignore: true
}];
// media-inline.ts uses this same function to generate the nodespec
// this ensures that we don't make a media inline out of a copied image
// https://product-fabric.atlassian.net/browse/EDM-2996
if (!inline) {
parseDOM.push({
tag: 'img:not(.smart-link-icon)',
getAttrs: function getAttrs(dom) {
return {
type: 'external',
url: dom.getAttribute('src') || '',
alt: dom.getAttribute('alt') || ''
};
}
});
}
return {
selectable: true,
inline: inline,
group: inline ? 'inline' : undefined,
attrs: attributes,
parseDOM: parseDOM,
toDOM: function toDOM(node) {
var attrs = {
'data-id': node.attrs.id,
'data-node-type': "".concat(nodeName),
'data-type': node.attrs.type,
'data-collection': node.attrs.collection,
'data-occurrence-key': node.attrs.occurrenceKey,
'data-width': node.attrs.width,
'data-height': node.attrs.height,
'data-url': node.attrs.url,
'data-alt': node.attrs.alt,
// toDOM is used for static rendering as well as editor rendering. This comes into play for
// emails, copy/paste, etc, so the title and styling here *is* useful (despite a React-based
// node view being used for editing).
title: 'Attachment',
// Manually kept in sync with the style of media cards. The goal is to render a plain gray
// rectangle that provides an affordance for media.
style: "display: inline-block; border-radius: 3px; background: ".concat(N30, "; box-shadow: 0 1px 1px rgba(9, 30, 66, 0.2), 0 0 1px 0 rgba(9, 30, 66, 0.24);")
};
copyPrivateAttributes(node.attrs, attrs, function (key) {
return "data-".concat(camelCaseToKebabCase(key.slice(2)));
});
return ["".concat(domNodeType), attrs];
}
};
};
export var media = createMediaSpec(defaultAttrs);
export var camelCaseToKebabCase = function camelCaseToKebabCase(str) {
return str.replace(/([^A-Z]+)([A-Z])/g, function (_, x, y) {
return "".concat(x, "-").concat(y.toLowerCase());
});
};
export var copyPrivateAttributes = function copyPrivateAttributes(from, to, map) {
if (media.attrs) {
Object.keys(media.attrs).forEach(function (key) {
if (key[0] === '_' && key[1] === '_' && from[key]) {
to[map ? map(key) : key] = from[key];
}
});
}
};
/**
* There's no concept of optional property in ProseMirror. It sets value as `null`
* when there's no use of any property. We are filtering out all private & optional attrs here.
*/
var optionalAttributes = ['occurrenceKey', 'width', 'height', 'url', 'alt'];
var externalOnlyAttributes = ['type', 'url', 'width', 'height', 'alt'];
export var toJSON = function toJSON(node) {
return {
attrs: Object.keys(node.attrs)
// Strip private attributes e.g. __fileName, __fileSize, __fileMimeType, etc.
.filter(function (key) {
return !(key[0] === '_' && key[1] === '_');
}).reduce(function (obj, key) {
if (node.attrs.type === 'external' && externalOnlyAttributes.indexOf(key) === -1) {
return obj;
}
if (optionalAttributes.indexOf(key) > -1 && (node.attrs[key] === null || node.attrs[key] === '')) {
return obj;
}
if (['width', 'height'].indexOf(key) !== -1) {
obj[key] = Number(node.attrs[key]);
return obj;
}
obj[key] = node.attrs[key];
return obj;
}, {})
};
};