/** * Created by roobm on 16.05.2017. * Mapping from normalized tag names to placeholder names. */ /* copied from https://github.com/angular/angular/blob/master/packages/compiler/src/i18n/serializers/placeholder.ts */ const TAG_TO_PLACEHOLDER_NAMES: {[k: string]: string} = { 'A': 'LINK', 'B': 'BOLD_TEXT', 'BR': 'LINE_BREAK', 'EM': 'EMPHASISED_TEXT', 'H1': 'HEADING_LEVEL1', 'H2': 'HEADING_LEVEL2', 'H3': 'HEADING_LEVEL3', 'H4': 'HEADING_LEVEL4', 'H5': 'HEADING_LEVEL5', 'H6': 'HEADING_LEVEL6', 'HR': 'HORIZONTAL_RULE', 'I': 'ITALIC_TEXT', 'LI': 'LIST_ITEM', 'LINK': 'MEDIA_LINK', 'OL': 'ORDERED_LIST', 'P': 'PARAGRAPH', 'Q': 'QUOTATION', 'S': 'STRIKETHROUGH_TEXT', 'SMALL': 'SMALL_TEXT', 'SUB': 'SUBSTRIPT', 'SUP': 'SUPERSCRIPT', 'TBODY': 'TABLE_BODY', 'TD': 'TABLE_CELL', 'TFOOT': 'TABLE_FOOTER', 'TH': 'TABLE_HEADER_CELL', 'THEAD': 'TABLE_HEADER', 'TR': 'TABLE_ROW', 'TT': 'MONOSPACED_TEXT', 'U': 'UNDERLINED_TEXT', 'UL': 'UNORDERED_LIST', }; /** * HTML Tags (in uppercase) that are empty, they have no content, but do not need a close tag, e.g.
, ,
. */ const VOID_TAGS = ['BR', 'HR', 'IMG', 'AREA', 'LINK', 'WBR']; export class TagMapping { public getStartTagPlaceholderName(tag: string, id: number): string { const upperTag = tag.toUpperCase(); const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`; return `START_${baseName}` + this.counterString(id); } public getCloseTagPlaceholderName(tag: string): string { const upperTag = tag.toUpperCase(); const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`; return `CLOSE_${baseName}`; } public getEmptyTagPlaceholderName(tag: string, id: number): string { const upperTag = tag.toUpperCase(); const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`; return baseName + this.counterString(id); } public getCtypeForTag(tag: string): string { switch (tag.toLowerCase()) { case 'br': return 'lb'; case 'img': return 'image'; default: return `x-${tag}`; } } public getTagnameFromStartTagPlaceholderName(placeholderName: string): string { if (placeholderName.startsWith('START_TAG_')) { return this.stripCounter(placeholderName.substring('START_TAG_'.length)).toLowerCase(); } else if (placeholderName.startsWith('START_')) { const ph = this.stripCounter(placeholderName.substring('START_'.length)); const matchKey = Object.keys(TAG_TO_PLACEHOLDER_NAMES).find((key) => TAG_TO_PLACEHOLDER_NAMES[key] === ph); return matchKey ? matchKey.toLowerCase() : null; } return null; } public getTagnameFromCloseTagPlaceholderName(placeholderName: string): string { if (placeholderName.startsWith('CLOSE_TAG_')) { return this.stripCounter(placeholderName.substring('CLOSE_TAG_'.length)).toLowerCase(); } else if (placeholderName.startsWith('CLOSE_')) { const ph = this.stripCounter(placeholderName.substring('CLOSE_'.length)); const matchKey = Object.keys(TAG_TO_PLACEHOLDER_NAMES).find((key) => TAG_TO_PLACEHOLDER_NAMES[key] === ph); return matchKey ? matchKey.toLowerCase() : null; } return null; } /** * Test, wether placeholder name stands for empty html tag. * @param placeholderName can be TAG_ or just */ public isEmptyTagPlaceholderName(placeholderName: string): boolean { const ph = this.stripCounter(placeholderName); let matchKey; if (ph.startsWith('TAG_')) { matchKey = ph.substring(4).toUpperCase(); } else { matchKey = Object.keys(TAG_TO_PLACEHOLDER_NAMES).find((key) => TAG_TO_PLACEHOLDER_NAMES[key] === ph); } if (matchKey) { if (VOID_TAGS.indexOf(matchKey) >= 0) { return true; } } return false; } /** * tagname of empty tag placeholder. * @param placeholderName can be TAG_ or just */ public getTagnameFromEmptyTagPlaceholderName(placeholderName: string): string { const ph = this.stripCounter(placeholderName); let matchKey; if (ph.startsWith('TAG_')) { matchKey = ph.substring(4).toUpperCase(); } else { matchKey = Object.keys(TAG_TO_PLACEHOLDER_NAMES).find((key) => TAG_TO_PLACEHOLDER_NAMES[key] === ph); } if (matchKey) { if (VOID_TAGS.indexOf(matchKey) >= 0) { return matchKey.toLowerCase(); } else { return null; } } return null; } /** * If placeholder ends with _[0-9]+, strip that number. * @param placeholderName placeholderName * @return placeholderName without counter at end. */ private stripCounter(placeholderName: string): string { if (placeholderName) { const re = /(.*)_[0-9]+$/; if (placeholderName.match(re)) { return placeholderName.replace(re, '$1'); } } return placeholderName; } /** * String suffix for counter. * If counter is 0, it is empty, otherwise _. * @param id id * @return suffix for counter. */ private counterString(id: number) { if (id === 0) { return ''; } else { return '_' + id.toString(10); } } }