quill-delta-to-html
Version:
Converts Quill's delta ops to HTML
160 lines (127 loc) • 4.57 kB
text/typescript
import { ListType, AlignType, DirectionType, ScriptType } from './value-types';
import { MentionSanitizer } from "./mentions/MentionSanitizer";
import './extensions/String';
import { IMention } from "./mentions/MentionSanitizer";
interface IOpAttributes {
background?: string | undefined,
color?: string | undefined,
font?: string | undefined,
size?: string | undefined,
width?: string | undefined,
link?: string | undefined,
bold?: boolean | undefined,
italic?: boolean | undefined,
underline?: boolean | undefined,
strike?: boolean | undefined,
script?: ScriptType,
code?: boolean | undefined,
list?: ListType,
blockquote?: boolean | undefined,
'code-block'?: boolean | undefined,
header?: number | undefined,
align?: AlignType,
direction?: DirectionType,
indent?: number | undefined,
mentions?: boolean | undefined,
mention?: IMention | undefined,
target?: string | undefined,
}
class OpAttributeSanitizer {
static sanitize(dirtyAttrs: IOpAttributes): IOpAttributes {
var cleanAttrs: any = {};
if (!dirtyAttrs || typeof dirtyAttrs !== 'object') {
return cleanAttrs;
}
let booleanAttrs = [
'bold', 'italic', 'underline', 'strike', 'code',
'blockquote', 'code-block'
];
let colorAttrs = ['background', 'color'];
let { font, size, link, script, list, header, align,
direction, indent, mentions, mention, width, target
} = dirtyAttrs;
let sanitizedAttrs = [...booleanAttrs, ...colorAttrs,
'font', 'size', 'link', 'script', 'list', 'header', 'align',
'direction', 'indent', 'mentions', 'mention', 'width'
];
booleanAttrs.forEach(function (prop: string) {
var v = (<any>dirtyAttrs)[prop];
if (v) {
cleanAttrs[prop] = !!v;
}
});
colorAttrs.forEach(function (prop: string) {
var val = (<any>dirtyAttrs)[prop];
if (val && (OpAttributeSanitizer.IsValidHexColor(val + '') ||
OpAttributeSanitizer.IsValidColorLiteral(val + ''))) {
cleanAttrs[prop] = val;
}
});
if (font && OpAttributeSanitizer.IsValidFontName(font + '')) {
cleanAttrs.font = font;
}
if (size && OpAttributeSanitizer.IsValidSize(size + '')) {
cleanAttrs.size = size;
}
if (width && OpAttributeSanitizer.IsValidWidth(width + '')) {
cleanAttrs.width = width;
}
if (link) {
cleanAttrs.link = (link + '')._sanitizeUrl();
}
if (target && OpAttributeSanitizer.isValidTarget(target)) {
cleanAttrs.target = target;
}
if (script === ScriptType.Sub || ScriptType.Super === script) {
cleanAttrs.script = script;
}
if (list === ListType.Bullet || list === ListType.Ordered) {
cleanAttrs.list = list;
}
if (Number(header)) {
cleanAttrs.header = Math.min(Number(header), 6);
}
if (align === AlignType.Center || align === AlignType.Right || align === AlignType.Justify) {
cleanAttrs.align = align;
}
if (direction === DirectionType.Rtl) {
cleanAttrs.direction = direction;
}
if (indent && Number(indent)) {
cleanAttrs.indent = Math.min(Number(indent), 30);
}
if (mentions && mention) {
let sanitizedMention = MentionSanitizer.sanitize(mention);
if (Object.keys(sanitizedMention).length > 0) {
cleanAttrs.mentions = !!mentions;
cleanAttrs.mention = mention;
}
}
return Object.keys(dirtyAttrs).reduce((cleaned, k) => {
// this is a custom attr, put it back
if (sanitizedAttrs.indexOf(k) === -1) {
cleaned[k] = (<any>dirtyAttrs)[k];
};
return cleaned;
}, cleanAttrs);
}
static IsValidHexColor(colorStr: string) {
return !!colorStr.match(/^#([0-9A-F]{6}|[0-9A-F]{3})$/i);
}
static IsValidColorLiteral(colorStr: string) {
return !!colorStr.match(/^[a-z]{1,50}$/i);
}
static IsValidFontName(fontName: string) {
return !!fontName.match(/^[a-z\s0-9\- ]{1,30}$/i)
}
static IsValidSize(size: string) {
return !!size.match(/^[a-z0-9\-]{1,20}$/i)
}
static IsValidWidth(width: string) {
return !!width.match(/^[0-9]*(px|em|%)?$/)
}
static isValidTarget(target: string) {
return !!target.match(/^[_a-zA-Z0-9\-]{1,50}$/);
}
}
export { OpAttributeSanitizer, IOpAttributes }