UNPKG

beansflight-json-form

Version:

> **版本号:verison 0.23.17**

1,307 lines (1,273 loc) 37.6 kB
/** * TinyMCE version 6.1.0 (2022-06-29) */ ;(function () { 'use strict' var global$6 = tinymce.util.Tools.resolve('tinymce.PluginManager') const hasProto = (v, constructor, predicate) => { var _a if (predicate(v, constructor.prototype)) { return true } else { return ( ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name ) } } const typeOf = x => { const t = typeof x if (x === null) { return 'null' } else if (t === 'object' && Array.isArray(x)) { return 'array' } else if ( t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o)) ) { return 'string' } else { return t } } const isType = type => value => typeOf(value) === type const isString = isType('string') const isObject = isType('object') const isArray = isType('array') const isNullable = a => a === null || a === undefined const isNonNullable = a => !isNullable(a) class Optional { constructor(tag, value) { this.tag = tag this.value = value } static some(value) { return new Optional(true, value) } static none() { return Optional.singletonNone } fold(onNone, onSome) { if (this.tag) { return onSome(this.value) } else { return onNone() } } isSome() { return this.tag } isNone() { return !this.tag } map(mapper) { if (this.tag) { return Optional.some(mapper(this.value)) } else { return Optional.none() } } bind(binder) { if (this.tag) { return binder(this.value) } else { return Optional.none() } } exists(predicate) { return this.tag && predicate(this.value) } forall(predicate) { return !this.tag || predicate(this.value) } filter(predicate) { if (!this.tag || predicate(this.value)) { return this } else { return Optional.none() } } getOr(replacement) { return this.tag ? this.value : replacement } or(replacement) { return this.tag ? this : replacement } getOrThunk(thunk) { return this.tag ? this.value : thunk() } orThunk(thunk) { return this.tag ? this : thunk() } getOrDie(message) { if (!this.tag) { throw new Error( message !== null && message !== void 0 ? message : 'Called getOrDie on None' ) } else { return this.value } } static from(value) { return isNonNullable(value) ? Optional.some(value) : Optional.none() } getOrNull() { return this.tag ? this.value : null } getOrUndefined() { return this.value } each(worker) { if (this.tag) { worker(this.value) } } toArray() { return this.tag ? [this.value] : [] } toString() { return this.tag ? `some(${this.value})` : 'none()' } } Optional.singletonNone = new Optional(false) const nativePush = Array.prototype.push const each$1 = (xs, f) => { for (let i = 0, len = xs.length; i < len; i++) { const x = xs[i] f(x, i) } } const flatten = xs => { const r = [] for (let i = 0, len = xs.length; i < len; ++i) { if (!isArray(xs[i])) { throw new Error( 'Arr.flatten item ' + i + ' was not an array, input: ' + xs ) } nativePush.apply(r, xs[i]) } return r } const Cell = initial => { let value = initial const get = () => { return value } const set = v => { value = v } return { get, set } } const keys = Object.keys const hasOwnProperty = Object.hasOwnProperty const each = (obj, f) => { const props = keys(obj) for (let k = 0, len = props.length; k < len; k++) { const i = props[k] const x = obj[i] f(x, i) } } const get$1 = (obj, key) => { return has(obj, key) ? Optional.from(obj[key]) : Optional.none() } const has = (obj, key) => hasOwnProperty.call(obj, key) const option = name => editor => editor.options.get(name) const register$2 = editor => { const registerOption = editor.options.register registerOption('audio_template_callback', { processor: 'function' }) registerOption('video_template_callback', { processor: 'function' }) registerOption('iframe_template_callback', { processor: 'function' }) registerOption('media_live_embeds', { processor: 'boolean', default: true }) registerOption('media_filter_html', { processor: 'boolean', default: true }) registerOption('media_url_resolver', { processor: 'function' }) registerOption('media_alt_source', { processor: 'boolean', default: true }) registerOption('media_poster', { processor: 'boolean', default: true }) registerOption('media_dimensions', { processor: 'boolean', default: true }) } const getAudioTemplateCallback = option('audio_template_callback') const getVideoTemplateCallback = option('video_template_callback') const getIframeTemplateCallback = option('iframe_template_callback') const hasLiveEmbeds = option('media_live_embeds') const shouldFilterHtml = option('media_filter_html') const getUrlResolver = option('media_url_resolver') const hasAltSource = option('media_alt_source') const hasPoster = option('media_poster') const hasDimensions = option('media_dimensions') var global$5 = tinymce.util.Tools.resolve('tinymce.util.Tools') var global$4 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils') var global$3 = tinymce.util.Tools.resolve('tinymce.html.DomParser') const DOM$1 = global$4.DOM const trimPx = value => value.replace(/px$/, '') const getEphoxEmbedData = node => { const style = node.attr('style') const styles = style ? DOM$1.parseStyle(style) : {} return { type: 'ephox-embed-iri', source: node.attr('data-ephox-embed-iri'), altsource: '', poster: '', width: get$1(styles, 'max-width').map(trimPx).getOr(''), height: get$1(styles, 'max-height').map(trimPx).getOr('') } } const htmlToData = (html, schema) => { let data = {} const parser = global$3( { validate: false, forced_root_block: false }, schema ) const rootNode = parser.parse(html) for (let node = rootNode; node; node = node.walk()) { if (node.type === 1) { const name = node.name if (node.attr('data-ephox-embed-iri')) { data = getEphoxEmbedData(node) break } else { if (!data.source && name === 'param') { data.source = node.attr('movie') } if ( name === 'iframe' || name === 'object' || name === 'embed' || name === 'video' || name === 'audio' ) { if (!data.type) { data.type = name } data = global$5.extend(node.attributes.map, data) } if (name === 'script') { data = { type: 'script', source: node.attr('src') } } if (name === 'source') { if (!data.source) { data.source = node.attr('src') } else if (!data.altsource) { data.altsource = node.attr('src') } } if (name === 'img' && !data.poster) { data.poster = node.attr('src') } } } } data.source = data.source || data.src || data.data data.altsource = data.altsource || '' data.poster = data.poster || '' return data } const guess = url => { const mimes = { mp3: 'audio/mpeg', m4a: 'audio/x-m4a', wav: 'audio/wav', mp4: 'video/mp4', webm: 'video/webm', ogg: 'video/ogg', swf: 'application/x-shockwave-flash' } const fileEnd = url.toLowerCase().split('.').pop() const mime = mimes[fileEnd] return mime ? mime : '' } var global$2 = tinymce.util.Tools.resolve('tinymce.html.Node') var global$1 = tinymce.util.Tools.resolve('tinymce.html.Serializer') const Parser = (schema, settings = {}) => global$3( { forced_root_block: false, validate: false, allow_conditional_comments: true, ...settings }, schema ) const DOM = global$4.DOM const addPx = value => (/^[0-9.]+$/.test(value) ? value + 'px' : value) const updateEphoxEmbed = (data, node) => { const style = node.attr('style') const styleMap = style ? DOM.parseStyle(style) : {} styleMap['max-width'] = addPx(data.width) styleMap['max-height'] = addPx(data.height) node.attr('style', DOM.serializeStyle(styleMap)) } const sources = ['source', 'altsource'] const updateHtml = (html, data, updateAll, schema) => { let numSources = 0 let sourceCount = 0 const parser = Parser(schema) parser.addNodeFilter('source', nodes => (numSources = nodes.length)) const rootNode = parser.parse(html) for (let node = rootNode; node; node = node.walk()) { if (node.type === 1) { const name = node.name if (node.attr('data-ephox-embed-iri')) { updateEphoxEmbed(data, node) break } else { switch (name) { case 'video': case 'object': case 'embed': case 'img': case 'iframe': if (data.height !== undefined && data.width !== undefined) { node.attr('width', data.width) node.attr('height', data.height) } break } if (updateAll) { switch (name) { case 'video': node.attr('poster', data.poster) node.attr('src', null) for (let index = numSources; index < 2; index++) { if (data[sources[index]]) { const source = new global$2('source', 1) source.attr('src', data[sources[index]]) source.attr('type', data[sources[index] + 'mime'] || null) node.append(source) } } break case 'iframe': node.attr('src', data.source) break case 'object': const hasImage = node.getAll('img').length > 0 if (data.poster && !hasImage) { node.attr('src', data.poster) const img = new global$2('img', 1) img.attr('src', data.poster) img.attr('width', data.width) img.attr('height', data.height) node.append(img) } break case 'source': if (sourceCount < 2) { node.attr('src', data[sources[sourceCount]]) node.attr('type', data[sources[sourceCount] + 'mime'] || null) if (!data[sources[sourceCount]]) { node.remove() continue } } sourceCount++ break case 'img': if (!data.poster) { node.remove() } break } } } } } return global$1({}, schema).serialize(rootNode) } const urlPatterns = [ { regex: /youtu\.be\/([\w\-_\?&=.]+)/i, type: 'iframe', w: 560, h: 314, url: 'www.youtube.com/embed/$1', allowFullscreen: true }, { regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i, type: 'iframe', w: 560, h: 314, url: 'www.youtube.com/embed/$2?$4', allowFullscreen: true }, { regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i, type: 'iframe', w: 560, h: 314, url: 'www.youtube.com/embed/$1', allowFullscreen: true }, { regex: /vimeo\.com\/([0-9]+)/, type: 'iframe', w: 425, h: 350, url: 'player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc', allowFullscreen: true }, { regex: /vimeo\.com\/(.*)\/([0-9]+)/, type: 'iframe', w: 425, h: 350, url: 'player.vimeo.com/video/$2?title=0&amp;byline=0', allowFullscreen: true }, { regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/, type: 'iframe', w: 425, h: 350, url: 'maps.google.com/maps/ms?msid=$2&output=embed"', allowFullscreen: false }, { regex: /dailymotion\.com\/video\/([^_]+)/, type: 'iframe', w: 480, h: 270, url: 'www.dailymotion.com/embed/video/$1', allowFullscreen: true }, { regex: /dai\.ly\/([^_]+)/, type: 'iframe', w: 480, h: 270, url: 'www.dailymotion.com/embed/video/$1', allowFullscreen: true } ] const getProtocol = url => { const protocolMatches = url.match(/^(https?:\/\/|www\.)(.+)$/i) if (protocolMatches && protocolMatches.length > 1) { return protocolMatches[1] === 'www.' ? 'https://' : protocolMatches[1] } else { return 'https://' } } const getUrl = (pattern, url) => { const protocol = getProtocol(url) const match = pattern.regex.exec(url) let newUrl = protocol + pattern.url for (let i = 0; i < match.length; i++) { newUrl = newUrl.replace('$' + i, () => (match[i] ? match[i] : '')) } return newUrl.replace(/\?$/, '') } const matchPattern = url => { const patterns = urlPatterns.filter(pattern => pattern.regex.test(url)) if (patterns.length > 0) { return global$5.extend({}, patterns[0], { url: getUrl(patterns[0], url) }) } else { return null } } const getIframeHtml = (data, iframeTemplateCallback) => { if (iframeTemplateCallback) { return iframeTemplateCallback(data) } else { const allowFullscreen = data.allowfullscreen ? ' allowFullscreen="1"' : '' return ( '<iframe src="' + data.source + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + '></iframe>' ) } } const getFlashHtml = data => { let html = '<object data="' + data.source + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">' if (data.poster) { html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />' } html += '</object>' return html } const getAudioHtml = (data, audioTemplateCallback) => { if (audioTemplateCallback) { return audioTemplateCallback(data) } else { return ( '<audio controls="controls" src="' + data.source + '">' + (data.altsource ? '\n<source src="' + data.altsource + '"' + (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : '') + ' />\n' : '') + '</audio>' ) } } const getVideoHtml = (data, videoTemplateCallback) => { if (videoTemplateCallback) { return videoTemplateCallback(data) } else { return ( '<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' + '<source src="' + data.source + '"' + (data.sourcemime ? ' type="' + data.sourcemime + '"' : '') + ' />\n' + (data.altsource ? '<source src="' + data.altsource + '"' + (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : '') + ' />\n' : '') + '</video>' ) } } const getScriptHtml = data => { return '<script src="' + data.source + '"></script>' } const dataToHtml = (editor, dataIn) => { const data = global$5.extend({}, dataIn) if (!data.source) { global$5.extend(data, htmlToData(data.embed, editor.schema)) if (!data.source) { return '' } } if (!data.altsource) { data.altsource = '' } if (!data.poster) { data.poster = '' } data.source = editor.convertURL(data.source, 'source') data.altsource = editor.convertURL(data.altsource, 'source') data.sourcemime = guess(data.source) data.altsourcemime = guess(data.altsource) data.poster = editor.convertURL(data.poster, 'poster') const pattern = matchPattern(data.source) if (pattern) { data.source = pattern.url data.type = pattern.type data.allowfullscreen = pattern.allowFullscreen data.width = data.width || String(pattern.w) data.height = data.height || String(pattern.h) } if (data.embed) { return updateHtml(data.embed, data, true, editor.schema) } else { const audioTemplateCallback = getAudioTemplateCallback(editor) const videoTemplateCallback = getVideoTemplateCallback(editor) const iframeTemplateCallback = getIframeTemplateCallback(editor) data.width = data.width || '300' data.height = data.height || '150' global$5.each(data, (value, key) => { data[key] = editor.dom.encode('' + value) }) if (data.type === 'iframe') { return getIframeHtml(data, iframeTemplateCallback) } else if (data.sourcemime === 'application/x-shockwave-flash') { return getFlashHtml(data) } else if (data.sourcemime.indexOf('audio') !== -1) { return getAudioHtml(data, audioTemplateCallback) } else if (data.type === 'script') { return getScriptHtml(data) } else { return getVideoHtml(data, videoTemplateCallback) } } } const isMediaElement = element => element.hasAttribute('data-mce-object') || element.hasAttribute('data-ephox-embed-iri') const setup$2 = editor => { editor.on('click keyup touchend', () => { const selectedNode = editor.selection.getNode() if ( selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object') ) { if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) { selectedNode.setAttribute('data-mce-selected', '2') } } }) editor.on('ObjectSelected', e => { const objectType = e.target.getAttribute('data-mce-object') if (objectType === 'script') { e.preventDefault() } }) editor.on('ObjectResized', e => { const target = e.target if (target.getAttribute('data-mce-object')) { let html = target.getAttribute('data-mce-html') if (html) { html = unescape(html) target.setAttribute( 'data-mce-html', escape( updateHtml( html, { width: String(e.width), height: String(e.height) }, false, editor.schema ) ) ) } } }) } const cache = {} const embedPromise = (data, dataToHtml, handler) => { return new Promise((res, rej) => { const wrappedResolve = response => { if (response.html) { cache[data.source] = response } return res({ url: data.source, html: response.html ? response.html : dataToHtml(data) }) } if (cache[data.source]) { wrappedResolve(cache[data.source]) } else { handler({ url: data.source }, wrappedResolve, rej) } }) } const defaultPromise = (data, dataToHtml) => Promise.resolve({ html: dataToHtml(data), url: data.source }) const loadedData = editor => data => dataToHtml(editor, data) const getEmbedHtml = (editor, data) => { const embedHandler = getUrlResolver(editor) return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor)) } const isCached = url => has(cache, url) const extractMeta = (sourceInput, data) => get$1(data, sourceInput).bind(mainData => get$1(mainData, 'meta')) const getValue = (data, metaData, sourceInput) => prop => { const getFromData = () => get$1(data, prop) const getFromMetaData = () => get$1(metaData, prop) const getNonEmptyValue = c => get$1(c, 'value').bind(v => v.length > 0 ? Optional.some(v) : Optional.none() ) const getFromValueFirst = () => getFromData().bind(child => isObject(child) ? getNonEmptyValue(child).orThunk(getFromMetaData) : getFromMetaData().orThunk(() => Optional.from(child)) ) const getFromMetaFirst = () => getFromMetaData().orThunk(() => getFromData().bind(child => isObject(child) ? getNonEmptyValue(child) : Optional.from(child) ) ) return { [prop]: (prop === sourceInput ? getFromValueFirst() : getFromMetaFirst() ).getOr('') } } const getDimensions = (data, metaData) => { const dimensions = {} get$1(data, 'dimensions').each(dims => { each$1(['width', 'height'], prop => { get$1(metaData, prop) .orThunk(() => get$1(dims, prop)) .each(value => (dimensions[prop] = value)) }) }) return dimensions } const unwrap = (data, sourceInput) => { const metaData = sourceInput ? extractMeta(sourceInput, data).getOr({}) : {} const get = getValue(data, metaData, sourceInput) return { ...get('source'), ...get('altsource'), ...get('poster'), ...get('embed'), ...getDimensions(data, metaData) } } const wrap = data => { const wrapped = { ...data, source: { value: get$1(data, 'source').getOr('') }, altsource: { value: get$1(data, 'altsource').getOr('') }, poster: { value: get$1(data, 'poster').getOr('') } } each$1(['width', 'height'], prop => { get$1(data, prop).each(value => { const dimensions = wrapped.dimensions || {} dimensions[prop] = value wrapped.dimensions = dimensions }) }) return wrapped } const handleError = editor => error => { const errorMessage = error && error.msg ? 'Media embed handler error: ' + error.msg : 'Media embed handler threw unknown error.' editor.notificationManager.open({ type: 'error', text: errorMessage }) } const getEditorData = editor => { const element = editor.selection.getNode() const snippet = isMediaElement(element) ? editor.serializer.serialize(element, { selection: true }) : '' return { embed: snippet, ...htmlToData(snippet, editor.schema) } } const addEmbedHtml = (api, editor) => response => { if (isString(response.url) && response.url.trim().length > 0) { const html = response.html const snippetData = htmlToData(html, editor.schema) const nuData = { ...snippetData, source: response.url, embed: html } api.setData(wrap(nuData)) } } const selectPlaceholder = (editor, beforeObjects) => { const afterObjects = editor.dom.select('*[data-mce-object]') for (let i = 0; i < beforeObjects.length; i++) { for (let y = afterObjects.length - 1; y >= 0; y--) { if (beforeObjects[i] === afterObjects[y]) { afterObjects.splice(y, 1) } } } editor.selection.select(afterObjects[0]) } const handleInsert = (editor, html) => { const beforeObjects = editor.dom.select('*[data-mce-object]') editor.insertContent(html) selectPlaceholder(editor, beforeObjects) editor.nodeChanged() } const submitForm = (prevData, newData, editor) => { newData.embed = updateHtml(newData.embed, newData, false, editor.schema) if ( newData.embed && (prevData.source === newData.source || isCached(newData.source)) ) { handleInsert(editor, newData.embed) } else { getEmbedHtml(editor, newData) .then(response => { handleInsert(editor, response.html) }) .catch(handleError(editor)) } } const showDialog = editor => { const editorData = getEditorData(editor) const currentData = Cell(editorData) const initialData = wrap(editorData) const handleSource = (prevData, api) => { const serviceData = unwrap(api.getData(), 'source') if (prevData.source !== serviceData.source) { addEmbedHtml( win, editor )({ url: serviceData.source, html: '' }) getEmbedHtml(editor, serviceData) .then(addEmbedHtml(win, editor)) .catch(handleError(editor)) } } const handleEmbed = api => { const data = unwrap(api.getData()) const dataFromEmbed = htmlToData(data.embed, editor.schema) api.setData(wrap(dataFromEmbed)) } const handleUpdate = (api, sourceInput) => { const data = unwrap(api.getData(), sourceInput) const embed = dataToHtml(editor, data) api.setData( wrap({ ...data, embed }) ) } const mediaInput = [ { name: 'source', type: 'urlinput', filetype: 'media', label: 'Source' } ] const sizeInput = !hasDimensions(editor) ? [] : [ { type: 'sizeinput', name: 'dimensions', label: 'Constrain proportions', constrain: true } ] const generalTab = { title: 'General', name: 'general', items: flatten([mediaInput, sizeInput]) } const embedTextarea = { type: 'textarea', name: 'embed', label: 'Paste your embed code below:' } const embedTab = { title: 'Embed', items: [embedTextarea] } const advancedFormItems = [] if (hasAltSource(editor)) { advancedFormItems.push({ name: 'altsource', type: 'urlinput', filetype: 'media', label: 'Alternative source URL' }) } if (hasPoster(editor)) { advancedFormItems.push({ name: 'poster', type: 'urlinput', filetype: 'image', label: 'Media poster (Image URL)' }) } const advancedTab = { title: 'Advanced', name: 'advanced', items: advancedFormItems } const tabs = [generalTab, embedTab] if (advancedFormItems.length > 0) { tabs.push(advancedTab) } const body = { type: 'tabpanel', tabs } const win = editor.windowManager.open({ title: 'Insert/Edit Media', size: 'normal', body, buttons: [ { type: 'cancel', name: 'cancel', text: 'Cancel' }, { type: 'submit', name: 'save', text: 'Save', primary: true } ], onSubmit: api => { const serviceData = unwrap(api.getData()) submitForm(currentData.get(), serviceData, editor) api.close() }, onChange: (api, detail) => { switch (detail.name) { case 'source': handleSource(currentData.get(), api) break case 'embed': handleEmbed(api) break case 'dimensions': case 'altsource': case 'poster': handleUpdate(api, detail.name) break } currentData.set(unwrap(api.getData())) }, initialData }) } const get = editor => { const showDialog$1 = () => { showDialog(editor) } return { showDialog: showDialog$1 } } const register$1 = editor => { const showDialog$1 = () => { showDialog(editor) } editor.addCommand('mceMedia', showDialog$1) } const checkRange = (str, substr, start) => substr === '' || (str.length >= substr.length && str.substr(start, start + substr.length) === substr) const startsWith = (str, prefix) => { return checkRange(str, prefix, 0) } var global = tinymce.util.Tools.resolve('tinymce.Env') const isLiveEmbedNode = node => { const name = node.name return name === 'iframe' || name === 'video' || name === 'audio' } const getDimension = (node, styles, dimension, defaultValue = null) => { const value = node.attr(dimension) if (isNonNullable(value)) { return value } else if (!has(styles, dimension)) { return defaultValue } else { return null } } const setDimensions = (node, previewNode, styles) => { const useDefaults = previewNode.name === 'img' || node.name === 'video' const defaultWidth = useDefaults ? '300' : null const fallbackHeight = node.name === 'audio' ? '30' : '150' const defaultHeight = useDefaults ? fallbackHeight : null previewNode.attr({ width: getDimension(node, styles, 'width', defaultWidth), height: getDimension(node, styles, 'height', defaultHeight) }) } const appendNodeContent = (editor, nodeName, previewNode, html) => { const newNode = Parser(editor.schema).parse(html, { context: nodeName }) while (newNode.firstChild) { previewNode.append(newNode.firstChild) } } const createPlaceholderNode = (editor, node) => { const name = node.name const placeHolder = new global$2('img', 1) retainAttributesAndInnerHtml(editor, node, placeHolder) setDimensions(node, placeHolder, {}) placeHolder.attr({ style: node.attr('style'), src: global.transparentSrc, 'data-mce-object': name, class: 'mce-object mce-object-' + name }) return placeHolder } const createPreviewNode = (editor, node) => { const name = node.name const previewWrapper = new global$2('span', 1) previewWrapper.attr({ contentEditable: 'false', style: node.attr('style'), 'data-mce-object': name, class: 'mce-preview-object mce-object-' + name }) retainAttributesAndInnerHtml(editor, node, previewWrapper) const styles = editor.dom.parseStyle(node.attr('style')) const previewNode = new global$2(name, 1) setDimensions(node, previewNode, styles) previewNode.attr({ src: node.attr('src'), style: node.attr('style'), class: node.attr('class') }) if (name === 'iframe') { previewNode.attr({ allowfullscreen: node.attr('allowfullscreen'), frameborder: '0' }) } else { const attrs = [ 'controls', 'crossorigin', 'currentTime', 'loop', 'muted', 'poster', 'preload' ] each$1(attrs, attrName => { previewNode.attr(attrName, node.attr(attrName)) }) const sanitizedHtml = previewWrapper.attr('data-mce-html') if (isNonNullable(sanitizedHtml)) { appendNodeContent(editor, name, previewNode, unescape(sanitizedHtml)) } } const shimNode = new global$2('span', 1) shimNode.attr('class', 'mce-shim') previewWrapper.append(previewNode) previewWrapper.append(shimNode) return previewWrapper } const retainAttributesAndInnerHtml = (editor, sourceNode, targetNode) => { const attribs = sourceNode.attributes let ai = attribs.length while (ai--) { const attrName = attribs[ai].name let attrValue = attribs[ai].value if ( attrName !== 'width' && attrName !== 'height' && attrName !== 'style' && !startsWith(attrName, 'data-mce-') ) { if (attrName === 'data' || attrName === 'src') { attrValue = editor.convertURL(attrValue, attrName) } targetNode.attr('data-mce-p-' + attrName, attrValue) } } const serializer = global$1({ inner: true }, editor.schema) const tempNode = new global$2('div', 1) each$1(sourceNode.children(), child => tempNode.append(child)) const innerHtml = serializer.serialize(tempNode) if (innerHtml) { targetNode.attr('data-mce-html', escape(innerHtml)) targetNode.empty() } } const isPageEmbedWrapper = node => { const nodeClass = node.attr('class') return nodeClass && /\btiny-pageembed\b/.test(nodeClass) } const isWithinEmbedWrapper = node => { while ((node = node.parent)) { if (node.attr('data-ephox-embed-iri') || isPageEmbedWrapper(node)) { return true } } return false } const placeHolderConverter = editor => nodes => { let i = nodes.length let node while (i--) { node = nodes[i] if (!node.parent) { continue } if (node.parent.attr('data-mce-object')) { continue } if (isLiveEmbedNode(node) && hasLiveEmbeds(editor)) { if (!isWithinEmbedWrapper(node)) { node.replace(createPreviewNode(editor, node)) } } else { if (!isWithinEmbedWrapper(node)) { node.replace(createPlaceholderNode(editor, node)) } } } } const parseAndSanitize = (editor, context, html) => { const validate = shouldFilterHtml(editor) return Parser(editor.schema, { validate }).parse(html, { context }) } const setup$1 = editor => { editor.on('PreInit', () => { const { schema, serializer, parser } = editor const boolAttrs = schema.getBoolAttrs() each$1('webkitallowfullscreen mozallowfullscreen'.split(' '), name => { boolAttrs[name] = {} }) each({ embed: ['wmode'] }, (attrs, name) => { const rule = schema.getElementRule(name) each$1(attrs, attr => { rule.attributes[attr] = {} rule.attributesOrder.push(attr) }) }) parser.addNodeFilter( 'iframe,video,audio,object,embed,script', placeHolderConverter(editor) ) serializer.addAttributeFilter('data-mce-object', (nodes, name) => { let i = nodes.length while (i--) { const node = nodes[i] if (!node.parent) { continue } const realElmName = node.attr(name) const realElm = new global$2(realElmName, 1) if (realElmName !== 'audio' && realElmName !== 'script') { const className = node.attr('class') if (className && className.indexOf('mce-preview-object') !== -1) { realElm.attr({ width: node.firstChild.attr('width'), height: node.firstChild.attr('height') }) } else { realElm.attr({ width: node.attr('width'), height: node.attr('height') }) } } realElm.attr({ style: node.attr('style') }) const attribs = node.attributes let ai = attribs.length while (ai--) { const attrName = attribs[ai].name if (attrName.indexOf('data-mce-p-') === 0) { realElm.attr(attrName.substr(11), attribs[ai].value) } } if (realElmName === 'script') { realElm.attr('type', 'text/javascript') } const innerHtml = node.attr('data-mce-html') if (innerHtml) { const fragment = parseAndSanitize( editor, realElmName, unescape(innerHtml) ) each$1(fragment.children(), child => realElm.append(child)) } node.replace(realElm) } }) }) editor.on('SetContent', () => { const dom = editor.dom each$1(dom.select('span.mce-preview-object'), elm => { if (dom.select('span.mce-shim', elm).length === 0) { dom.add(elm, 'span', { class: 'mce-shim' }) } }) }) } const setup = editor => { editor.on('ResolveName', e => { let name if ( e.target.nodeType === 1 && (name = e.target.getAttribute('data-mce-object')) ) { e.name = name } }) } const register = editor => { const onAction = () => editor.execCommand('mceMedia') editor.ui.registry.addToggleButton('media', { tooltip: 'Insert/edit media', icon: 'embed', onAction, onSetup: buttonApi => { const selection = editor.selection buttonApi.setActive(isMediaElement(selection.getNode())) return selection.selectorChangedWithUnbind( 'img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]', buttonApi.setActive ).unbind } }) editor.ui.registry.addMenuItem('media', { icon: 'embed', text: 'Media...', onAction }) } var Plugin = () => { global$6.add('media', editor => { register$2(editor) register$1(editor) register(editor) setup(editor) setup$1(editor) setup$2(editor) return get(editor) }) } Plugin() })()