/** * UpdateHtml.js * * Released under LGPL License. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ import Writer from 'tinymce/core/api/html/Writer'; import SaxParser from 'tinymce/core/api/html/SaxParser'; import Schema from 'tinymce/core/api/html/Schema'; import DOMUtils from 'tinymce/core/api/dom/DOMUtils'; import Size from './Size'; const DOM = DOMUtils.DOM; const setAttributes = function (attrs, updatedAttrs) { let name; let i; let value; let attr; for (name in updatedAttrs) { value = '' + updatedAttrs[name]; if (attrs.map[name]) { i = attrs.length; while (i--) { attr = attrs[i]; if (attr.name === name) { if (value) { attrs.map[name] = value; attr.value = value; } else { delete attrs.map[name]; attrs.splice(i, 1); } } } } else if (value) { attrs.push({ name, value }); attrs.map[name] = value; } } }; const normalizeHtml = function (html) { const writer = Writer(); const parser = SaxParser(writer); parser.parse(html); return writer.getContent(); }; const updateHtmlSax = function (html, data, updateAll?) { const writer = Writer(); let sourceCount = 0; let hasImage; SaxParser({ validate: false, allow_conditional_comments: true, special: 'script,noscript', comment (text) { writer.comment(text); }, cdata (text) { writer.cdata(text); }, text (text, raw) { writer.text(text, raw); }, start (name, attrs, empty) { switch (name) { case 'video': case 'object': case 'embed': case 'img': case 'iframe': if (data.height !== undefined && data.width !== undefined) { setAttributes(attrs, { width: data.width, height: data.height }); } break; } if (updateAll) { switch (name) { case 'video': setAttributes(attrs, { poster: data.poster, src: '' }); if (data.source2) { setAttributes(attrs, { src: '' }); } break; case 'iframe': setAttributes(attrs, { src: data.source1 }); break; case 'source': sourceCount++; if (sourceCount <= 2) { setAttributes(attrs, { src: data['source' + sourceCount], type: data['source' + sourceCount + 'mime'] }); if (!data['source' + sourceCount]) { return; } } break; case 'img': if (!data.poster) { return; } hasImage = true; break; } } writer.start(name, attrs, empty); }, end (name) { if (name === 'video' && updateAll) { for (let index = 1; index <= 2; index++) { if (data['source' + index]) { const attrs: any = []; attrs.map = {}; if (sourceCount < index) { setAttributes(attrs, { src: data['source' + index], type: data['source' + index + 'mime'] }); writer.start('source', attrs, true); } } } } if (data.poster && name === 'object' && updateAll && !hasImage) { const imgAttrs: any = []; imgAttrs.map = {}; setAttributes(imgAttrs, { src: data.poster, width: data.width, height: data.height }); writer.start('img', imgAttrs, true); } writer.end(name); } }, Schema({})).parse(html); return writer.getContent(); }; const isEphoxEmbed = function (html) { const fragment = DOM.createFragment(html); return DOM.getAttrib(fragment.firstChild, 'data-ephox-embed-iri') !== ''; }; const updateEphoxEmbed = function (html, data) { const fragment = DOM.createFragment(html); const div = fragment.firstChild as Element; Size.setMaxWidth(div, data.width); Size.setMaxHeight(div, data.height); return normalizeHtml(div.outerHTML); }; const updateHtml = function (html, data, updateAll?) { return isEphoxEmbed(html) ? updateEphoxEmbed(html, data) : updateHtmlSax(html, data, updateAll); }; export default { updateHtml };