Be(e,"*:not(.tox-silver-sink)")))),c=$e(n);E(l,r("display:none!important;")),E(o,r(_e+je+c)),r((!0===ze?"":_e)+je+c)(t)})(e.dom,l,d),p.width=p.height="100%",g.width=g.height="",f(Ue.addClass),Ke.bind(l),e.on("remove",v),t.set(r),qe(e)&&(e=>{const t=e.dom;t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.webkitRequestFullScreen&&t.webkitRequestFullScreen()})(c),We(e,!0)}var y},Ye=(e,t)=>n=>{n.setActive(null!==t.get());const r=e=>n.setActive(e.state);return e.on("FullscreenStateChanged",r),()=>e.off("FullscreenStateChanged",r)};t.add("fullscreen",(t=>{const n=e(null);return t.inline||((e=>{(0,e.options.register)("fullscreen_native",{processor:"boolean",default:!1})})(t),((e,t)=>{e.addCommand("mceFullScreen",(()=>{Xe(e,t)}))})(t,n),((e,t)=>{const n=()=>e.execCommand("mceFullScreen");e.ui.registry.addToggleMenuItem("fullscreen",{text:"Fullscreen",icon:"fullscreen",shortcut:"Meta+Shift+F",onAction:n,onSetup:Ye(e,t)}),e.ui.registry.addToggleButton("fullscreen",{tooltip:"Fullscreen",icon:"fullscreen",onAction:n,onSetup:Ye(e,t)})})(t,n),t.addShortcut("Meta+Shift+F","","mceFullScreen")),(e=>({isFullscreen:()=>null!==e.get()}))(n)}))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/help/plugin.js b/lib/editor/tiny/js/tinymce/plugins/help/plugin.js
new file mode 100644
index 00000000000..9b6bdbf4b00
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/help/plugin.js
@@ -0,0 +1,918 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ const Cell = initial => {
+ let value = initial;
+ const get = () => {
+ return value;
+ };
+ const set = v => {
+ value = v;
+ };
+ return {
+ get,
+ set
+ };
+ };
+
+ var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ let unique = 0;
+ const generate = prefix => {
+ const date = new Date();
+ const time = date.getTime();
+ const random = Math.floor(Math.random() * 1000000000);
+ unique++;
+ return prefix + '_' + random + unique + String(time);
+ };
+
+ const get$1 = customTabs => {
+ const addTab = spec => {
+ const name = spec.name ?? generate('tab-name');
+ const currentCustomTabs = customTabs.get();
+ currentCustomTabs[name] = spec;
+ customTabs.set(currentCustomTabs);
+ };
+ return { addTab };
+ };
+
+ const register$2 = (editor, dialogOpener) => {
+ editor.addCommand('mceHelp', dialogOpener);
+ };
+
+ const option = name => editor => editor.options.get(name);
+ const register$1 = editor => {
+ const registerOption = editor.options.register;
+ registerOption('help_tabs', { processor: 'array' });
+ };
+ const getHelpTabs = option('help_tabs');
+ const getForcedPlugins = option('forced_plugins');
+
+ const register = (editor, dialogOpener) => {
+ editor.ui.registry.addButton('help', {
+ icon: 'help',
+ tooltip: 'Help',
+ onAction: dialogOpener
+ });
+ editor.ui.registry.addMenuItem('help', {
+ text: 'Help',
+ icon: 'help',
+ shortcut: 'Alt+0',
+ onAction: dialogOpener
+ });
+ };
+
+ const hasProto = (v, constructor, predicate) => {
+ if (predicate(v, constructor.prototype)) {
+ return true;
+ } else {
+ return v.constructor?.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 isSimpleType = type => value => typeof value === type;
+ const eq = t => a => t === a;
+ const isString = isType('string');
+ const isUndefined = eq(undefined);
+ const isNullable = a => a === null || a === undefined;
+ const isNonNullable = a => !isNullable(a);
+ const isFunction = isSimpleType('function');
+
+ const constant = value => {
+ return () => {
+ return value;
+ };
+ };
+ const never = constant(false);
+
+ 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 ?? '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 nativeSlice = Array.prototype.slice;
+ const nativeIndexOf = Array.prototype.indexOf;
+ const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
+ const contains = (xs, x) => rawIndexOf(xs, x) > -1;
+ const map = (xs, f) => {
+ const len = xs.length;
+ const r = new Array(len);
+ for (let i = 0; i < len; i++) {
+ const x = xs[i];
+ r[i] = f(x, i);
+ }
+ return r;
+ };
+ const filter = (xs, pred) => {
+ const r = [];
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ if (pred(x, i)) {
+ r.push(x);
+ }
+ }
+ return r;
+ };
+ const findUntil = (xs, pred, until) => {
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ if (pred(x, i)) {
+ return Optional.some(x);
+ } else if (until(x, i)) {
+ break;
+ }
+ }
+ return Optional.none();
+ };
+ const find = (xs, pred) => {
+ return findUntil(xs, pred, never);
+ };
+ const sort = (xs, comparator) => {
+ const copy = nativeSlice.call(xs, 0);
+ copy.sort(comparator);
+ return copy;
+ };
+
+ const keys = Object.keys;
+ const hasOwnProperty = Object.hasOwnProperty;
+ const get = (obj, key) => {
+ return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
+ };
+ const has = (obj, key) => hasOwnProperty.call(obj, key);
+
+ const cat = arr => {
+ const r = [];
+ const push = x => {
+ r.push(x);
+ };
+ for (let i = 0; i < arr.length; i++) {
+ arr[i].each(push);
+ }
+ return r;
+ };
+
+ const description = `Editor UI keyboard navigation
+
+Activating keyboard navigation
+
+The sections of the outer UI of the editor - the menubar, toolbar, sidebar and footer - are all keyboard navigable. As such, there are multiple ways to activate keyboard navigation:
+
+ Focus the menubar: Alt + F9 (Windows) or ⌥F9 (MacOS)
+ Focus the toolbar: Alt + F10 (Windows) or ⌥F10 (MacOS)
+ Focus the footer: Alt + F11 (Windows) or ⌥F11 (MacOS)
+
+
+Focusing the menubar or toolbar will start keyboard navigation at the first item in the menubar or toolbar, which will be highlighted with a gray background. Focusing the footer will start keyboard navigation at the first item in the element path, which will be highlighted with an underline.
+
+Moving between UI sections
+
+When keyboard navigation is active, pressing tab will move the focus to the next major section of the UI, where applicable. These sections are:
+
+ the menubar
+ each group of the toolbar
+ the sidebar
+ the element path in the footer
+ the wordcount toggle button in the footer
+ the branding link in the footer
+ the editor resize handle in the footer
+
+
+Pressing shift + tab will move backwards through the same sections, except when moving from the footer to the toolbar. Focusing the element path then pressing shift + tab will move focus to the first toolbar group, not the last.
+
+Moving within UI sections
+
+Keyboard navigation within UI sections can usually be achieved using the left and right arrow keys. This includes:
+
+ moving between menus in the menubar
+ moving between buttons in a toolbar group
+ moving between items in the element path
+
+
+In all these UI sections, keyboard navigation will cycle within the section. For example, focusing the last button in a toolbar group then pressing right arrow will move focus to the first item in the same toolbar group.
+
+Executing buttons
+
+To execute a button, navigate the selection to the desired button and hit space or enter.
+
+Opening, navigating and closing menus
+
+When focusing a menubar button or a toolbar button with a menu, pressing space, enter or down arrow will open the menu. When the menu opens the first item will be selected. To move up or down the menu, press the up or down arrow key respectively. This is the same for submenus, which can also be opened and closed using the left and right arrow keys.
+
+To close any active menu, hit the escape key. When a menu is closed the selection will be restored to its previous selection. This also works for closing submenus.
+
+Context toolbars and menus
+
+To focus an open context toolbar such as the table context toolbar, press Ctrl + F9 (Windows) or ⌃F9 (MacOS).
+
+Context toolbar navigation is the same as toolbar navigation, and context menu navigation is the same as standard menu navigation.
+
+Dialog navigation
+
+There are two types of dialog UIs in TinyMCE: tabbed dialogs and non-tabbed dialogs.
+
+When a non-tabbed dialog is opened, the first interactive component in the dialog will be focused. Users can navigate between interactive components by pressing tab. This includes any footer buttons. Navigation will cycle back to the first dialog component if tab is pressed while focusing the last component in the dialog. Pressing shift + tab will navigate backwards.
+
+When a tabbed dialog is opened, the first button in the tab menu is focused. Pressing tab will navigate to the first interactive component in that tab, and will cycle through the tab\u2019s components, the footer buttons, then back to the tab button. To switch to another tab, focus the tab button for the current tab, then use the arrow keys to cycle through the tab buttons.
`;
+ const tab$3 = () => {
+ const body = {
+ type: 'htmlpanel',
+ presets: 'document',
+ html: description
+ };
+ return {
+ name: 'keyboardnav',
+ title: 'Keyboard Navigation',
+ items: [body]
+ };
+ };
+
+ var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
+
+ const convertText = source => {
+ const isMac = global$2.os.isMacOS() || global$2.os.isiOS();
+ const mac = {
+ alt: '⌥',
+ ctrl: '⌃',
+ shift: '⇧',
+ meta: '⌘',
+ access: '⌃⌥'
+ };
+ const other = {
+ meta: 'Ctrl ',
+ access: 'Shift + Alt '
+ };
+ const replace = isMac ? mac : other;
+ const shortcut = source.split('+');
+ const updated = map(shortcut, segment => {
+ const search = segment.toLowerCase().trim();
+ return has(replace, search) ? replace[search] : segment;
+ });
+ return isMac ? updated.join('').replace(/\s/, '') : updated.join('+');
+ };
+
+ const shortcuts = [
+ {
+ shortcuts: ['Meta + B'],
+ action: 'Bold'
+ },
+ {
+ shortcuts: ['Meta + I'],
+ action: 'Italic'
+ },
+ {
+ shortcuts: ['Meta + U'],
+ action: 'Underline'
+ },
+ {
+ shortcuts: ['Meta + A'],
+ action: 'Select all'
+ },
+ {
+ shortcuts: [
+ 'Meta + Y',
+ 'Meta + Shift + Z'
+ ],
+ action: 'Redo'
+ },
+ {
+ shortcuts: ['Meta + Z'],
+ action: 'Undo'
+ },
+ {
+ shortcuts: ['Access + 1'],
+ action: 'Heading 1'
+ },
+ {
+ shortcuts: ['Access + 2'],
+ action: 'Heading 2'
+ },
+ {
+ shortcuts: ['Access + 3'],
+ action: 'Heading 3'
+ },
+ {
+ shortcuts: ['Access + 4'],
+ action: 'Heading 4'
+ },
+ {
+ shortcuts: ['Access + 5'],
+ action: 'Heading 5'
+ },
+ {
+ shortcuts: ['Access + 6'],
+ action: 'Heading 6'
+ },
+ {
+ shortcuts: ['Access + 7'],
+ action: 'Paragraph'
+ },
+ {
+ shortcuts: ['Access + 8'],
+ action: 'Div'
+ },
+ {
+ shortcuts: ['Access + 9'],
+ action: 'Address'
+ },
+ {
+ shortcuts: ['Alt + 0'],
+ action: 'Open help dialog'
+ },
+ {
+ shortcuts: ['Alt + F9'],
+ action: 'Focus to menubar'
+ },
+ {
+ shortcuts: ['Alt + F10'],
+ action: 'Focus to toolbar'
+ },
+ {
+ shortcuts: ['Alt + F11'],
+ action: 'Focus to element path'
+ },
+ {
+ shortcuts: ['Ctrl + F9'],
+ action: 'Focus to contextual toolbar'
+ },
+ {
+ shortcuts: ['Shift + Enter'],
+ action: 'Open popup menu for split buttons'
+ },
+ {
+ shortcuts: ['Meta + K'],
+ action: 'Insert link (if link plugin activated)'
+ },
+ {
+ shortcuts: ['Meta + S'],
+ action: 'Save (if save plugin activated)'
+ },
+ {
+ shortcuts: ['Meta + F'],
+ action: 'Find (if searchreplace plugin activated)'
+ },
+ {
+ shortcuts: ['Meta + Shift + F'],
+ action: 'Switch to or from fullscreen mode'
+ }
+ ];
+
+ const tab$2 = () => {
+ const shortcutList = map(shortcuts, shortcut => {
+ const shortcutText = map(shortcut.shortcuts, convertText).join(' or ');
+ return [
+ shortcut.action,
+ shortcutText
+ ];
+ });
+ const tablePanel = {
+ type: 'table',
+ header: [
+ 'Action',
+ 'Shortcut'
+ ],
+ cells: shortcutList
+ };
+ return {
+ name: 'shortcuts',
+ title: 'Handy Shortcuts',
+ items: [tablePanel]
+ };
+ };
+
+ var global$1 = tinymce.util.Tools.resolve('tinymce.util.I18n');
+
+ const urls = map([
+ {
+ key: 'advlist',
+ name: 'Advanced List'
+ },
+ {
+ key: 'anchor',
+ name: 'Anchor'
+ },
+ {
+ key: 'autolink',
+ name: 'Autolink'
+ },
+ {
+ key: 'autoresize',
+ name: 'Autoresize'
+ },
+ {
+ key: 'autosave',
+ name: 'Autosave'
+ },
+ {
+ key: 'charmap',
+ name: 'Character Map'
+ },
+ {
+ key: 'code',
+ name: 'Code'
+ },
+ {
+ key: 'codesample',
+ name: 'Code Sample'
+ },
+ {
+ key: 'colorpicker',
+ name: 'Color Picker'
+ },
+ {
+ key: 'directionality',
+ name: 'Directionality'
+ },
+ {
+ key: 'emoticons',
+ name: 'Emoticons'
+ },
+ {
+ key: 'fullscreen',
+ name: 'Full Screen'
+ },
+ {
+ key: 'help',
+ name: 'Help'
+ },
+ {
+ key: 'image',
+ name: 'Image'
+ },
+ {
+ key: 'importcss',
+ name: 'Import CSS'
+ },
+ {
+ key: 'insertdatetime',
+ name: 'Insert Date/Time'
+ },
+ {
+ key: 'link',
+ name: 'Link'
+ },
+ {
+ key: 'lists',
+ name: 'Lists'
+ },
+ {
+ key: 'media',
+ name: 'Media'
+ },
+ {
+ key: 'nonbreaking',
+ name: 'Nonbreaking'
+ },
+ {
+ key: 'pagebreak',
+ name: 'Page Break'
+ },
+ {
+ key: 'preview',
+ name: 'Preview'
+ },
+ {
+ key: 'quickbars',
+ name: 'Quick Toolbars'
+ },
+ {
+ key: 'save',
+ name: 'Save'
+ },
+ {
+ key: 'searchreplace',
+ name: 'Search and Replace'
+ },
+ {
+ key: 'table',
+ name: 'Table'
+ },
+ {
+ key: 'template',
+ name: 'Template'
+ },
+ {
+ key: 'textcolor',
+ name: 'Text Color'
+ },
+ {
+ key: 'visualblocks',
+ name: 'Visual Blocks'
+ },
+ {
+ key: 'visualchars',
+ name: 'Visual Characters'
+ },
+ {
+ key: 'wordcount',
+ name: 'Word Count'
+ },
+ {
+ key: 'a11ychecker',
+ name: 'Accessibility Checker',
+ type: 'premium'
+ },
+ {
+ key: 'advcode',
+ name: 'Advanced Code Editor',
+ type: 'premium'
+ },
+ {
+ key: 'advtable',
+ name: 'Advanced Tables',
+ type: 'premium'
+ },
+ {
+ key: 'casechange',
+ name: 'Case Change',
+ type: 'premium'
+ },
+ {
+ key: 'checklist',
+ name: 'Checklist',
+ type: 'premium'
+ },
+ {
+ key: 'editimage',
+ name: 'Enhanced Image Editing',
+ type: 'premium'
+ },
+ {
+ key: 'footnotes',
+ name: 'Footnotes',
+ type: 'premium'
+ },
+ {
+ key: 'mediaembed',
+ name: 'Enhanced Media Embed',
+ type: 'premium',
+ slug: 'introduction-to-mediaembed'
+ },
+ {
+ key: 'export',
+ name: 'Export',
+ type: 'premium'
+ },
+ {
+ key: 'formatpainter',
+ name: 'Format Painter',
+ type: 'premium'
+ },
+ {
+ key: 'linkchecker',
+ name: 'Link Checker',
+ type: 'premium'
+ },
+ {
+ key: 'mentions',
+ name: 'Mentions',
+ type: 'premium'
+ },
+ {
+ key: 'mergetags',
+ name: 'Merge Tags',
+ type: 'premium'
+ },
+ {
+ key: 'pageembed',
+ name: 'Page Embed',
+ type: 'premium'
+ },
+ {
+ key: 'permanentpen',
+ name: 'Permanent Pen',
+ type: 'premium'
+ },
+ {
+ key: 'powerpaste',
+ name: 'PowerPaste',
+ type: 'premium',
+ slug: 'introduction-to-powerpaste'
+ },
+ {
+ key: 'rtc',
+ name: 'Real-Time Collaboration',
+ type: 'premium',
+ slug: 'rtc-introduction'
+ },
+ {
+ key: 'tinymcespellchecker',
+ name: 'Spell Checker Pro',
+ type: 'premium',
+ slug: 'introduction-to-tiny-spellchecker'
+ },
+ {
+ key: 'autocorrect',
+ name: 'Spelling Autocorrect',
+ type: 'premium'
+ },
+ {
+ key: 'tinycomments',
+ name: 'Tiny Comments',
+ type: 'premium',
+ slug: 'introduction-to-tiny-comments'
+ },
+ {
+ key: 'tinydrive',
+ name: 'Tiny Drive',
+ type: 'premium',
+ slug: 'tinydrive-introduction'
+ },
+ {
+ key: 'tableofcontents',
+ name: 'Table of Contents',
+ type: 'premium'
+ }
+ ], item => ({
+ ...item,
+ type: item.type || 'opensource',
+ slug: item.slug || item.key
+ }));
+
+ const tab$1 = editor => {
+ const availablePlugins = () => {
+ const premiumPlugins = filter(urls, ({type}) => {
+ return type === 'premium';
+ });
+ const sortedPremiumPlugins = sort(map(premiumPlugins, p => p.name), (s1, s2) => s1.localeCompare(s2));
+ const premiumPluginList = map(sortedPremiumPlugins, pluginName => `${ pluginName } `).join('');
+ return '' + '
' + global$1.translate('Premium plugins:') + '
' + '
' + '
';
+ };
+ const makeLink = p => `${ p.name } `;
+ const identifyUnknownPlugin = (editor, key) => {
+ const getMetadata = editor.plugins[key].getMetadata;
+ if (isFunction(getMetadata)) {
+ const metadata = getMetadata();
+ return {
+ name: metadata.name,
+ html: makeLink(metadata)
+ };
+ } else {
+ return {
+ name: key,
+ html: key
+ };
+ }
+ };
+ const getPluginData = (editor, key) => find(urls, x => {
+ return x.key === key;
+ }).fold(() => {
+ return identifyUnknownPlugin(editor, key);
+ }, x => {
+ const name = x.type === 'premium' ? `${ x.name }*` : x.name;
+ const html = makeLink({
+ name,
+ url: `https://www.tiny.cloud/docs/tinymce/6/${ x.slug }/`
+ });
+ return {
+ name,
+ html
+ };
+ });
+ const getPluginKeys = editor => {
+ const keys$1 = keys(editor.plugins);
+ const forcedPlugins = getForcedPlugins(editor);
+ return isUndefined(forcedPlugins) ? keys$1 : filter(keys$1, k => !contains(forcedPlugins, k));
+ };
+ const pluginLister = editor => {
+ const pluginKeys = getPluginKeys(editor);
+ const sortedPluginData = sort(map(pluginKeys, k => getPluginData(editor, k)), (pd1, pd2) => pd1.name.localeCompare(pd2.name));
+ const pluginLis = map(sortedPluginData, key => {
+ return '' + key.html + ' ';
+ });
+ const count = pluginLis.length;
+ const pluginsString = pluginLis.join('');
+ const html = '' + global$1.translate([
+ 'Plugins installed ({0}):',
+ count
+ ]) + '
' + '';
+ return html;
+ };
+ const installedPlugins = editor => {
+ if (editor == null) {
+ return '';
+ }
+ return '' + pluginLister(editor) + '
';
+ };
+ const htmlPanel = {
+ type: 'htmlpanel',
+ presets: 'document',
+ html: [
+ installedPlugins(editor),
+ availablePlugins()
+ ].join('')
+ };
+ return {
+ name: 'plugins',
+ title: 'Plugins',
+ items: [htmlPanel]
+ };
+ };
+
+ var global = tinymce.util.Tools.resolve('tinymce.EditorManager');
+
+ const tab = () => {
+ const getVersion = (major, minor) => major.indexOf('@') === 0 ? 'X.X.X' : major + '.' + minor;
+ const version = getVersion(global.majorVersion, global.minorVersion);
+ const changeLogLink = 'TinyMCE ' + version + ' ';
+ const htmlPanel = {
+ type: 'htmlpanel',
+ html: '' + global$1.translate([
+ 'You are using {0}',
+ changeLogLink
+ ]) + '
',
+ presets: 'document'
+ };
+ return {
+ name: 'versions',
+ title: 'Version',
+ items: [htmlPanel]
+ };
+ };
+
+ const parseHelpTabsSetting = (tabsFromSettings, tabs) => {
+ const newTabs = {};
+ const names = map(tabsFromSettings, t => {
+ if (isString(t)) {
+ if (has(tabs, t)) {
+ newTabs[t] = tabs[t];
+ }
+ return t;
+ } else {
+ const name = t.name ?? generate('tab-name');
+ newTabs[name] = t;
+ return name;
+ }
+ });
+ return {
+ tabs: newTabs,
+ names
+ };
+ };
+ const getNamesFromTabs = tabs => {
+ const names = keys(tabs);
+ const idx = names.indexOf('versions');
+ if (idx !== -1) {
+ names.splice(idx, 1);
+ names.push('versions');
+ }
+ return {
+ tabs,
+ names
+ };
+ };
+ const parseCustomTabs = (editor, customTabs) => {
+ const shortcuts = tab$2();
+ const nav = tab$3();
+ const plugins = tab$1(editor);
+ const versions = tab();
+ const tabs = {
+ [shortcuts.name]: shortcuts,
+ [nav.name]: nav,
+ [plugins.name]: plugins,
+ [versions.name]: versions,
+ ...customTabs.get()
+ };
+ return Optional.from(getHelpTabs(editor)).fold(() => getNamesFromTabs(tabs), tabsFromSettings => parseHelpTabsSetting(tabsFromSettings, tabs));
+ };
+ const init = (editor, customTabs) => () => {
+ const {tabs, names} = parseCustomTabs(editor, customTabs);
+ const foundTabs = map(names, name => get(tabs, name));
+ const dialogTabs = cat(foundTabs);
+ const body = {
+ type: 'tabpanel',
+ tabs: dialogTabs
+ };
+ editor.windowManager.open({
+ title: 'Help',
+ size: 'medium',
+ body,
+ buttons: [{
+ type: 'cancel',
+ name: 'close',
+ text: 'Close',
+ primary: true
+ }],
+ initialData: {}
+ });
+ };
+
+ var Plugin = () => {
+ global$3.add('help', editor => {
+ const customTabs = Cell({});
+ const api = get$1(customTabs);
+ register$1(editor);
+ const dialogOpener = init(editor, customTabs);
+ register(editor, dialogOpener);
+ register$2(editor, dialogOpener);
+ editor.shortcuts.add('Alt+0', 'Open help dialog', 'mceHelp');
+ return api;
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/help/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/help/plugin.min.js
new file mode 100644
index 00000000000..ed7b2b2c288
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/help/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const n=e=>{const n=(new Date).getTime(),o=Math.floor(1e9*Math.random());return t++,e+"_"+o+t+String(n)},o=e=>t=>t.options.get(e),a=o("help_tabs"),i=o("forced_plugins"),r=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(a=String).prototype.isPrototypeOf(n)||o.constructor?.name===a.name)?"string":t;var n,o,a})(e));const s=(void 0,e=>undefined===e);const l=e=>"function"==typeof e,c=(!1,()=>false);class u{constructor(e,t){this.tag=e,this.value=t}static some(e){return new u(!0,e)}static none(){return u.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?u.some(e(this.value)):u.none()}bind(e){return this.tag?e(this.value):u.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:u.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(e??"Called getOrDie on None")}static from(e){return null==e?u.none():u.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}u.singletonNone=new u(!1);const m=Array.prototype.slice,h=Array.prototype.indexOf,p=(e,t)=>{const n=e.length,o=new Array(n);for(let a=0;a{const n=[];for(let o=0,a=e.length;o{const n=m.call(e,0);return n.sort(t),n},y=Object.keys,b=Object.hasOwnProperty,k=(e,t)=>b.call(e,t);var v=tinymce.util.Tools.resolve("tinymce.Env");const f=e=>{const t=v.os.isMacOS()||v.os.isiOS(),n=t?{alt:"⌥",ctrl:"⌃",shift:"⇧",meta:"⌘",access:"⌃⌥"}:{meta:"Ctrl ",access:"Shift + Alt "},o=e.split("+"),a=p(o,(e=>{const t=e.toLowerCase().trim();return k(n,t)?n[t]:e}));return t?a.join("").replace(/\s/,""):a.join("+")},w=[{shortcuts:["Meta + B"],action:"Bold"},{shortcuts:["Meta + I"],action:"Italic"},{shortcuts:["Meta + U"],action:"Underline"},{shortcuts:["Meta + A"],action:"Select all"},{shortcuts:["Meta + Y","Meta + Shift + Z"],action:"Redo"},{shortcuts:["Meta + Z"],action:"Undo"},{shortcuts:["Access + 1"],action:"Heading 1"},{shortcuts:["Access + 2"],action:"Heading 2"},{shortcuts:["Access + 3"],action:"Heading 3"},{shortcuts:["Access + 4"],action:"Heading 4"},{shortcuts:["Access + 5"],action:"Heading 5"},{shortcuts:["Access + 6"],action:"Heading 6"},{shortcuts:["Access + 7"],action:"Paragraph"},{shortcuts:["Access + 8"],action:"Div"},{shortcuts:["Access + 9"],action:"Address"},{shortcuts:["Alt + 0"],action:"Open help dialog"},{shortcuts:["Alt + F9"],action:"Focus to menubar"},{shortcuts:["Alt + F10"],action:"Focus to toolbar"},{shortcuts:["Alt + F11"],action:"Focus to element path"},{shortcuts:["Ctrl + F9"],action:"Focus to contextual toolbar"},{shortcuts:["Shift + Enter"],action:"Open popup menu for split buttons"},{shortcuts:["Meta + K"],action:"Insert link (if link plugin activated)"},{shortcuts:["Meta + S"],action:"Save (if save plugin activated)"},{shortcuts:["Meta + F"],action:"Find (if searchreplace plugin activated)"},{shortcuts:["Meta + Shift + F"],action:"Switch to or from fullscreen mode"}],A=()=>({name:"shortcuts",title:"Handy Shortcuts",items:[{type:"table",header:["Action","Shortcut"],cells:p(w,(e=>{const t=p(e.shortcuts,f).join(" or ");return[e.action,t]}))}]});var x=tinymce.util.Tools.resolve("tinymce.util.I18n");const T=p([{key:"advlist",name:"Advanced List"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"image",name:"Image"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"pagebreak",name:"Page Break"},{key:"preview",name:"Preview"},{key:"quickbars",name:"Quick Toolbars"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"table",name:"Table"},{key:"template",name:"Template"},{key:"textcolor",name:"Text Color"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"},{key:"a11ychecker",name:"Accessibility Checker",type:"premium"},{key:"advcode",name:"Advanced Code Editor",type:"premium"},{key:"advtable",name:"Advanced Tables",type:"premium"},{key:"casechange",name:"Case Change",type:"premium"},{key:"checklist",name:"Checklist",type:"premium"},{key:"editimage",name:"Enhanced Image Editing",type:"premium"},{key:"footnotes",name:"Footnotes",type:"premium"},{key:"mediaembed",name:"Enhanced Media Embed",type:"premium",slug:"introduction-to-mediaembed"},{key:"export",name:"Export",type:"premium"},{key:"formatpainter",name:"Format Painter",type:"premium"},{key:"linkchecker",name:"Link Checker",type:"premium"},{key:"mentions",name:"Mentions",type:"premium"},{key:"mergetags",name:"Merge Tags",type:"premium"},{key:"pageembed",name:"Page Embed",type:"premium"},{key:"permanentpen",name:"Permanent Pen",type:"premium"},{key:"powerpaste",name:"PowerPaste",type:"premium",slug:"introduction-to-powerpaste"},{key:"rtc",name:"Real-Time Collaboration",type:"premium",slug:"rtc-introduction"},{key:"tinymcespellchecker",name:"Spell Checker Pro",type:"premium",slug:"introduction-to-tiny-spellchecker"},{key:"autocorrect",name:"Spelling Autocorrect",type:"premium"},{key:"tinycomments",name:"Tiny Comments",type:"premium",slug:"introduction-to-tiny-comments"},{key:"tinydrive",name:"Tiny Drive",type:"premium",slug:"tinydrive-introduction"},{key:"tableofcontents",name:"Table of Contents",type:"premium"}],(e=>({...e,type:e.type||"opensource",slug:e.slug||e.key}))),M=e=>{const t=e=>` ${e.name} `,n=(e,n)=>{return(o=T,a=e=>e.key===n,((e,t,n)=>{for(let o=0,a=e.length;o((e,n)=>{const o=e.plugins[n].getMetadata;if(l(o)){const e=o();return{name:e.name,html:t(e)}}return{name:n,html:n}})(e,n)),(e=>{const n="premium"===e.type?`${e.name}*`:e.name;return{name:n,html:t({name:n,url:`https://www.tiny.cloud/docs/tinymce/6/${e.slug}/`})}}));var o,a},o=e=>{const t=(e=>{const t=y(e.plugins),n=i(e);return s(n)?t:d(t,(e=>!(((e,t)=>h.call(e,t))(n,e)>-1)))})(e),o=g(p(t,(t=>n(e,t))),((e,t)=>e.name.localeCompare(t.name))),a=p(o,(e=>""+e.html+" ")),r=a.length,l=a.join("");return""+x.translate(["Plugins installed ({0}):",r])+"
"},a={type:"htmlpanel",presets:"document",html:[(e=>null==e?"":''+o(e)+"
")(e),(()=>{const e=d(T,(({type:e})=>"premium"===e)),t=g(p(e,(e=>e.name)),((e,t)=>e.localeCompare(t))),n=p(t,(e=>`${e} `)).join("");return''+x.translate("Premium plugins:")+"
"})()].join("")};return{name:"plugins",title:"Plugins",items:[a]}};var C=tinymce.util.Tools.resolve("tinymce.EditorManager");const F=(e,t)=>()=>{const{tabs:o,names:i}=((e,t)=>{const o=A(),i={name:"keyboardnav",title:"Keyboard Navigation",items:[{type:"htmlpanel",presets:"document",html:"Editor UI keyboard navigation \n\nActivating keyboard navigation \n\nThe sections of the outer UI of the editor - the menubar, toolbar, sidebar and footer - are all keyboard navigable. As such, there are multiple ways to activate keyboard navigation:
\n\n Focus the menubar: Alt + F9 (Windows) or ⌥F9 (MacOS) \n Focus the toolbar: Alt + F10 (Windows) or ⌥F10 (MacOS) \n Focus the footer: Alt + F11 (Windows) or ⌥F11 (MacOS) \n \n\nFocusing the menubar or toolbar will start keyboard navigation at the first item in the menubar or toolbar, which will be highlighted with a gray background. Focusing the footer will start keyboard navigation at the first item in the element path, which will be highlighted with an underline.
\n\nMoving between UI sections \n\nWhen keyboard navigation is active, pressing tab will move the focus to the next major section of the UI, where applicable. These sections are:
\n\n the menubar \n each group of the toolbar \n the sidebar \n the element path in the footer \n the wordcount toggle button in the footer \n the branding link in the footer \n the editor resize handle in the footer \n \n\nPressing shift + tab will move backwards through the same sections, except when moving from the footer to the toolbar. Focusing the element path then pressing shift + tab will move focus to the first toolbar group, not the last.
\n\nMoving within UI sections \n\nKeyboard navigation within UI sections can usually be achieved using the left and right arrow keys. This includes:
\n\n moving between menus in the menubar \n moving between buttons in a toolbar group \n moving between items in the element path \n \n\nIn all these UI sections, keyboard navigation will cycle within the section. For example, focusing the last button in a toolbar group then pressing right arrow will move focus to the first item in the same toolbar group.
\n\nExecuting buttons \n\nTo execute a button, navigate the selection to the desired button and hit space or enter.
\n\nOpening, navigating and closing menus \n\nWhen focusing a menubar button or a toolbar button with a menu, pressing space, enter or down arrow will open the menu. When the menu opens the first item will be selected. To move up or down the menu, press the up or down arrow key respectively. This is the same for submenus, which can also be opened and closed using the left and right arrow keys.
\n\nTo close any active menu, hit the escape key. When a menu is closed the selection will be restored to its previous selection. This also works for closing submenus.
\n\nContext toolbars and menus \n\nTo focus an open context toolbar such as the table context toolbar, press Ctrl + F9 (Windows) or ⌃F9 (MacOS).
\n\nContext toolbar navigation is the same as toolbar navigation, and context menu navigation is the same as standard menu navigation.
\n\nDialog navigation \n\nThere are two types of dialog UIs in TinyMCE: tabbed dialogs and non-tabbed dialogs.
\n\nWhen a non-tabbed dialog is opened, the first interactive component in the dialog will be focused. Users can navigate between interactive components by pressing tab. This includes any footer buttons. Navigation will cycle back to the first dialog component if tab is pressed while focusing the last component in the dialog. Pressing shift + tab will navigate backwards.
\n\nWhen a tabbed dialog is opened, the first button in the tab menu is focused. Pressing tab will navigate to the first interactive component in that tab, and will cycle through the tab\u2019s components, the footer buttons, then back to the tab button. To switch to another tab, focus the tab button for the current tab, then use the arrow keys to cycle through the tab buttons.
"}]},s=M(e),l=(()=>{var e,t;const n=' TinyMCE '+(e=C.majorVersion,t=C.minorVersion,(0===e.indexOf("@")?"X.X.X":e+"."+t)+" ");return{name:"versions",title:"Version",items:[{type:"htmlpanel",html:""+x.translate(["You are using {0}",n])+"
",presets:"document"}]}})(),c={[o.name]:o,[i.name]:i,[s.name]:s,[l.name]:l,...t.get()};return u.from(a(e)).fold((()=>(e=>{const t=y(e),n=t.indexOf("versions");return-1!==n&&(t.splice(n,1),t.push("versions")),{tabs:e,names:t}})(c)),(e=>((e,t)=>{const o={},a=p(e,(e=>{if(r(e))return k(t,e)&&(o[e]=t[e]),e;{const t=e.name??n("tab-name");return o[t]=e,t}}));return{tabs:o,names:a}})(e,c)))})(e,t),s={type:"tabpanel",tabs:(e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t{return k(t=o,n=e)?u.from(t[n]):u.none();var t,n})))};e.windowManager.open({title:"Help",size:"medium",body:s,buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{}})};e.add("help",(e=>{const t=(e=>{let t={};return{get:()=>t,set:e=>{t=e}}})(),o=(e=>({addTab:t=>{const o=t.name??n("tab-name"),a=e.get();a[o]=t,e.set(a)}}))(t);(e=>{(0,e.options.register)("help_tabs",{processor:"array"})})(e);const a=F(e,t);return((e,t)=>{e.ui.registry.addButton("help",{icon:"help",tooltip:"Help",onAction:t}),e.ui.registry.addMenuItem("help",{text:"Help",icon:"help",shortcut:"Alt+0",onAction:t})})(e,a),((e,t)=>{e.addCommand("mceHelp",t)})(e,a),e.shortcuts.add("Alt+0","Open help dialog","mceHelp"),o}))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/image/plugin.js b/lib/editor/tiny/js/tinymce/plugins/image/plugin.js
new file mode 100644
index 00000000000..ca5e00de376
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/image/plugin.js
@@ -0,0 +1,1476 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ const getPrototypeOf = Object.getPrototypeOf;
+ const hasProto = (v, constructor, predicate) => {
+ if (predicate(v, constructor.prototype)) {
+ return true;
+ } else {
+ return v.constructor?.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 isSimpleType = type => value => typeof value === type;
+ const eq = t => a => t === a;
+ const is = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf(o) === proto);
+ const isString = isType('string');
+ const isObject = isType('object');
+ const isPlainObject = value => is(value, Object);
+ const isArray = isType('array');
+ const isNull = eq(null);
+ const isBoolean = isSimpleType('boolean');
+ const isNullable = a => a === null || a === undefined;
+ const isNonNullable = a => !isNullable(a);
+ const isFunction = isSimpleType('function');
+ const isNumber = isSimpleType('number');
+ const isArrayOf = (value, pred) => {
+ if (isArray(value)) {
+ for (let i = 0, len = value.length; i < len; ++i) {
+ if (!pred(value[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+
+ const noop = () => {
+ };
+
+ 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 ?? '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 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 objAcc = r => (x, i) => {
+ r[i] = x;
+ };
+ const internalFilter = (obj, pred, onTrue, onFalse) => {
+ each(obj, (x, i) => {
+ (pred(x, i) ? onTrue : onFalse)(x, i);
+ });
+ };
+ const filter = (obj, pred) => {
+ const t = {};
+ internalFilter(obj, pred, objAcc(t), noop);
+ return t;
+ };
+ const has = (obj, key) => hasOwnProperty.call(obj, key);
+ const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;
+
+ const nativePush = Array.prototype.push;
+ 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 get = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
+ const head = xs => get(xs, 0);
+ const findMap = (arr, f) => {
+ for (let i = 0; i < arr.length; i++) {
+ const r = f(arr[i], i);
+ if (r.isSome()) {
+ return r;
+ }
+ }
+ return Optional.none();
+ };
+
+ typeof window !== 'undefined' ? window : Function('return this;')();
+
+ const rawSet = (dom, key, value) => {
+ if (isString(value) || isBoolean(value) || isNumber(value)) {
+ dom.setAttribute(key, value + '');
+ } else {
+ console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
+ throw new Error('Attribute value was not simple');
+ }
+ };
+ const set = (element, key, value) => {
+ rawSet(element.dom, key, value);
+ };
+ const remove = (element, key) => {
+ element.dom.removeAttribute(key);
+ };
+
+ const fromHtml = (html, scope) => {
+ const doc = scope || document;
+ const div = doc.createElement('div');
+ div.innerHTML = html;
+ if (!div.hasChildNodes() || div.childNodes.length > 1) {
+ const message = 'HTML does not have a single root node';
+ console.error(message, html);
+ throw new Error(message);
+ }
+ return fromDom(div.childNodes[0]);
+ };
+ const fromTag = (tag, scope) => {
+ const doc = scope || document;
+ const node = doc.createElement(tag);
+ return fromDom(node);
+ };
+ const fromText = (text, scope) => {
+ const doc = scope || document;
+ const node = doc.createTextNode(text);
+ return fromDom(node);
+ };
+ const fromDom = node => {
+ if (node === null || node === undefined) {
+ throw new Error('Node cannot be null or undefined');
+ }
+ return { dom: node };
+ };
+ const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
+ const SugarElement = {
+ fromHtml,
+ fromTag,
+ fromText,
+ fromDom,
+ fromPoint
+ };
+
+ var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
+
+ var global$2 = tinymce.util.Tools.resolve('tinymce.util.URI');
+
+ const isNotEmpty = s => s.length > 0;
+
+ const option = name => editor => editor.options.get(name);
+ const register$2 = editor => {
+ const registerOption = editor.options.register;
+ registerOption('image_dimensions', {
+ processor: 'boolean',
+ default: true
+ });
+ registerOption('image_advtab', {
+ processor: 'boolean',
+ default: false
+ });
+ registerOption('image_uploadtab', {
+ processor: 'boolean',
+ default: true
+ });
+ registerOption('image_prepend_url', {
+ processor: 'string',
+ default: ''
+ });
+ registerOption('image_class_list', { processor: 'object[]' });
+ registerOption('image_description', {
+ processor: 'boolean',
+ default: true
+ });
+ registerOption('image_title', {
+ processor: 'boolean',
+ default: false
+ });
+ registerOption('image_caption', {
+ processor: 'boolean',
+ default: false
+ });
+ registerOption('image_list', {
+ processor: value => {
+ const valid = value === false || isString(value) || isArrayOf(value, isObject) || isFunction(value);
+ return valid ? {
+ value,
+ valid
+ } : {
+ valid: false,
+ message: 'Must be false, a string, an array or a function.'
+ };
+ },
+ default: false
+ });
+ };
+ const hasDimensions = option('image_dimensions');
+ const hasAdvTab = option('image_advtab');
+ const hasUploadTab = option('image_uploadtab');
+ const getPrependUrl = option('image_prepend_url');
+ const getClassList = option('image_class_list');
+ const hasDescription = option('image_description');
+ const hasImageTitle = option('image_title');
+ const hasImageCaption = option('image_caption');
+ const getImageList = option('image_list');
+ const showAccessibilityOptions = option('a11y_advanced_options');
+ const isAutomaticUploadsEnabled = option('automatic_uploads');
+ const hasUploadUrl = editor => isNotEmpty(editor.options.get('images_upload_url'));
+ const hasUploadHandler = editor => isNonNullable(editor.options.get('images_upload_handler'));
+
+ const parseIntAndGetMax = (val1, val2) => Math.max(parseInt(val1, 10), parseInt(val2, 10));
+ const getImageSize = url => new Promise(callback => {
+ const img = document.createElement('img');
+ const done = dimensions => {
+ img.onload = img.onerror = null;
+ if (img.parentNode) {
+ img.parentNode.removeChild(img);
+ }
+ callback(dimensions);
+ };
+ img.onload = () => {
+ const width = parseIntAndGetMax(img.width, img.clientWidth);
+ const height = parseIntAndGetMax(img.height, img.clientHeight);
+ const dimensions = {
+ width,
+ height
+ };
+ done(Promise.resolve(dimensions));
+ };
+ img.onerror = () => {
+ done(Promise.reject(`Failed to get image dimensions for: ${ url }`));
+ };
+ const style = img.style;
+ style.visibility = 'hidden';
+ style.position = 'fixed';
+ style.bottom = style.left = '0px';
+ style.width = style.height = 'auto';
+ document.body.appendChild(img);
+ img.src = url;
+ });
+ const removePixelSuffix = value => {
+ if (value) {
+ value = value.replace(/px$/, '');
+ }
+ return value;
+ };
+ const addPixelSuffix = value => {
+ if (value.length > 0 && /^[0-9]+$/.test(value)) {
+ value += 'px';
+ }
+ return value;
+ };
+ const mergeMargins = css => {
+ if (css.margin) {
+ const splitMargin = String(css.margin).split(' ');
+ switch (splitMargin.length) {
+ case 1:
+ css['margin-top'] = css['margin-top'] || splitMargin[0];
+ css['margin-right'] = css['margin-right'] || splitMargin[0];
+ css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
+ css['margin-left'] = css['margin-left'] || splitMargin[0];
+ break;
+ case 2:
+ css['margin-top'] = css['margin-top'] || splitMargin[0];
+ css['margin-right'] = css['margin-right'] || splitMargin[1];
+ css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
+ css['margin-left'] = css['margin-left'] || splitMargin[1];
+ break;
+ case 3:
+ css['margin-top'] = css['margin-top'] || splitMargin[0];
+ css['margin-right'] = css['margin-right'] || splitMargin[1];
+ css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
+ css['margin-left'] = css['margin-left'] || splitMargin[1];
+ break;
+ case 4:
+ css['margin-top'] = css['margin-top'] || splitMargin[0];
+ css['margin-right'] = css['margin-right'] || splitMargin[1];
+ css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
+ css['margin-left'] = css['margin-left'] || splitMargin[3];
+ }
+ delete css.margin;
+ }
+ return css;
+ };
+ const createImageList = (editor, callback) => {
+ const imageList = getImageList(editor);
+ if (isString(imageList)) {
+ fetch(imageList).then(res => {
+ if (res.ok) {
+ res.json().then(callback);
+ }
+ });
+ } else if (isFunction(imageList)) {
+ imageList(callback);
+ } else {
+ callback(imageList);
+ }
+ };
+ const waitLoadImage = (editor, data, imgElm) => {
+ const selectImage = () => {
+ imgElm.onload = imgElm.onerror = null;
+ if (editor.selection) {
+ editor.selection.select(imgElm);
+ editor.nodeChanged();
+ }
+ };
+ imgElm.onload = () => {
+ if (!data.width && !data.height && hasDimensions(editor)) {
+ editor.dom.setAttribs(imgElm, {
+ width: String(imgElm.clientWidth),
+ height: String(imgElm.clientHeight)
+ });
+ }
+ selectImage();
+ };
+ imgElm.onerror = selectImage;
+ };
+ const blobToDataUri = blob => new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onload = () => {
+ resolve(reader.result);
+ };
+ reader.onerror = () => {
+ reject(reader.error?.message);
+ };
+ reader.readAsDataURL(blob);
+ });
+ const isPlaceholderImage = imgElm => imgElm.nodeName === 'IMG' && (imgElm.hasAttribute('data-mce-object') || imgElm.hasAttribute('data-mce-placeholder'));
+ const isSafeImageUrl = (editor, src) => {
+ const getOption = editor.options.get;
+ return global$2.isDomSafe(src, 'img', {
+ allow_html_data_urls: getOption('allow_html_data_urls'),
+ allow_script_urls: getOption('allow_script_urls'),
+ allow_svg_data_urls: getOption('allow_svg_data_urls')
+ });
+ };
+
+ const DOM = global$3.DOM;
+ const getHspace = image => {
+ if (image.style.marginLeft && image.style.marginRight && image.style.marginLeft === image.style.marginRight) {
+ return removePixelSuffix(image.style.marginLeft);
+ } else {
+ return '';
+ }
+ };
+ const getVspace = image => {
+ if (image.style.marginTop && image.style.marginBottom && image.style.marginTop === image.style.marginBottom) {
+ return removePixelSuffix(image.style.marginTop);
+ } else {
+ return '';
+ }
+ };
+ const getBorder = image => {
+ if (image.style.borderWidth) {
+ return removePixelSuffix(image.style.borderWidth);
+ } else {
+ return '';
+ }
+ };
+ const getAttrib = (image, name) => {
+ if (image.hasAttribute(name)) {
+ return image.getAttribute(name) ?? '';
+ } else {
+ return '';
+ }
+ };
+ const hasCaption = image => image.parentNode !== null && image.parentNode.nodeName === 'FIGURE';
+ const updateAttrib = (image, name, value) => {
+ if (value === '' || value === null) {
+ image.removeAttribute(name);
+ } else {
+ image.setAttribute(name, value);
+ }
+ };
+ const wrapInFigure = image => {
+ const figureElm = DOM.create('figure', { class: 'image' });
+ DOM.insertAfter(figureElm, image);
+ figureElm.appendChild(image);
+ figureElm.appendChild(DOM.create('figcaption', { contentEditable: 'true' }, 'Caption'));
+ figureElm.contentEditable = 'false';
+ };
+ const removeFigure = image => {
+ const figureElm = image.parentNode;
+ if (isNonNullable(figureElm)) {
+ DOM.insertAfter(image, figureElm);
+ DOM.remove(figureElm);
+ }
+ };
+ const toggleCaption = image => {
+ if (hasCaption(image)) {
+ removeFigure(image);
+ } else {
+ wrapInFigure(image);
+ }
+ };
+ const normalizeStyle = (image, normalizeCss) => {
+ const attrValue = image.getAttribute('style');
+ const value = normalizeCss(attrValue !== null ? attrValue : '');
+ if (value.length > 0) {
+ image.setAttribute('style', value);
+ image.setAttribute('data-mce-style', value);
+ } else {
+ image.removeAttribute('style');
+ }
+ };
+ const setSize = (name, normalizeCss) => (image, name, value) => {
+ const styles = image.style;
+ if (styles[name]) {
+ styles[name] = addPixelSuffix(value);
+ normalizeStyle(image, normalizeCss);
+ } else {
+ updateAttrib(image, name, value);
+ }
+ };
+ const getSize = (image, name) => {
+ if (image.style[name]) {
+ return removePixelSuffix(image.style[name]);
+ } else {
+ return getAttrib(image, name);
+ }
+ };
+ const setHspace = (image, value) => {
+ const pxValue = addPixelSuffix(value);
+ image.style.marginLeft = pxValue;
+ image.style.marginRight = pxValue;
+ };
+ const setVspace = (image, value) => {
+ const pxValue = addPixelSuffix(value);
+ image.style.marginTop = pxValue;
+ image.style.marginBottom = pxValue;
+ };
+ const setBorder = (image, value) => {
+ const pxValue = addPixelSuffix(value);
+ image.style.borderWidth = pxValue;
+ };
+ const setBorderStyle = (image, value) => {
+ image.style.borderStyle = value;
+ };
+ const getBorderStyle = image => image.style.borderStyle ?? '';
+ const isFigure = elm => isNonNullable(elm) && elm.nodeName === 'FIGURE';
+ const isImage = elm => elm.nodeName === 'IMG';
+ const getIsDecorative = image => DOM.getAttrib(image, 'alt').length === 0 && DOM.getAttrib(image, 'role') === 'presentation';
+ const getAlt = image => {
+ if (getIsDecorative(image)) {
+ return '';
+ } else {
+ return getAttrib(image, 'alt');
+ }
+ };
+ const defaultData = () => ({
+ src: '',
+ alt: '',
+ title: '',
+ width: '',
+ height: '',
+ class: '',
+ style: '',
+ caption: false,
+ hspace: '',
+ vspace: '',
+ border: '',
+ borderStyle: '',
+ isDecorative: false
+ });
+ const getStyleValue = (normalizeCss, data) => {
+ const image = document.createElement('img');
+ updateAttrib(image, 'style', data.style);
+ if (getHspace(image) || data.hspace !== '') {
+ setHspace(image, data.hspace);
+ }
+ if (getVspace(image) || data.vspace !== '') {
+ setVspace(image, data.vspace);
+ }
+ if (getBorder(image) || data.border !== '') {
+ setBorder(image, data.border);
+ }
+ if (getBorderStyle(image) || data.borderStyle !== '') {
+ setBorderStyle(image, data.borderStyle);
+ }
+ return normalizeCss(image.getAttribute('style') ?? '');
+ };
+ const create = (normalizeCss, data) => {
+ const image = document.createElement('img');
+ write(normalizeCss, {
+ ...data,
+ caption: false
+ }, image);
+ setAlt(image, data.alt, data.isDecorative);
+ if (data.caption) {
+ const figure = DOM.create('figure', { class: 'image' });
+ figure.appendChild(image);
+ figure.appendChild(DOM.create('figcaption', { contentEditable: 'true' }, 'Caption'));
+ figure.contentEditable = 'false';
+ return figure;
+ } else {
+ return image;
+ }
+ };
+ const read = (normalizeCss, image) => ({
+ src: getAttrib(image, 'src'),
+ alt: getAlt(image),
+ title: getAttrib(image, 'title'),
+ width: getSize(image, 'width'),
+ height: getSize(image, 'height'),
+ class: getAttrib(image, 'class'),
+ style: normalizeCss(getAttrib(image, 'style')),
+ caption: hasCaption(image),
+ hspace: getHspace(image),
+ vspace: getVspace(image),
+ border: getBorder(image),
+ borderStyle: getBorderStyle(image),
+ isDecorative: getIsDecorative(image)
+ });
+ const updateProp = (image, oldData, newData, name, set) => {
+ if (newData[name] !== oldData[name]) {
+ set(image, name, String(newData[name]));
+ }
+ };
+ const setAlt = (image, alt, isDecorative) => {
+ if (isDecorative) {
+ DOM.setAttrib(image, 'role', 'presentation');
+ const sugarImage = SugarElement.fromDom(image);
+ set(sugarImage, 'alt', '');
+ } else {
+ if (isNull(alt)) {
+ const sugarImage = SugarElement.fromDom(image);
+ remove(sugarImage, 'alt');
+ } else {
+ const sugarImage = SugarElement.fromDom(image);
+ set(sugarImage, 'alt', alt);
+ }
+ if (DOM.getAttrib(image, 'role') === 'presentation') {
+ DOM.setAttrib(image, 'role', '');
+ }
+ }
+ };
+ const updateAlt = (image, oldData, newData) => {
+ if (newData.alt !== oldData.alt || newData.isDecorative !== oldData.isDecorative) {
+ setAlt(image, newData.alt, newData.isDecorative);
+ }
+ };
+ const normalized = (set, normalizeCss) => (image, name, value) => {
+ set(image, value);
+ normalizeStyle(image, normalizeCss);
+ };
+ const write = (normalizeCss, newData, image) => {
+ const oldData = read(normalizeCss, image);
+ updateProp(image, oldData, newData, 'caption', (image, _name, _value) => toggleCaption(image));
+ updateProp(image, oldData, newData, 'src', updateAttrib);
+ updateProp(image, oldData, newData, 'title', updateAttrib);
+ updateProp(image, oldData, newData, 'width', setSize('width', normalizeCss));
+ updateProp(image, oldData, newData, 'height', setSize('height', normalizeCss));
+ updateProp(image, oldData, newData, 'class', updateAttrib);
+ updateProp(image, oldData, newData, 'style', normalized((image, value) => updateAttrib(image, 'style', value), normalizeCss));
+ updateProp(image, oldData, newData, 'hspace', normalized(setHspace, normalizeCss));
+ updateProp(image, oldData, newData, 'vspace', normalized(setVspace, normalizeCss));
+ updateProp(image, oldData, newData, 'border', normalized(setBorder, normalizeCss));
+ updateProp(image, oldData, newData, 'borderStyle', normalized(setBorderStyle, normalizeCss));
+ updateAlt(image, oldData, newData);
+ };
+
+ const normalizeCss$1 = (editor, cssText) => {
+ const css = editor.dom.styles.parse(cssText);
+ const mergedCss = mergeMargins(css);
+ const compressed = editor.dom.styles.parse(editor.dom.styles.serialize(mergedCss));
+ return editor.dom.styles.serialize(compressed);
+ };
+ const getSelectedImage = editor => {
+ const imgElm = editor.selection.getNode();
+ const figureElm = editor.dom.getParent(imgElm, 'figure.image');
+ if (figureElm) {
+ return editor.dom.select('img', figureElm)[0];
+ }
+ if (imgElm && (imgElm.nodeName !== 'IMG' || isPlaceholderImage(imgElm))) {
+ return null;
+ }
+ return imgElm;
+ };
+ const splitTextBlock = (editor, figure) => {
+ const dom = editor.dom;
+ const textBlockElements = filter(editor.schema.getTextBlockElements(), (_, parentElm) => !editor.schema.isValidChild(parentElm, 'figure'));
+ const textBlock = dom.getParent(figure.parentNode, node => hasNonNullableKey(textBlockElements, node.nodeName), editor.getBody());
+ if (textBlock) {
+ return dom.split(textBlock, figure) ?? figure;
+ } else {
+ return figure;
+ }
+ };
+ const readImageDataFromSelection = editor => {
+ const image = getSelectedImage(editor);
+ return image ? read(css => normalizeCss$1(editor, css), image) : defaultData();
+ };
+ const insertImageAtCaret = (editor, data) => {
+ const elm = create(css => normalizeCss$1(editor, css), data);
+ editor.dom.setAttrib(elm, 'data-mce-id', '__mcenew');
+ editor.focus();
+ editor.selection.setContent(elm.outerHTML);
+ const insertedElm = editor.dom.select('*[data-mce-id="__mcenew"]')[0];
+ editor.dom.setAttrib(insertedElm, 'data-mce-id', null);
+ if (isFigure(insertedElm)) {
+ const figure = splitTextBlock(editor, insertedElm);
+ editor.selection.select(figure);
+ } else {
+ editor.selection.select(insertedElm);
+ }
+ };
+ const syncSrcAttr = (editor, image) => {
+ editor.dom.setAttrib(image, 'src', image.getAttribute('src'));
+ };
+ const deleteImage = (editor, image) => {
+ if (image) {
+ const elm = editor.dom.is(image.parentNode, 'figure.image') ? image.parentNode : image;
+ editor.dom.remove(elm);
+ editor.focus();
+ editor.nodeChanged();
+ if (editor.dom.isEmpty(editor.getBody())) {
+ editor.setContent('');
+ editor.selection.setCursorLocation();
+ }
+ }
+ };
+ const writeImageDataToSelection = (editor, data) => {
+ const image = getSelectedImage(editor);
+ if (image) {
+ write(css => normalizeCss$1(editor, css), data, image);
+ syncSrcAttr(editor, image);
+ if (isFigure(image.parentNode)) {
+ const figure = image.parentNode;
+ splitTextBlock(editor, figure);
+ editor.selection.select(image.parentNode);
+ } else {
+ editor.selection.select(image);
+ waitLoadImage(editor, data, image);
+ }
+ }
+ };
+ const sanitizeImageData = (editor, data) => {
+ const src = data.src;
+ return {
+ ...data,
+ src: isSafeImageUrl(editor, src) ? src : ''
+ };
+ };
+ const insertOrUpdateImage = (editor, partialData) => {
+ const image = getSelectedImage(editor);
+ if (image) {
+ const selectedImageData = read(css => normalizeCss$1(editor, css), image);
+ const data = {
+ ...selectedImageData,
+ ...partialData
+ };
+ const sanitizedData = sanitizeImageData(editor, data);
+ if (data.src) {
+ writeImageDataToSelection(editor, sanitizedData);
+ } else {
+ deleteImage(editor, image);
+ }
+ } else if (partialData.src) {
+ insertImageAtCaret(editor, {
+ ...defaultData(),
+ ...partialData
+ });
+ }
+ };
+
+ const deep = (old, nu) => {
+ const bothObjects = isPlainObject(old) && isPlainObject(nu);
+ return bothObjects ? deepMerge(old, nu) : nu;
+ };
+ const baseMerge = merger => {
+ return (...objects) => {
+ if (objects.length === 0) {
+ throw new Error(`Can't merge zero objects`);
+ }
+ const ret = {};
+ for (let j = 0; j < objects.length; j++) {
+ const curObject = objects[j];
+ for (const key in curObject) {
+ if (has(curObject, key)) {
+ ret[key] = merger(ret[key], curObject[key]);
+ }
+ }
+ }
+ return ret;
+ };
+ };
+ const deepMerge = baseMerge(deep);
+
+ var global$1 = tinymce.util.Tools.resolve('tinymce.util.ImageUploader');
+
+ var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
+
+ const getValue = item => isString(item.value) ? item.value : '';
+ const getText = item => {
+ if (isString(item.text)) {
+ return item.text;
+ } else if (isString(item.title)) {
+ return item.title;
+ } else {
+ return '';
+ }
+ };
+ const sanitizeList = (list, extractValue) => {
+ const out = [];
+ global.each(list, item => {
+ const text = getText(item);
+ if (item.menu !== undefined) {
+ const items = sanitizeList(item.menu, extractValue);
+ out.push({
+ text,
+ items
+ });
+ } else {
+ const value = extractValue(item);
+ out.push({
+ text,
+ value
+ });
+ }
+ });
+ return out;
+ };
+ const sanitizer = (extractor = getValue) => list => {
+ if (list) {
+ return Optional.from(list).map(list => sanitizeList(list, extractor));
+ } else {
+ return Optional.none();
+ }
+ };
+ const sanitize = list => sanitizer(getValue)(list);
+ const isGroup = item => has(item, 'items');
+ const findEntryDelegate = (list, value) => findMap(list, item => {
+ if (isGroup(item)) {
+ return findEntryDelegate(item.items, value);
+ } else if (item.value === value) {
+ return Optional.some(item);
+ } else {
+ return Optional.none();
+ }
+ });
+ const findEntry = (optList, value) => optList.bind(list => findEntryDelegate(list, value));
+ const ListUtils = {
+ sanitizer,
+ sanitize,
+ findEntry
+ };
+
+ const makeTab$2 = _info => ({
+ title: 'Advanced',
+ name: 'advanced',
+ items: [{
+ type: 'grid',
+ columns: 2,
+ items: [
+ {
+ type: 'input',
+ label: 'Vertical space',
+ name: 'vspace',
+ inputMode: 'numeric'
+ },
+ {
+ type: 'input',
+ label: 'Horizontal space',
+ name: 'hspace',
+ inputMode: 'numeric'
+ },
+ {
+ type: 'input',
+ label: 'Border width',
+ name: 'border',
+ inputMode: 'numeric'
+ },
+ {
+ type: 'listbox',
+ name: 'borderstyle',
+ label: 'Border style',
+ items: [
+ {
+ text: 'Select...',
+ value: ''
+ },
+ {
+ text: 'Solid',
+ value: 'solid'
+ },
+ {
+ text: 'Dotted',
+ value: 'dotted'
+ },
+ {
+ text: 'Dashed',
+ value: 'dashed'
+ },
+ {
+ text: 'Double',
+ value: 'double'
+ },
+ {
+ text: 'Groove',
+ value: 'groove'
+ },
+ {
+ text: 'Ridge',
+ value: 'ridge'
+ },
+ {
+ text: 'Inset',
+ value: 'inset'
+ },
+ {
+ text: 'Outset',
+ value: 'outset'
+ },
+ {
+ text: 'None',
+ value: 'none'
+ },
+ {
+ text: 'Hidden',
+ value: 'hidden'
+ }
+ ]
+ }
+ ]
+ }]
+ });
+ const AdvTab = { makeTab: makeTab$2 };
+
+ const collect = editor => {
+ const urlListSanitizer = ListUtils.sanitizer(item => editor.convertURL(item.value || item.url || '', 'src'));
+ const futureImageList = new Promise(completer => {
+ createImageList(editor, imageList => {
+ completer(urlListSanitizer(imageList).map(items => flatten([
+ [{
+ text: 'None',
+ value: ''
+ }],
+ items
+ ])));
+ });
+ });
+ const classList = ListUtils.sanitize(getClassList(editor));
+ const hasAdvTab$1 = hasAdvTab(editor);
+ const hasUploadTab$1 = hasUploadTab(editor);
+ const hasUploadUrl$1 = hasUploadUrl(editor);
+ const hasUploadHandler$1 = hasUploadHandler(editor);
+ const image = readImageDataFromSelection(editor);
+ const hasDescription$1 = hasDescription(editor);
+ const hasImageTitle$1 = hasImageTitle(editor);
+ const hasDimensions$1 = hasDimensions(editor);
+ const hasImageCaption$1 = hasImageCaption(editor);
+ const hasAccessibilityOptions = showAccessibilityOptions(editor);
+ const automaticUploads = isAutomaticUploadsEnabled(editor);
+ const prependURL = Optional.some(getPrependUrl(editor)).filter(preUrl => isString(preUrl) && preUrl.length > 0);
+ return futureImageList.then(imageList => ({
+ image,
+ imageList,
+ classList,
+ hasAdvTab: hasAdvTab$1,
+ hasUploadTab: hasUploadTab$1,
+ hasUploadUrl: hasUploadUrl$1,
+ hasUploadHandler: hasUploadHandler$1,
+ hasDescription: hasDescription$1,
+ hasImageTitle: hasImageTitle$1,
+ hasDimensions: hasDimensions$1,
+ hasImageCaption: hasImageCaption$1,
+ prependURL,
+ hasAccessibilityOptions,
+ automaticUploads
+ }));
+ };
+
+ const makeItems = info => {
+ const imageUrl = {
+ name: 'src',
+ type: 'urlinput',
+ filetype: 'image',
+ label: 'Source'
+ };
+ const imageList = info.imageList.map(items => ({
+ name: 'images',
+ type: 'listbox',
+ label: 'Image list',
+ items
+ }));
+ const imageDescription = {
+ name: 'alt',
+ type: 'input',
+ label: 'Alternative description',
+ enabled: !(info.hasAccessibilityOptions && info.image.isDecorative)
+ };
+ const imageTitle = {
+ name: 'title',
+ type: 'input',
+ label: 'Image title'
+ };
+ const imageDimensions = {
+ name: 'dimensions',
+ type: 'sizeinput'
+ };
+ const isDecorative = {
+ type: 'label',
+ label: 'Accessibility',
+ items: [{
+ name: 'isDecorative',
+ type: 'checkbox',
+ label: 'Image is decorative'
+ }]
+ };
+ const classList = info.classList.map(items => ({
+ name: 'classes',
+ type: 'listbox',
+ label: 'Class',
+ items
+ }));
+ const caption = {
+ type: 'label',
+ label: 'Caption',
+ items: [{
+ type: 'checkbox',
+ name: 'caption',
+ label: 'Show caption'
+ }]
+ };
+ const getDialogContainerType = useColumns => useColumns ? {
+ type: 'grid',
+ columns: 2
+ } : { type: 'panel' };
+ return flatten([
+ [imageUrl],
+ imageList.toArray(),
+ info.hasAccessibilityOptions && info.hasDescription ? [isDecorative] : [],
+ info.hasDescription ? [imageDescription] : [],
+ info.hasImageTitle ? [imageTitle] : [],
+ info.hasDimensions ? [imageDimensions] : [],
+ [{
+ ...getDialogContainerType(info.classList.isSome() && info.hasImageCaption),
+ items: flatten([
+ classList.toArray(),
+ info.hasImageCaption ? [caption] : []
+ ])
+ }]
+ ]);
+ };
+ const makeTab$1 = info => ({
+ title: 'General',
+ name: 'general',
+ items: makeItems(info)
+ });
+ const MainTab = {
+ makeTab: makeTab$1,
+ makeItems
+ };
+
+ const makeTab = _info => {
+ const items = [{
+ type: 'dropzone',
+ name: 'fileinput'
+ }];
+ return {
+ title: 'Upload',
+ name: 'upload',
+ items
+ };
+ };
+ const UploadTab = { makeTab };
+
+ const createState = info => ({
+ prevImage: ListUtils.findEntry(info.imageList, info.image.src),
+ prevAlt: info.image.alt,
+ open: true
+ });
+ const fromImageData = image => ({
+ src: {
+ value: image.src,
+ meta: {}
+ },
+ images: image.src,
+ alt: image.alt,
+ title: image.title,
+ dimensions: {
+ width: image.width,
+ height: image.height
+ },
+ classes: image.class,
+ caption: image.caption,
+ style: image.style,
+ vspace: image.vspace,
+ border: image.border,
+ hspace: image.hspace,
+ borderstyle: image.borderStyle,
+ fileinput: [],
+ isDecorative: image.isDecorative
+ });
+ const toImageData = (data, removeEmptyAlt) => ({
+ src: data.src.value,
+ alt: (data.alt === null || data.alt.length === 0) && removeEmptyAlt ? null : data.alt,
+ title: data.title,
+ width: data.dimensions.width,
+ height: data.dimensions.height,
+ class: data.classes,
+ style: data.style,
+ caption: data.caption,
+ hspace: data.hspace,
+ vspace: data.vspace,
+ border: data.border,
+ borderStyle: data.borderstyle,
+ isDecorative: data.isDecorative
+ });
+ const addPrependUrl2 = (info, srcURL) => {
+ if (!/^(?:[a-zA-Z]+:)?\/\//.test(srcURL)) {
+ return info.prependURL.bind(prependUrl => {
+ if (srcURL.substring(0, prependUrl.length) !== prependUrl) {
+ return Optional.some(prependUrl + srcURL);
+ }
+ return Optional.none();
+ });
+ }
+ return Optional.none();
+ };
+ const addPrependUrl = (info, api) => {
+ const data = api.getData();
+ addPrependUrl2(info, data.src.value).each(srcURL => {
+ api.setData({
+ src: {
+ value: srcURL,
+ meta: data.src.meta
+ }
+ });
+ });
+ };
+ const formFillFromMeta2 = (info, data, meta) => {
+ if (info.hasDescription && isString(meta.alt)) {
+ data.alt = meta.alt;
+ }
+ if (info.hasAccessibilityOptions) {
+ data.isDecorative = meta.isDecorative || data.isDecorative || false;
+ }
+ if (info.hasImageTitle && isString(meta.title)) {
+ data.title = meta.title;
+ }
+ if (info.hasDimensions) {
+ if (isString(meta.width)) {
+ data.dimensions.width = meta.width;
+ }
+ if (isString(meta.height)) {
+ data.dimensions.height = meta.height;
+ }
+ }
+ if (isString(meta.class)) {
+ ListUtils.findEntry(info.classList, meta.class).each(entry => {
+ data.classes = entry.value;
+ });
+ }
+ if (info.hasImageCaption) {
+ if (isBoolean(meta.caption)) {
+ data.caption = meta.caption;
+ }
+ }
+ if (info.hasAdvTab) {
+ if (isString(meta.style)) {
+ data.style = meta.style;
+ }
+ if (isString(meta.vspace)) {
+ data.vspace = meta.vspace;
+ }
+ if (isString(meta.border)) {
+ data.border = meta.border;
+ }
+ if (isString(meta.hspace)) {
+ data.hspace = meta.hspace;
+ }
+ if (isString(meta.borderstyle)) {
+ data.borderstyle = meta.borderstyle;
+ }
+ }
+ };
+ const formFillFromMeta = (info, api) => {
+ const data = api.getData();
+ const meta = data.src.meta;
+ if (meta !== undefined) {
+ const newData = deepMerge({}, data);
+ formFillFromMeta2(info, newData, meta);
+ api.setData(newData);
+ }
+ };
+ const calculateImageSize = (helpers, info, state, api) => {
+ const data = api.getData();
+ const url = data.src.value;
+ const meta = data.src.meta || {};
+ if (!meta.width && !meta.height && info.hasDimensions) {
+ if (isNotEmpty(url)) {
+ helpers.imageSize(url).then(size => {
+ if (state.open) {
+ api.setData({ dimensions: size });
+ }
+ }).catch(e => console.error(e));
+ } else {
+ api.setData({
+ dimensions: {
+ width: '',
+ height: ''
+ }
+ });
+ }
+ }
+ };
+ const updateImagesDropdown = (info, state, api) => {
+ const data = api.getData();
+ const image = ListUtils.findEntry(info.imageList, data.src.value);
+ state.prevImage = image;
+ api.setData({ images: image.map(entry => entry.value).getOr('') });
+ };
+ const changeSrc = (helpers, info, state, api) => {
+ addPrependUrl(info, api);
+ formFillFromMeta(info, api);
+ calculateImageSize(helpers, info, state, api);
+ updateImagesDropdown(info, state, api);
+ };
+ const changeImages = (helpers, info, state, api) => {
+ const data = api.getData();
+ const image = ListUtils.findEntry(info.imageList, data.images);
+ image.each(img => {
+ const updateAlt = data.alt === '' || state.prevImage.map(image => image.text === data.alt).getOr(false);
+ if (updateAlt) {
+ if (img.value === '') {
+ api.setData({
+ src: img,
+ alt: state.prevAlt
+ });
+ } else {
+ api.setData({
+ src: img,
+ alt: img.text
+ });
+ }
+ } else {
+ api.setData({ src: img });
+ }
+ });
+ state.prevImage = image;
+ changeSrc(helpers, info, state, api);
+ };
+ const changeFileInput = (helpers, info, state, api) => {
+ const data = api.getData();
+ api.block('Uploading image');
+ head(data.fileinput).fold(() => {
+ api.unblock();
+ }, file => {
+ const blobUri = URL.createObjectURL(file);
+ const finalize = () => {
+ api.unblock();
+ URL.revokeObjectURL(blobUri);
+ };
+ const updateSrcAndSwitchTab = url => {
+ api.setData({
+ src: {
+ value: url,
+ meta: {}
+ }
+ });
+ api.showTab('general');
+ changeSrc(helpers, info, state, api);
+ };
+ blobToDataUri(file).then(dataUrl => {
+ const blobInfo = helpers.createBlobCache(file, blobUri, dataUrl);
+ if (info.automaticUploads) {
+ helpers.uploadImage(blobInfo).then(result => {
+ updateSrcAndSwitchTab(result.url);
+ finalize();
+ }).catch(err => {
+ finalize();
+ helpers.alertErr(err);
+ });
+ } else {
+ helpers.addToBlobCache(blobInfo);
+ updateSrcAndSwitchTab(blobInfo.blobUri());
+ api.unblock();
+ }
+ });
+ });
+ };
+ const changeHandler = (helpers, info, state) => (api, evt) => {
+ if (evt.name === 'src') {
+ changeSrc(helpers, info, state, api);
+ } else if (evt.name === 'images') {
+ changeImages(helpers, info, state, api);
+ } else if (evt.name === 'alt') {
+ state.prevAlt = api.getData().alt;
+ } else if (evt.name === 'fileinput') {
+ changeFileInput(helpers, info, state, api);
+ } else if (evt.name === 'isDecorative') {
+ api.setEnabled('alt', !api.getData().isDecorative);
+ }
+ };
+ const closeHandler = state => () => {
+ state.open = false;
+ };
+ const makeDialogBody = info => {
+ if (info.hasAdvTab || info.hasUploadUrl || info.hasUploadHandler) {
+ const tabPanel = {
+ type: 'tabpanel',
+ tabs: flatten([
+ [MainTab.makeTab(info)],
+ info.hasAdvTab ? [AdvTab.makeTab(info)] : [],
+ info.hasUploadTab && (info.hasUploadUrl || info.hasUploadHandler) ? [UploadTab.makeTab(info)] : []
+ ])
+ };
+ return tabPanel;
+ } else {
+ const panel = {
+ type: 'panel',
+ items: MainTab.makeItems(info)
+ };
+ return panel;
+ }
+ };
+ const submitHandler = (editor, info, helpers) => api => {
+ const data = deepMerge(fromImageData(info.image), api.getData());
+ const finalData = {
+ ...data,
+ style: getStyleValue(helpers.normalizeCss, toImageData(data, false))
+ };
+ editor.execCommand('mceUpdateImage', false, toImageData(finalData, info.hasAccessibilityOptions));
+ editor.editorUpload.uploadImagesAuto();
+ api.close();
+ };
+ const imageSize = editor => url => {
+ if (!isSafeImageUrl(editor, url)) {
+ return Promise.resolve({
+ width: '',
+ height: ''
+ });
+ } else {
+ return getImageSize(editor.documentBaseURI.toAbsolute(url)).then(dimensions => ({
+ width: String(dimensions.width),
+ height: String(dimensions.height)
+ }));
+ }
+ };
+ const createBlobCache = editor => (file, blobUri, dataUrl) => editor.editorUpload.blobCache.create({
+ blob: file,
+ blobUri,
+ name: file.name?.replace(/\.[^\.]+$/, ''),
+ filename: file.name,
+ base64: dataUrl.split(',')[1]
+ });
+ const addToBlobCache = editor => blobInfo => {
+ editor.editorUpload.blobCache.add(blobInfo);
+ };
+ const alertErr = editor => message => {
+ editor.windowManager.alert(message);
+ };
+ const normalizeCss = editor => cssText => normalizeCss$1(editor, cssText);
+ const parseStyle = editor => cssText => editor.dom.parseStyle(cssText);
+ const serializeStyle = editor => (stylesArg, name) => editor.dom.serializeStyle(stylesArg, name);
+ const uploadImage = editor => blobInfo => global$1(editor).upload([blobInfo], false).then(results => {
+ if (results.length === 0) {
+ return Promise.reject('Failed to upload image');
+ } else if (results[0].status === false) {
+ return Promise.reject(results[0].error?.message);
+ } else {
+ return results[0];
+ }
+ });
+ const Dialog = editor => {
+ const helpers = {
+ imageSize: imageSize(editor),
+ addToBlobCache: addToBlobCache(editor),
+ createBlobCache: createBlobCache(editor),
+ alertErr: alertErr(editor),
+ normalizeCss: normalizeCss(editor),
+ parseStyle: parseStyle(editor),
+ serializeStyle: serializeStyle(editor),
+ uploadImage: uploadImage(editor)
+ };
+ const open = () => {
+ collect(editor).then(info => {
+ const state = createState(info);
+ return {
+ title: 'Insert/Edit Image',
+ size: 'normal',
+ body: makeDialogBody(info),
+ buttons: [
+ {
+ type: 'cancel',
+ name: 'cancel',
+ text: 'Cancel'
+ },
+ {
+ type: 'submit',
+ name: 'save',
+ text: 'Save',
+ primary: true
+ }
+ ],
+ initialData: fromImageData(info.image),
+ onSubmit: submitHandler(editor, info, helpers),
+ onChange: changeHandler(helpers, info, state),
+ onClose: closeHandler(state)
+ };
+ }).then(editor.windowManager.open);
+ };
+ return { open };
+ };
+
+ const register$1 = editor => {
+ editor.addCommand('mceImage', Dialog(editor).open);
+ editor.addCommand('mceUpdateImage', (_ui, data) => {
+ editor.undoManager.transact(() => insertOrUpdateImage(editor, data));
+ });
+ };
+
+ const hasImageClass = node => {
+ const className = node.attr('class');
+ return isNonNullable(className) && /\bimage\b/.test(className);
+ };
+ const toggleContentEditableState = state => nodes => {
+ let i = nodes.length;
+ const toggleContentEditable = node => {
+ node.attr('contenteditable', state ? 'true' : null);
+ };
+ while (i--) {
+ const node = nodes[i];
+ if (hasImageClass(node)) {
+ node.attr('contenteditable', state ? 'false' : null);
+ global.each(node.getAll('figcaption'), toggleContentEditable);
+ }
+ }
+ };
+ const setup = editor => {
+ editor.on('PreInit', () => {
+ editor.parser.addNodeFilter('figure', toggleContentEditableState(true));
+ editor.serializer.addNodeFilter('figure', toggleContentEditableState(false));
+ });
+ };
+
+ const register = editor => {
+ editor.ui.registry.addToggleButton('image', {
+ icon: 'image',
+ tooltip: 'Insert/edit image',
+ onAction: Dialog(editor).open,
+ onSetup: buttonApi => {
+ buttonApi.setActive(isNonNullable(getSelectedImage(editor)));
+ return editor.selection.selectorChangedWithUnbind('img:not([data-mce-object]):not([data-mce-placeholder]),figure.image', buttonApi.setActive).unbind;
+ }
+ });
+ editor.ui.registry.addMenuItem('image', {
+ icon: 'image',
+ text: 'Image...',
+ onAction: Dialog(editor).open
+ });
+ editor.ui.registry.addContextMenu('image', { update: element => isFigure(element) || isImage(element) && !isPlaceholderImage(element) ? ['image'] : [] });
+ };
+
+ var Plugin = () => {
+ global$4.add('image', editor => {
+ register$2(editor);
+ setup(editor);
+ register(editor);
+ register$1(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/image/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/image/plugin.min.js
new file mode 100644
index 00000000000..98a3a7a9763
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/image/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=Object.getPrototypeOf,a=(e,t,a)=>!!a(e,t.prototype)||e.constructor?.name===t.name,i=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&a(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,s=e=>t=>typeof t===e,o=i("string"),r=i("object"),n=e=>((e,i)=>r(e)&&a(e,i,((e,a)=>t(e)===a)))(e,Object),l=i("array"),c=(null,e=>null===e);const m=s("boolean"),d=e=>!(e=>null==e)(e),g=s("function"),p=s("number"),u=()=>{};class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(e??"Called getOrDie on None")}static from(e){return d(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const b=Object.keys,y=Object.hasOwnProperty,v=(e,t)=>y.call(e,t),f=Array.prototype.push,w=e=>{const t=[];for(let a=0,i=e.length;a{((e,t,a)=>{if(!(o(a)||m(a)||p(a)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",a,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,a+"")})(e.dom,t,a)},D=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},_=D;var C=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),I=tinymce.util.Tools.resolve("tinymce.util.URI");const U=e=>e.length>0,x=e=>t=>t.options.get(e),S=x("image_dimensions"),N=x("image_advtab"),T=x("image_uploadtab"),O=x("image_prepend_url"),L=x("image_class_list"),E=x("image_description"),j=x("image_title"),M=x("image_caption"),R=x("image_list"),k=x("a11y_advanced_options"),z=x("automatic_uploads"),P=(e,t)=>Math.max(parseInt(e,10),parseInt(t,10)),B=e=>(e&&(e=e.replace(/px$/,"")),e),F=e=>(e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e),H=e=>"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder")),G=(e,t)=>{const a=e.options.get;return I.isDomSafe(t,"img",{allow_html_data_urls:a("allow_html_data_urls"),allow_script_urls:a("allow_script_urls"),allow_svg_data_urls:a("allow_svg_data_urls")})},W=C.DOM,$=e=>e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?B(e.style.marginLeft):"",V=e=>e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?B(e.style.marginTop):"",K=e=>e.style.borderWidth?B(e.style.borderWidth):"",Z=(e,t)=>e.hasAttribute(t)?e.getAttribute(t)??"":"",q=e=>null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName,J=(e,t,a)=>{""===a||null===a?e.removeAttribute(t):e.setAttribute(t,a)},Q=(e,t)=>{const a=e.getAttribute("style"),i=t(null!==a?a:"");i.length>0?(e.setAttribute("style",i),e.setAttribute("data-mce-style",i)):e.removeAttribute("style")},X=(e,t)=>(e,a,i)=>{const s=e.style;s[a]?(s[a]=F(i),Q(e,t)):J(e,a,i)},Y=(e,t)=>e.style[t]?B(e.style[t]):Z(e,t),ee=(e,t)=>{const a=F(t);e.style.marginLeft=a,e.style.marginRight=a},te=(e,t)=>{const a=F(t);e.style.marginTop=a,e.style.marginBottom=a},ae=(e,t)=>{const a=F(t);e.style.borderWidth=a},ie=(e,t)=>{e.style.borderStyle=t},se=e=>e.style.borderStyle??"",oe=e=>d(e)&&"FIGURE"===e.nodeName,re=e=>0===W.getAttrib(e,"alt").length&&"presentation"===W.getAttrib(e,"role"),ne=e=>re(e)?"":Z(e,"alt"),le=(e,t)=>{const a=document.createElement("img");return J(a,"style",t.style),($(a)||""!==t.hspace)&&ee(a,t.hspace),(V(a)||""!==t.vspace)&&te(a,t.vspace),(K(a)||""!==t.border)&&ae(a,t.border),(se(a)||""!==t.borderStyle)&&ie(a,t.borderStyle),e(a.getAttribute("style")??"")},ce=(e,t)=>({src:Z(t,"src"),alt:ne(t),title:Z(t,"title"),width:Y(t,"width"),height:Y(t,"height"),class:Z(t,"class"),style:e(Z(t,"style")),caption:q(t),hspace:$(t),vspace:V(t),border:K(t),borderStyle:se(t),isDecorative:re(t)}),me=(e,t,a,i,s)=>{a[i]!==t[i]&&s(e,i,String(a[i]))},de=(e,t,a)=>{if(a){W.setAttrib(e,"role","presentation");const t=_(e);A(t,"alt","")}else{if(c(t)){"alt",_(e).dom.removeAttribute("alt")}else{const a=_(e);A(a,"alt",t)}"presentation"===W.getAttrib(e,"role")&&W.setAttrib(e,"role","")}},ge=(e,t)=>(a,i,s)=>{e(a,s),Q(a,t)},pe=(e,t,a)=>{const i=ce(e,a);me(a,i,t,"caption",((e,t,a)=>(e=>{q(e)?(e=>{const t=e.parentNode;d(t)&&(W.insertAfter(e,t),W.remove(t))})(e):(e=>{const t=W.create("figure",{class:"image"});W.insertAfter(t,e),t.appendChild(e),t.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"})(e)})(e))),me(a,i,t,"src",J),me(a,i,t,"title",J),me(a,i,t,"width",X(0,e)),me(a,i,t,"height",X(0,e)),me(a,i,t,"class",J),me(a,i,t,"style",ge(((e,t)=>J(e,"style",t)),e)),me(a,i,t,"hspace",ge(ee,e)),me(a,i,t,"vspace",ge(te,e)),me(a,i,t,"border",ge(ae,e)),me(a,i,t,"borderStyle",ge(ie,e)),((e,t,a)=>{a.alt===t.alt&&a.isDecorative===t.isDecorative||de(e,a.alt,a.isDecorative)})(a,i,t)},ue=(e,t)=>{const a=(e=>{if(e.margin){const t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e})(e.dom.styles.parse(t)),i=e.dom.styles.parse(e.dom.styles.serialize(a));return e.dom.styles.serialize(i)},he=e=>{const t=e.selection.getNode(),a=e.dom.getParent(t,"figure.image");return a?e.dom.select("img",a)[0]:t&&("IMG"!==t.nodeName||H(t))?null:t},be=(e,t)=>{const a=e.dom,i=((t,a)=>{const i={};var s;return((e,t,a,i)=>{((e,t)=>{const a=b(e);for(let i=0,s=a.length;i{(t(e,s)?a:i)(e,s)}))})(t,((t,a)=>!e.schema.isValidChild(a,"figure")),(s=i,(e,t)=>{s[t]=e}),u),i})(e.schema.getTextBlockElements()),s=a.getParent(t.parentNode,(e=>{return t=i,a=e.nodeName,v(t,a)&&void 0!==t[a]&&null!==t[a];var t,a}),e.getBody());return s?a.split(s,t)??t:t},ye=(e,t)=>{const a=((t,a)=>{const i=document.createElement("img");if(pe((t=>ue(e,t)),{...a,caption:!1},i),de(i,a.alt,a.isDecorative),a.caption){const e=W.create("figure",{class:"image"});return e.appendChild(i),e.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),e.contentEditable="false",e}return i})(0,t);e.dom.setAttrib(a,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(a.outerHTML);const i=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(i,"data-mce-id",null),oe(i)){const t=be(e,i);e.selection.select(t)}else e.selection.select(i)},ve=(e,t)=>{const a=he(e);if(a){const i={...ce((t=>ue(e,t)),a),...t},s=((e,t)=>{const a=t.src;return{...t,src:G(e,a)?a:""}})(e,i);i.src?((e,t)=>{const a=he(e);if(a)if(pe((t=>ue(e,t)),t,a),((e,t)=>{e.dom.setAttrib(t,"src",t.getAttribute("src"))})(e,a),oe(a.parentNode)){const t=a.parentNode;be(e,t),e.selection.select(a.parentNode)}else e.selection.select(a),((e,t,a)=>{const i=()=>{a.onload=a.onerror=null,e.selection&&(e.selection.select(a),e.nodeChanged())};a.onload=()=>{t.width||t.height||!S(e)||e.dom.setAttribs(a,{width:String(a.clientWidth),height:String(a.clientHeight)}),i()},a.onerror=i})(e,t,a)})(e,s):((e,t)=>{if(t){const a=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(a),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}})(e,a)}else t.src&&ye(e,{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1,...t})},fe=(we=(e,t)=>n(e)&&n(t)?fe(e,t):t,(...e)=>{if(0===e.length)throw new Error("Can't merge zero objects");const t={};for(let a=0;ao(e.value)?e.value:"",Ce=(e,t)=>{const a=[];return De.each(e,(e=>{const i=(e=>o(e.text)?e.text:o(e.title)?e.title:"")(e);if(void 0!==e.menu){const s=Ce(e.menu,t);a.push({text:i,items:s})}else{const s=t(e);a.push({text:i,value:s})}})),a},Ie=(e=_e)=>t=>t?h.from(t).map((t=>Ce(t,e))):h.none(),Ue=(e,t)=>((e,a)=>{for(let a=0;av(e,"items"))(i=e[a])?Ue(i.items,t):i.value===t?h.some(i):h.none();if(s.isSome())return s}var i;return h.none()})(e),xe=Ie,Se=(e,t)=>e.bind((e=>Ue(e,t))),Ne=e=>{const t=xe((t=>e.convertURL(t.value||t.url||"","src"))),a=new Promise((a=>{((e,t)=>{const a=R(e);o(a)?fetch(a).then((e=>{e.ok&&e.json().then(t)})):g(a)?a(t):t(a)})(e,(e=>{a(t(e).map((e=>w([[{text:"None",value:""}],e]))))}))})),i=(A=L(e),Ie(_e)(A)),s=N(e),r=T(e),n=(e=>U(e.options.get("images_upload_url")))(e),l=(e=>d(e.options.get("images_upload_handler")))(e),c=(e=>{const t=he(e);return t?ce((t=>ue(e,t)),t):{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}})(e),m=E(e),p=j(e),u=S(e),b=M(e),y=k(e),v=z(e),f=h.some(O(e)).filter((e=>o(e)&&e.length>0));var A;return a.then((e=>({image:c,imageList:e,classList:i,hasAdvTab:s,hasUploadTab:r,hasUploadUrl:n,hasUploadHandler:l,hasDescription:m,hasImageTitle:p,hasDimensions:u,hasImageCaption:b,prependURL:f,hasAccessibilityOptions:y,automaticUploads:v})))},Te=e=>{const t=e.imageList.map((e=>({name:"images",type:"listbox",label:"Image list",items:e}))),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},i=e.classList.map((e=>({name:"classes",type:"listbox",label:"Class",items:e})));return w([[{name:"src",type:"urlinput",filetype:"image",label:"Source"}],t.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[{...(s=e.classList.isSome()&&e.hasImageCaption,s?{type:"grid",columns:2}:{type:"panel"}),items:w([i.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])}]]);var s},Oe=e=>({title:"General",name:"general",items:Te(e)}),Le=Te,Ee=e=>({src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative}),je=(e,t)=>({src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative}),Me=(e,t,a,i)=>{((e,t)=>{const a=t.getData();((e,t)=>/^(?:[a-zA-Z]+:)?\/\//.test(t)?h.none():e.prependURL.bind((e=>t.substring(0,e.length)!==e?h.some(e+t):h.none())))(e,a.src.value).each((e=>{t.setData({src:{value:e,meta:a.src.meta}})}))})(t,i),((e,t)=>{const a=t.getData(),i=a.src.meta;if(void 0!==i){const s=fe({},a);((e,t,a)=>{e.hasDescription&&o(a.alt)&&(t.alt=a.alt),e.hasAccessibilityOptions&&(t.isDecorative=a.isDecorative||t.isDecorative||!1),e.hasImageTitle&&o(a.title)&&(t.title=a.title),e.hasDimensions&&(o(a.width)&&(t.dimensions.width=a.width),o(a.height)&&(t.dimensions.height=a.height)),o(a.class)&&Se(e.classList,a.class).each((e=>{t.classes=e.value})),e.hasImageCaption&&m(a.caption)&&(t.caption=a.caption),e.hasAdvTab&&(o(a.style)&&(t.style=a.style),o(a.vspace)&&(t.vspace=a.vspace),o(a.border)&&(t.border=a.border),o(a.hspace)&&(t.hspace=a.hspace),o(a.borderstyle)&&(t.borderstyle=a.borderstyle))})(e,s,i),t.setData(s)}})(t,i),((e,t,a,i)=>{const s=i.getData(),o=s.src.value,r=s.src.meta||{};r.width||r.height||!t.hasDimensions||(U(o)?e.imageSize(o).then((e=>{a.open&&i.setData({dimensions:e})})).catch((e=>console.error(e))):i.setData({dimensions:{width:"",height:""}}))})(e,t,a,i),((e,t,a)=>{const i=a.getData(),s=Se(e.imageList,i.src.value);t.prevImage=s,a.setData({images:s.map((e=>e.value)).getOr("")})})(t,a,i)},Re=(e,t,a,i)=>{const s=i.getData();var o;i.block("Uploading image"),(o=s.fileinput,((e,t)=>0{i.unblock()}),(s=>{const o=URL.createObjectURL(s),r=()=>{i.unblock(),URL.revokeObjectURL(o)},n=s=>{i.setData({src:{value:s,meta:{}}}),i.showTab("general"),Me(e,t,a,i)};var l;(l=s,new Promise(((e,t)=>{const a=new FileReader;a.onload=()=>{e(a.result)},a.onerror=()=>{t(a.error?.message)},a.readAsDataURL(l)}))).then((a=>{const l=e.createBlobCache(s,o,a);t.automaticUploads?e.uploadImage(l).then((e=>{n(e.url),r()})).catch((t=>{r(),e.alertErr(t)})):(e.addToBlobCache(l),n(l.blobUri()),i.unblock())}))}))},ke=(e,t,a)=>(i,s)=>{"src"===s.name?Me(e,t,a,i):"images"===s.name?((e,t,a,i)=>{const s=i.getData(),o=Se(t.imageList,s.images);o.each((e=>{const t=""===s.alt||a.prevImage.map((e=>e.text===s.alt)).getOr(!1);t?""===e.value?i.setData({src:e,alt:a.prevAlt}):i.setData({src:e,alt:e.text}):i.setData({src:e})})),a.prevImage=o,Me(e,t,a,i)})(e,t,a,i):"alt"===s.name?a.prevAlt=i.getData().alt:"fileinput"===s.name?Re(e,t,a,i):"isDecorative"===s.name&&i.setEnabled("alt",!i.getData().isDecorative)},ze=e=>()=>{e.open=!1},Pe=e=>e.hasAdvTab||e.hasUploadUrl||e.hasUploadHandler?{type:"tabpanel",tabs:w([[Oe(e)],e.hasAdvTab?[{title:"Advanced",name:"advanced",items:[{type:"grid",columns:2,items:[{type:"input",label:"Vertical space",name:"vspace",inputMode:"numeric"},{type:"input",label:"Horizontal space",name:"hspace",inputMode:"numeric"},{type:"input",label:"Border width",name:"border",inputMode:"numeric"},{type:"listbox",name:"borderstyle",label:"Border style",items:[{text:"Select...",value:""},{text:"Solid",value:"solid"},{text:"Dotted",value:"dotted"},{text:"Dashed",value:"dashed"},{text:"Double",value:"double"},{text:"Groove",value:"groove"},{text:"Ridge",value:"ridge"},{text:"Inset",value:"inset"},{text:"Outset",value:"outset"},{text:"None",value:"none"},{text:"Hidden",value:"hidden"}]}]}]}]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}]:[]])}:{type:"panel",items:Le(e)},Be=(e,t,a)=>i=>{const s=fe(Ee(t.image),i.getData()),o={...s,style:le(a.normalizeCss,je(s,!1))};e.execCommand("mceUpdateImage",!1,je(o,t.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),i.close()},Fe=e=>t=>G(e,t)?(e=>new Promise((t=>{const a=document.createElement("img"),i=e=>{a.onload=a.onerror=null,a.parentNode&&a.parentNode.removeChild(a),t(e)};a.onload=()=>{const e={width:P(a.width,a.clientWidth),height:P(a.height,a.clientHeight)};i(Promise.resolve(e))},a.onerror=()=>{i(Promise.reject(`Failed to get image dimensions for: ${e}`))};const s=a.style;s.visibility="hidden",s.position="fixed",s.bottom=s.left="0px",s.width=s.height="auto",document.body.appendChild(a),a.src=e})))(e.documentBaseURI.toAbsolute(t)).then((e=>({width:String(e.width),height:String(e.height)}))):Promise.resolve({width:"",height:""}),He=e=>(t,a,i)=>e.editorUpload.blobCache.create({blob:t,blobUri:a,name:t.name?.replace(/\.[^\.]+$/,""),filename:t.name,base64:i.split(",")[1]}),Ge=e=>t=>{e.editorUpload.blobCache.add(t)},We=e=>t=>{e.windowManager.alert(t)},$e=e=>t=>ue(e,t),Ve=e=>t=>e.dom.parseStyle(t),Ke=e=>(t,a)=>e.dom.serializeStyle(t,a),Ze=e=>t=>Ae(e).upload([t],!1).then((e=>0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(e[0].error?.message):e[0])),qe=e=>{const t={imageSize:Fe(e),addToBlobCache:Ge(e),createBlobCache:He(e),alertErr:We(e),normalizeCss:$e(e),parseStyle:Ve(e),serializeStyle:Ke(e),uploadImage:Ze(e)};return{open:()=>{Ne(e).then((a=>{const i=(e=>({prevImage:Se(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}))(a);return{title:"Insert/Edit Image",size:"normal",body:Pe(a),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:Ee(a.image),onSubmit:Be(e,a,t),onChange:ke(t,a,i),onClose:ze(i)}})).then(e.windowManager.open)}}},Je=e=>{const t=e.attr("class");return d(t)&&/\bimage\b/.test(t)},Qe=e=>t=>{let a=t.length;const i=t=>{t.attr("contenteditable",e?"true":null)};for(;a--;){const s=t[a];Je(s)&&(s.attr("contenteditable",e?"false":null),De.each(s.getAll("figcaption"),i))}};e.add("image",(e=>{(e=>{const t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:e=>{const t=!1===e||o(e)||((e,t)=>{if(l(e)){for(let a=0,i=e.length;a{e.on("PreInit",(()=>{e.parser.addNodeFilter("figure",Qe(!0)),e.serializer.addNodeFilter("figure",Qe(!1))}))})(e),(e=>{e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:qe(e).open,onSetup:t=>(t.setActive(d(he(e))),e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind)}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:qe(e).open}),e.ui.registry.addContextMenu("image",{update:e=>oe(e)||"IMG"===e.nodeName&&!H(e)?["image"]:[]})})(e),(e=>{e.addCommand("mceImage",qe(e).open),e.addCommand("mceUpdateImage",((t,a)=>{e.undoManager.transact((()=>ve(e,a)))}))})(e)}))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/importcss/plugin.js b/lib/editor/tiny/js/tinymce/plugins/importcss/plugin.js
new file mode 100644
index 00000000000..250b8c4714c
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/importcss/plugin.js
@@ -0,0 +1,343 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ const hasProto = (v, constructor, predicate) => {
+ if (predicate(v, constructor.prototype)) {
+ return true;
+ } else {
+ return v.constructor?.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 isSimpleType = type => value => typeof value === type;
+ const isString = isType('string');
+ const isObject = isType('object');
+ const isArray = isType('array');
+ const isFunction = isSimpleType('function');
+
+ var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
+
+ var global$2 = tinymce.util.Tools.resolve('tinymce.EditorManager');
+
+ var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
+
+ var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
+
+ const option = name => editor => editor.options.get(name);
+ const register = editor => {
+ const registerOption = editor.options.register;
+ const filterProcessor = value => isString(value) || isFunction(value) || isObject(value);
+ registerOption('importcss_merge_classes', {
+ processor: 'boolean',
+ default: true
+ });
+ registerOption('importcss_exclusive', {
+ processor: 'boolean',
+ default: true
+ });
+ registerOption('importcss_selector_converter', { processor: 'function' });
+ registerOption('importcss_selector_filter', { processor: filterProcessor });
+ registerOption('importcss_file_filter', { processor: filterProcessor });
+ registerOption('importcss_groups', { processor: 'object[]' });
+ registerOption('importcss_append', {
+ processor: 'boolean',
+ default: false
+ });
+ };
+ const shouldMergeClasses = option('importcss_merge_classes');
+ const shouldImportExclusive = option('importcss_exclusive');
+ const getSelectorConverter = option('importcss_selector_converter');
+ const getSelectorFilter = option('importcss_selector_filter');
+ const getCssGroups = option('importcss_groups');
+ const shouldAppend = option('importcss_append');
+ const getFileFilter = option('importcss_file_filter');
+ const getSkin = option('skin');
+ const getSkinUrl = option('skin_url');
+
+ const nativePush = Array.prototype.push;
+ const map = (xs, f) => {
+ const len = xs.length;
+ const r = new Array(len);
+ for (let i = 0; i < len; i++) {
+ const x = xs[i];
+ r[i] = f(x, i);
+ }
+ return r;
+ };
+ 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 bind = (xs, f) => flatten(map(xs, f));
+
+ const generate = () => {
+ const ungroupedOrder = [];
+ const groupOrder = [];
+ const groups = {};
+ const addItemToGroup = (groupTitle, itemInfo) => {
+ if (groups[groupTitle]) {
+ groups[groupTitle].push(itemInfo);
+ } else {
+ groupOrder.push(groupTitle);
+ groups[groupTitle] = [itemInfo];
+ }
+ };
+ const addItem = itemInfo => {
+ ungroupedOrder.push(itemInfo);
+ };
+ const toFormats = () => {
+ const groupItems = bind(groupOrder, g => {
+ const items = groups[g];
+ return items.length === 0 ? [] : [{
+ title: g,
+ items
+ }];
+ });
+ return groupItems.concat(ungroupedOrder);
+ };
+ return {
+ addItemToGroup,
+ addItem,
+ toFormats
+ };
+ };
+
+ const internalEditorStyle = /^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/;
+ const removeCacheSuffix = url => {
+ const cacheSuffix = global$1.cacheSuffix;
+ if (isString(url)) {
+ url = url.replace('?' + cacheSuffix, '').replace('&' + cacheSuffix, '');
+ }
+ return url;
+ };
+ const isSkinContentCss = (editor, href) => {
+ const skin = getSkin(editor);
+ if (skin) {
+ const skinUrlBase = getSkinUrl(editor);
+ const skinUrl = skinUrlBase ? editor.documentBaseURI.toAbsolute(skinUrlBase) : global$2.baseURL + '/skins/ui/' + skin;
+ const contentSkinUrlPart = global$2.baseURL + '/skins/content/';
+ return href === skinUrl + '/content' + (editor.inline ? '.inline' : '') + '.min.css' || href.indexOf(contentSkinUrlPart) !== -1;
+ }
+ return false;
+ };
+ const compileFilter = filter => {
+ if (isString(filter)) {
+ return value => {
+ return value.indexOf(filter) !== -1;
+ };
+ } else if (filter instanceof RegExp) {
+ return value => {
+ return filter.test(value);
+ };
+ }
+ return filter;
+ };
+ const isCssImportRule = rule => rule.styleSheet;
+ const isCssPageRule = rule => rule.selectorText;
+ const getSelectors = (editor, doc, fileFilter) => {
+ const selectors = [];
+ const contentCSSUrls = {};
+ const append = (styleSheet, imported) => {
+ let href = styleSheet.href;
+ let rules;
+ href = removeCacheSuffix(href);
+ if (!href || fileFilter && !fileFilter(href, imported) || isSkinContentCss(editor, href)) {
+ return;
+ }
+ global.each(styleSheet.imports, styleSheet => {
+ append(styleSheet, true);
+ });
+ try {
+ rules = styleSheet.cssRules || styleSheet.rules;
+ } catch (e) {
+ }
+ global.each(rules, cssRule => {
+ if (isCssImportRule(cssRule)) {
+ append(cssRule.styleSheet, true);
+ } else if (isCssPageRule(cssRule)) {
+ global.each(cssRule.selectorText.split(','), selector => {
+ selectors.push(global.trim(selector));
+ });
+ }
+ });
+ };
+ global.each(editor.contentCSS, url => {
+ contentCSSUrls[url] = true;
+ });
+ if (!fileFilter) {
+ fileFilter = (href, imported) => {
+ return imported || contentCSSUrls[href];
+ };
+ }
+ try {
+ global.each(doc.styleSheets, styleSheet => {
+ append(styleSheet);
+ });
+ } catch (e) {
+ }
+ return selectors;
+ };
+ const defaultConvertSelectorToFormat = (editor, selectorText) => {
+ let format = {};
+ const selector = /^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(selectorText);
+ if (!selector) {
+ return;
+ }
+ const elementName = selector[1];
+ const classes = selector[2].substr(1).split('.').join(' ');
+ const inlineSelectorElements = global.makeMap('a,img');
+ if (selector[1]) {
+ format = { title: selectorText };
+ if (editor.schema.getTextBlockElements()[elementName]) {
+ format.block = elementName;
+ } else if (editor.schema.getBlockElements()[elementName] || inlineSelectorElements[elementName.toLowerCase()]) {
+ format.selector = elementName;
+ } else {
+ format.inline = elementName;
+ }
+ } else if (selector[2]) {
+ format = {
+ inline: 'span',
+ title: selectorText.substr(1),
+ classes
+ };
+ }
+ if (shouldMergeClasses(editor)) {
+ format.classes = classes;
+ } else {
+ format.attributes = { class: classes };
+ }
+ return format;
+ };
+ const getGroupsBySelector = (groups, selector) => {
+ return global.grep(groups, group => {
+ return !group.filter || group.filter(selector);
+ });
+ };
+ const compileUserDefinedGroups = groups => {
+ return global.map(groups, group => {
+ return global.extend({}, group, {
+ original: group,
+ selectors: {},
+ filter: compileFilter(group.filter)
+ });
+ });
+ };
+ const isExclusiveMode = (editor, group) => {
+ return group === null || shouldImportExclusive(editor);
+ };
+ const isUniqueSelector = (editor, selector, group, globallyUniqueSelectors) => {
+ return !(isExclusiveMode(editor, group) ? selector in globallyUniqueSelectors : selector in group.selectors);
+ };
+ const markUniqueSelector = (editor, selector, group, globallyUniqueSelectors) => {
+ if (isExclusiveMode(editor, group)) {
+ globallyUniqueSelectors[selector] = true;
+ } else {
+ group.selectors[selector] = true;
+ }
+ };
+ const convertSelectorToFormat = (editor, plugin, selector, group) => {
+ let selectorConverter;
+ const converter = getSelectorConverter(editor);
+ if (group && group.selector_converter) {
+ selectorConverter = group.selector_converter;
+ } else if (converter) {
+ selectorConverter = converter;
+ } else {
+ selectorConverter = () => {
+ return defaultConvertSelectorToFormat(editor, selector);
+ };
+ }
+ return selectorConverter.call(plugin, selector, group);
+ };
+ const setup = editor => {
+ editor.on('init', () => {
+ const model = generate();
+ const globallyUniqueSelectors = {};
+ const selectorFilter = compileFilter(getSelectorFilter(editor));
+ const groups = compileUserDefinedGroups(getCssGroups(editor));
+ const processSelector = (selector, group) => {
+ if (isUniqueSelector(editor, selector, group, globallyUniqueSelectors)) {
+ markUniqueSelector(editor, selector, group, globallyUniqueSelectors);
+ const format = convertSelectorToFormat(editor, editor.plugins.importcss, selector, group);
+ if (format) {
+ const formatName = format.name || global$3.DOM.uniqueId();
+ editor.formatter.register(formatName, format);
+ return {
+ title: format.title,
+ format: formatName
+ };
+ }
+ }
+ return null;
+ };
+ global.each(getSelectors(editor, editor.getDoc(), compileFilter(getFileFilter(editor))), selector => {
+ if (!internalEditorStyle.test(selector)) {
+ if (!selectorFilter || selectorFilter(selector)) {
+ const selectorGroups = getGroupsBySelector(groups, selector);
+ if (selectorGroups.length > 0) {
+ global.each(selectorGroups, group => {
+ const menuItem = processSelector(selector, group);
+ if (menuItem) {
+ model.addItemToGroup(group.title, menuItem);
+ }
+ });
+ } else {
+ const menuItem = processSelector(selector, null);
+ if (menuItem) {
+ model.addItem(menuItem);
+ }
+ }
+ }
+ }
+ });
+ const items = model.toFormats();
+ editor.dispatch('addStyleModifications', {
+ items,
+ replace: !shouldAppend(editor)
+ });
+ });
+ };
+
+ const get = editor => {
+ const convertSelectorToFormat = selectorText => {
+ return defaultConvertSelectorToFormat(editor, selectorText);
+ };
+ return { convertSelectorToFormat };
+ };
+
+ var Plugin = () => {
+ global$4.add('importcss', editor => {
+ register(editor);
+ setup(editor);
+ return get(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/importcss/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/importcss/plugin.min.js
new file mode 100644
index 00000000000..dc1ae1bc6c9
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/importcss/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||r.constructor?.name===o.name)?"string":t;var s,r,o})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),h=p("importcss_groups"),d=p("importcss_append"),_=p("importcss_file_filter"),g=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),w=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s{const s=e.length,r=new Array(s);for(let o=0;oa.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(h(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=g(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/";return t===o+"/content"+(e.inline?".inline":"")+".min.css"||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(_(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!d(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),w(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/insertdatetime/plugin.js b/lib/editor/tiny/js/tinymce/plugins/insertdatetime/plugin.js
new file mode 100644
index 00000000000..887058803a6
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/insertdatetime/plugin.js
@@ -0,0 +1,175 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ const option = name => editor => editor.options.get(name);
+ const register$2 = editor => {
+ const registerOption = editor.options.register;
+ registerOption('insertdatetime_dateformat', {
+ processor: 'string',
+ default: editor.translate('%Y-%m-%d')
+ });
+ registerOption('insertdatetime_timeformat', {
+ processor: 'string',
+ default: editor.translate('%H:%M:%S')
+ });
+ registerOption('insertdatetime_formats', {
+ processor: 'string[]',
+ default: [
+ '%H:%M:%S',
+ '%Y-%m-%d',
+ '%I:%M:%S %p',
+ '%D'
+ ]
+ });
+ registerOption('insertdatetime_element', {
+ processor: 'boolean',
+ default: false
+ });
+ };
+ const getDateFormat = option('insertdatetime_dateformat');
+ const getTimeFormat = option('insertdatetime_timeformat');
+ const getFormats = option('insertdatetime_formats');
+ const shouldInsertTimeElement = option('insertdatetime_element');
+ const getDefaultDateTime = editor => {
+ const formats = getFormats(editor);
+ return formats.length > 0 ? formats[0] : getTimeFormat(editor);
+ };
+
+ const daysShort = 'Sun Mon Tue Wed Thu Fri Sat Sun'.split(' ');
+ const daysLong = 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday'.split(' ');
+ const monthsShort = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
+ const monthsLong = 'January February March April May June July August September October November December'.split(' ');
+ const addZeros = (value, len) => {
+ value = '' + value;
+ if (value.length < len) {
+ for (let i = 0; i < len - value.length; i++) {
+ value = '0' + value;
+ }
+ }
+ return value;
+ };
+ const getDateTime = (editor, fmt, date = new Date()) => {
+ fmt = fmt.replace('%D', '%m/%d/%Y');
+ fmt = fmt.replace('%r', '%I:%M:%S %p');
+ fmt = fmt.replace('%Y', '' + date.getFullYear());
+ fmt = fmt.replace('%y', '' + date.getYear());
+ fmt = fmt.replace('%m', addZeros(date.getMonth() + 1, 2));
+ fmt = fmt.replace('%d', addZeros(date.getDate(), 2));
+ fmt = fmt.replace('%H', '' + addZeros(date.getHours(), 2));
+ fmt = fmt.replace('%M', '' + addZeros(date.getMinutes(), 2));
+ fmt = fmt.replace('%S', '' + addZeros(date.getSeconds(), 2));
+ fmt = fmt.replace('%I', '' + ((date.getHours() + 11) % 12 + 1));
+ fmt = fmt.replace('%p', '' + (date.getHours() < 12 ? 'AM' : 'PM'));
+ fmt = fmt.replace('%B', '' + editor.translate(monthsLong[date.getMonth()]));
+ fmt = fmt.replace('%b', '' + editor.translate(monthsShort[date.getMonth()]));
+ fmt = fmt.replace('%A', '' + editor.translate(daysLong[date.getDay()]));
+ fmt = fmt.replace('%a', '' + editor.translate(daysShort[date.getDay()]));
+ fmt = fmt.replace('%%', '%');
+ return fmt;
+ };
+ const updateElement = (editor, timeElm, computerTime, userTime) => {
+ const newTimeElm = editor.dom.create('time', { datetime: computerTime }, userTime);
+ editor.dom.replace(newTimeElm, timeElm);
+ editor.selection.select(newTimeElm, true);
+ editor.selection.collapse(false);
+ };
+ const insertDateTime = (editor, format) => {
+ if (shouldInsertTimeElement(editor)) {
+ const userTime = getDateTime(editor, format);
+ let computerTime;
+ if (/%[HMSIp]/.test(format)) {
+ computerTime = getDateTime(editor, '%Y-%m-%dT%H:%M');
+ } else {
+ computerTime = getDateTime(editor, '%Y-%m-%d');
+ }
+ const timeElm = editor.dom.getParent(editor.selection.getStart(), 'time');
+ if (timeElm) {
+ updateElement(editor, timeElm, computerTime, userTime);
+ } else {
+ editor.insertContent('' + userTime + ' ');
+ }
+ } else {
+ editor.insertContent(getDateTime(editor, format));
+ }
+ };
+
+ const register$1 = editor => {
+ editor.addCommand('mceInsertDate', (_ui, value) => {
+ insertDateTime(editor, value ?? getDateFormat(editor));
+ });
+ editor.addCommand('mceInsertTime', (_ui, value) => {
+ insertDateTime(editor, value ?? getTimeFormat(editor));
+ });
+ };
+
+ const Cell = initial => {
+ let value = initial;
+ const get = () => {
+ return value;
+ };
+ const set = v => {
+ value = v;
+ };
+ return {
+ get,
+ set
+ };
+ };
+
+ var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
+
+ const register = editor => {
+ const formats = getFormats(editor);
+ const defaultFormat = Cell(getDefaultDateTime(editor));
+ const insertDateTime = format => editor.execCommand('mceInsertDate', false, format);
+ editor.ui.registry.addSplitButton('insertdatetime', {
+ icon: 'insert-time',
+ tooltip: 'Insert date/time',
+ select: value => value === defaultFormat.get(),
+ fetch: done => {
+ done(global.map(formats, format => ({
+ type: 'choiceitem',
+ text: getDateTime(editor, format),
+ value: format
+ })));
+ },
+ onAction: _api => {
+ insertDateTime(defaultFormat.get());
+ },
+ onItemAction: (_api, value) => {
+ defaultFormat.set(value);
+ insertDateTime(value);
+ }
+ });
+ const makeMenuItemHandler = format => () => {
+ defaultFormat.set(format);
+ insertDateTime(format);
+ };
+ editor.ui.registry.addNestedMenuItem('insertdatetime', {
+ icon: 'insert-time',
+ text: 'Date/time',
+ getSubmenuItems: () => global.map(formats, format => ({
+ type: 'menuitem',
+ text: getDateTime(editor, format),
+ onAction: makeMenuItemHandler(format)
+ }))
+ });
+ };
+
+ var Plugin = () => {
+ global$1.add('insertdatetime', editor => {
+ register$2(editor);
+ register$1(editor);
+ register(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/insertdatetime/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/insertdatetime/plugin.min.js
new file mode 100644
index 00000000000..e2050964e81
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/insertdatetime/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),r=t("insertdatetime_timeformat"),n=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),m="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),l="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(l[a.getMonth()]))).replace("%b",""+e.translate(m[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let r;r=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const n=e.dom.getParent(e.selection.getStart(),"time");n?((e,t,a,r)=>{const n=e.dom.create("time",{datetime:a},r);e.dom.replace(n,t),e.selection.select(n,!0),e.selection.collapse(!1)})(e,n,r,a):e.insertContent(''+a+" ")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,r)=>{u(e,r??a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,a??r(e))}))})(e),(e=>{const t=n(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=n(e);return t.length>0?t[0]:r(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)}});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)})))})})(e)}))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/link/plugin.js b/lib/editor/tiny/js/tinymce/plugins/link/plugin.js
new file mode 100644
index 00000000000..e87d4ffda14
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/link/plugin.js
@@ -0,0 +1,1194 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ var global$5 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ const hasProto = (v, constructor, predicate) => {
+ if (predicate(v, constructor.prototype)) {
+ return true;
+ } else {
+ return v.constructor?.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 isSimpleType = type => value => typeof value === type;
+ const eq = t => a => t === a;
+ const isString = isType('string');
+ const isObject = isType('object');
+ const isArray = isType('array');
+ const isNull = eq(null);
+ const isBoolean = isSimpleType('boolean');
+ const isNullable = a => a === null || a === undefined;
+ const isNonNullable = a => !isNullable(a);
+ const isFunction = isSimpleType('function');
+ const isArrayOf = (value, pred) => {
+ if (isArray(value)) {
+ for (let i = 0, len = value.length; i < len; ++i) {
+ if (!pred(value[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+
+ const noop = () => {
+ };
+ const constant = value => {
+ return () => {
+ return value;
+ };
+ };
+ const tripleEquals = (a, b) => {
+ return a === b;
+ };
+
+ 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 ?? '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 nativeIndexOf = Array.prototype.indexOf;
+ const nativePush = Array.prototype.push;
+ const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
+ const contains = (xs, x) => rawIndexOf(xs, x) > -1;
+ const map = (xs, f) => {
+ const len = xs.length;
+ const r = new Array(len);
+ for (let i = 0; i < len; i++) {
+ const x = xs[i];
+ r[i] = f(x, i);
+ }
+ return r;
+ };
+ const each$1 = (xs, f) => {
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ f(x, i);
+ }
+ };
+ const foldl = (xs, f, acc) => {
+ each$1(xs, (x, i) => {
+ acc = f(acc, x, i);
+ });
+ return acc;
+ };
+ 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 bind = (xs, f) => flatten(map(xs, f));
+ const findMap = (arr, f) => {
+ for (let i = 0; i < arr.length; i++) {
+ const r = f(arr[i], i);
+ if (r.isSome()) {
+ return r;
+ }
+ }
+ return Optional.none();
+ };
+
+ const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
+ const cat = arr => {
+ const r = [];
+ const push = x => {
+ r.push(x);
+ };
+ for (let i = 0; i < arr.length; i++) {
+ arr[i].each(push);
+ }
+ return r;
+ };
+ const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
+
+ const option = name => editor => editor.options.get(name);
+ const register$1 = editor => {
+ const registerOption = editor.options.register;
+ registerOption('link_assume_external_targets', {
+ processor: value => {
+ const valid = isString(value) || isBoolean(value);
+ if (valid) {
+ if (value === true) {
+ return {
+ value: 1,
+ valid
+ };
+ } else if (value === 'http' || value === 'https') {
+ return {
+ value,
+ valid
+ };
+ } else {
+ return {
+ value: 0,
+ valid
+ };
+ }
+ } else {
+ return {
+ valid: false,
+ message: 'Must be a string or a boolean.'
+ };
+ }
+ },
+ default: false
+ });
+ registerOption('link_context_toolbar', {
+ processor: 'boolean',
+ default: false
+ });
+ registerOption('link_list', { processor: value => isString(value) || isFunction(value) || isArrayOf(value, isObject) });
+ registerOption('link_default_target', { processor: 'string' });
+ registerOption('link_default_protocol', {
+ processor: 'string',
+ default: 'https'
+ });
+ registerOption('link_target_list', {
+ processor: value => isBoolean(value) || isArrayOf(value, isObject),
+ default: true
+ });
+ registerOption('link_rel_list', {
+ processor: 'object[]',
+ default: []
+ });
+ registerOption('link_class_list', {
+ processor: 'object[]',
+ default: []
+ });
+ registerOption('link_title', {
+ processor: 'boolean',
+ default: true
+ });
+ registerOption('allow_unsafe_link_target', {
+ processor: 'boolean',
+ default: false
+ });
+ registerOption('link_quicklink', {
+ processor: 'boolean',
+ default: false
+ });
+ };
+ const assumeExternalTargets = option('link_assume_external_targets');
+ const hasContextToolbar = option('link_context_toolbar');
+ const getLinkList = option('link_list');
+ const getDefaultLinkTarget = option('link_default_target');
+ const getDefaultLinkProtocol = option('link_default_protocol');
+ const getTargetList = option('link_target_list');
+ const getRelList = option('link_rel_list');
+ const getLinkClassList = option('link_class_list');
+ const shouldShowLinkTitle = option('link_title');
+ const allowUnsafeLinkTarget = option('allow_unsafe_link_target');
+ const useQuickLink = option('link_quicklink');
+
+ var global$4 = tinymce.util.Tools.resolve('tinymce.util.Tools');
+
+ const getValue = item => isString(item.value) ? item.value : '';
+ const getText = item => {
+ if (isString(item.text)) {
+ return item.text;
+ } else if (isString(item.title)) {
+ return item.title;
+ } else {
+ return '';
+ }
+ };
+ const sanitizeList = (list, extractValue) => {
+ const out = [];
+ global$4.each(list, item => {
+ const text = getText(item);
+ if (item.menu !== undefined) {
+ const items = sanitizeList(item.menu, extractValue);
+ out.push({
+ text,
+ items
+ });
+ } else {
+ const value = extractValue(item);
+ out.push({
+ text,
+ value
+ });
+ }
+ });
+ return out;
+ };
+ const sanitizeWith = (extracter = getValue) => list => Optional.from(list).map(list => sanitizeList(list, extracter));
+ const sanitize = list => sanitizeWith(getValue)(list);
+ const createUi = (name, label) => items => ({
+ name,
+ type: 'listbox',
+ label,
+ items
+ });
+ const ListOptions = {
+ sanitize,
+ sanitizeWith,
+ createUi,
+ getValue
+ };
+
+ 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 objAcc = r => (x, i) => {
+ r[i] = x;
+ };
+ const internalFilter = (obj, pred, onTrue, onFalse) => {
+ each(obj, (x, i) => {
+ (pred(x, i) ? onTrue : onFalse)(x, i);
+ });
+ };
+ const filter = (obj, pred) => {
+ const t = {};
+ internalFilter(obj, pred, objAcc(t), noop);
+ return t;
+ };
+ const has = (obj, key) => hasOwnProperty.call(obj, key);
+ const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;
+
+ var global$3 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
+
+ var global$2 = tinymce.util.Tools.resolve('tinymce.util.URI');
+
+ const isAnchor = elm => isNonNullable(elm) && elm.nodeName.toLowerCase() === 'a';
+ const isLink = elm => isAnchor(elm) && !!getHref(elm);
+ const collectNodesInRange = (rng, predicate) => {
+ if (rng.collapsed) {
+ return [];
+ } else {
+ const contents = rng.cloneContents();
+ const firstChild = contents.firstChild;
+ const walker = new global$3(firstChild, contents);
+ const elements = [];
+ let current = firstChild;
+ do {
+ if (predicate(current)) {
+ elements.push(current);
+ }
+ } while (current = walker.next());
+ return elements;
+ }
+ };
+ const hasProtocol = url => /^\w+:/i.test(url);
+ const getHref = elm => {
+ return elm.getAttribute('data-mce-href') ?? elm.getAttribute('href') ?? '';
+ };
+ const applyRelTargetRules = (rel, isUnsafe) => {
+ const rules = ['noopener'];
+ const rels = rel ? rel.split(/\s+/) : [];
+ const toString = rels => global$4.trim(rels.sort().join(' '));
+ const addTargetRules = rels => {
+ rels = removeTargetRules(rels);
+ return rels.length > 0 ? rels.concat(rules) : rules;
+ };
+ const removeTargetRules = rels => rels.filter(val => global$4.inArray(rules, val) === -1);
+ const newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
+ return newRels.length > 0 ? toString(newRels) : '';
+ };
+ const trimCaretContainers = text => text.replace(/\uFEFF/g, '');
+ const getAnchorElement = (editor, selectedElm) => {
+ selectedElm = selectedElm || editor.selection.getNode();
+ if (isImageFigure(selectedElm)) {
+ return Optional.from(editor.dom.select('a[href]', selectedElm)[0]);
+ } else {
+ return Optional.from(editor.dom.getParent(selectedElm, 'a[href]'));
+ }
+ };
+ const isInAnchor = (editor, selectedElm) => getAnchorElement(editor, selectedElm).isSome();
+ const getAnchorText = (selection, anchorElm) => {
+ const text = anchorElm.fold(() => selection.getContent({ format: 'text' }), anchorElm => anchorElm.innerText || anchorElm.textContent || '');
+ return trimCaretContainers(text);
+ };
+ const hasLinks = elements => global$4.grep(elements, isLink).length > 0;
+ const hasLinksInSelection = rng => collectNodesInRange(rng, isLink).length > 0;
+ const isOnlyTextSelected = editor => {
+ const inlineTextElements = editor.schema.getTextInlineElements();
+ const isElement = elm => elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
+ const elements = collectNodesInRange(editor.selection.getRng(), isElement);
+ return elements.length === 0;
+ };
+ const isImageFigure = elm => isNonNullable(elm) && elm.nodeName === 'FIGURE' && /\bimage\b/i.test(elm.className);
+ const getLinkAttrs = data => {
+ const attrs = [
+ 'title',
+ 'rel',
+ 'class',
+ 'target'
+ ];
+ return foldl(attrs, (acc, key) => {
+ data[key].each(value => {
+ acc[key] = value.length > 0 ? value : null;
+ });
+ return acc;
+ }, { href: data.href });
+ };
+ const handleExternalTargets = (href, assumeExternalTargets) => {
+ if ((assumeExternalTargets === 'http' || assumeExternalTargets === 'https') && !hasProtocol(href)) {
+ return assumeExternalTargets + '://' + href;
+ }
+ return href;
+ };
+ const applyLinkOverrides = (editor, linkAttrs) => {
+ const newLinkAttrs = { ...linkAttrs };
+ if (getRelList(editor).length === 0 && !allowUnsafeLinkTarget(editor)) {
+ const newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === '_blank');
+ newLinkAttrs.rel = newRel ? newRel : null;
+ }
+ if (Optional.from(newLinkAttrs.target).isNone() && getTargetList(editor) === false) {
+ newLinkAttrs.target = getDefaultLinkTarget(editor);
+ }
+ newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
+ return newLinkAttrs;
+ };
+ const updateLink = (editor, anchorElm, text, linkAttrs) => {
+ text.each(text => {
+ if (has(anchorElm, 'innerText')) {
+ anchorElm.innerText = text;
+ } else {
+ anchorElm.textContent = text;
+ }
+ });
+ editor.dom.setAttribs(anchorElm, linkAttrs);
+ editor.selection.select(anchorElm);
+ };
+ const createLink = (editor, selectedElm, text, linkAttrs) => {
+ const dom = editor.dom;
+ if (isImageFigure(selectedElm)) {
+ linkImageFigure(dom, selectedElm, linkAttrs);
+ } else {
+ text.fold(() => {
+ editor.execCommand('mceInsertLink', false, linkAttrs);
+ }, text => {
+ editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(text)));
+ });
+ }
+ };
+ const linkDomMutation = (editor, attachState, data) => {
+ const selectedElm = editor.selection.getNode();
+ const anchorElm = getAnchorElement(editor, selectedElm);
+ const linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
+ editor.undoManager.transact(() => {
+ if (data.href === attachState.href) {
+ attachState.attach();
+ }
+ anchorElm.fold(() => {
+ createLink(editor, selectedElm, data.text, linkAttrs);
+ }, elm => {
+ editor.focus();
+ updateLink(editor, elm, data.text, linkAttrs);
+ });
+ });
+ };
+ const unlinkSelection = editor => {
+ const dom = editor.dom, selection = editor.selection;
+ const bookmark = selection.getBookmark();
+ const rng = selection.getRng().cloneRange();
+ const startAnchorElm = dom.getParent(rng.startContainer, 'a[href]', editor.getBody());
+ const endAnchorElm = dom.getParent(rng.endContainer, 'a[href]', editor.getBody());
+ if (startAnchorElm) {
+ rng.setStartBefore(startAnchorElm);
+ }
+ if (endAnchorElm) {
+ rng.setEndAfter(endAnchorElm);
+ }
+ selection.setRng(rng);
+ editor.execCommand('unlink');
+ selection.moveToBookmark(bookmark);
+ };
+ const unlinkDomMutation = editor => {
+ editor.undoManager.transact(() => {
+ const node = editor.selection.getNode();
+ if (isImageFigure(node)) {
+ unlinkImageFigure(editor, node);
+ } else {
+ unlinkSelection(editor);
+ }
+ editor.focus();
+ });
+ };
+ const unwrapOptions = data => {
+ const {
+ class: cls,
+ href,
+ rel,
+ target,
+ text,
+ title
+ } = data;
+ return filter({
+ class: cls.getOrNull(),
+ href,
+ rel: rel.getOrNull(),
+ target: target.getOrNull(),
+ text: text.getOrNull(),
+ title: title.getOrNull()
+ }, (v, _k) => isNull(v) === false);
+ };
+ const sanitizeData = (editor, data) => {
+ const getOption = editor.options.get;
+ const uriOptions = {
+ allow_html_data_urls: getOption('allow_html_data_urls'),
+ allow_script_urls: getOption('allow_script_urls'),
+ allow_svg_data_urls: getOption('allow_svg_data_urls')
+ };
+ const href = data.href;
+ return {
+ ...data,
+ href: global$2.isDomSafe(href, 'a', uriOptions) ? href : ''
+ };
+ };
+ const link = (editor, attachState, data) => {
+ const sanitizedData = sanitizeData(editor, data);
+ editor.hasPlugin('rtc', true) ? editor.execCommand('createlink', false, unwrapOptions(sanitizedData)) : linkDomMutation(editor, attachState, sanitizedData);
+ };
+ const unlink = editor => {
+ editor.hasPlugin('rtc', true) ? editor.execCommand('unlink') : unlinkDomMutation(editor);
+ };
+ const unlinkImageFigure = (editor, fig) => {
+ const img = editor.dom.select('img', fig)[0];
+ if (img) {
+ const a = editor.dom.getParents(img, 'a[href]', fig)[0];
+ if (a) {
+ a.parentNode?.insertBefore(img, a);
+ editor.dom.remove(a);
+ }
+ }
+ };
+ const linkImageFigure = (dom, fig, attrs) => {
+ const img = dom.select('img', fig)[0];
+ if (img) {
+ const a = dom.create('a', attrs);
+ img.parentNode?.insertBefore(a, img);
+ a.appendChild(img);
+ }
+ };
+
+ const isListGroup = item => hasNonNullableKey(item, 'items');
+ const findTextByValue = (value, catalog) => findMap(catalog, item => {
+ if (isListGroup(item)) {
+ return findTextByValue(value, item.items);
+ } else {
+ return someIf(item.value === value, item);
+ }
+ });
+ const getDelta = (persistentText, fieldName, catalog, data) => {
+ const value = data[fieldName];
+ const hasPersistentText = persistentText.length > 0;
+ return value !== undefined ? findTextByValue(value, catalog).map(i => ({
+ url: {
+ value: i.value,
+ meta: {
+ text: hasPersistentText ? persistentText : i.text,
+ attach: noop
+ }
+ },
+ text: hasPersistentText ? persistentText : i.text
+ })) : Optional.none();
+ };
+ const findCatalog = (catalogs, fieldName) => {
+ if (fieldName === 'link') {
+ return catalogs.link;
+ } else if (fieldName === 'anchor') {
+ return catalogs.anchor;
+ } else {
+ return Optional.none();
+ }
+ };
+ const init = (initialData, linkCatalog) => {
+ const persistentData = {
+ text: initialData.text,
+ title: initialData.title
+ };
+ const getTitleFromUrlChange = url => someIf(persistentData.title.length <= 0, Optional.from(url.meta?.title).getOr(''));
+ const getTextFromUrlChange = url => someIf(persistentData.text.length <= 0, Optional.from(url.meta?.text).getOr(url.value));
+ const onUrlChange = data => {
+ const text = getTextFromUrlChange(data.url);
+ const title = getTitleFromUrlChange(data.url);
+ if (text.isSome() || title.isSome()) {
+ return Optional.some({
+ ...text.map(text => ({ text })).getOr({}),
+ ...title.map(title => ({ title })).getOr({})
+ });
+ } else {
+ return Optional.none();
+ }
+ };
+ const onCatalogChange = (data, change) => {
+ const catalog = findCatalog(linkCatalog, change).getOr([]);
+ return getDelta(persistentData.text, change, catalog, data);
+ };
+ const onChange = (getData, change) => {
+ const name = change.name;
+ if (name === 'url') {
+ return onUrlChange(getData());
+ } else if (contains([
+ 'anchor',
+ 'link'
+ ], name)) {
+ return onCatalogChange(getData(), name);
+ } else if (name === 'text' || name === 'title') {
+ persistentData[name] = getData()[name];
+ return Optional.none();
+ } else {
+ return Optional.none();
+ }
+ };
+ return { onChange };
+ };
+ const DialogChanges = {
+ init,
+ getDelta
+ };
+
+ var global$1 = tinymce.util.Tools.resolve('tinymce.util.Delay');
+
+ const delayedConfirm = (editor, message, callback) => {
+ const rng = editor.selection.getRng();
+ global$1.setEditorTimeout(editor, () => {
+ editor.windowManager.confirm(message, state => {
+ editor.selection.setRng(rng);
+ callback(state);
+ });
+ });
+ };
+ const tryEmailTransform = data => {
+ const url = data.href;
+ const suggestMailTo = url.indexOf('@') > 0 && url.indexOf('/') === -1 && url.indexOf('mailto:') === -1;
+ return suggestMailTo ? Optional.some({
+ message: 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
+ preprocess: oldData => ({
+ ...oldData,
+ href: 'mailto:' + url
+ })
+ }) : Optional.none();
+ };
+ const tryProtocolTransform = (assumeExternalTargets, defaultLinkProtocol) => data => {
+ const url = data.href;
+ const suggestProtocol = assumeExternalTargets === 1 && !hasProtocol(url) || assumeExternalTargets === 0 && /^\s*www(\.|\d\.)/i.test(url);
+ return suggestProtocol ? Optional.some({
+ message: `The URL you entered seems to be an external link. Do you want to add the required ${ defaultLinkProtocol }:// prefix?`,
+ preprocess: oldData => ({
+ ...oldData,
+ href: defaultLinkProtocol + '://' + url
+ })
+ }) : Optional.none();
+ };
+ const preprocess = (editor, data) => findMap([
+ tryEmailTransform,
+ tryProtocolTransform(assumeExternalTargets(editor), getDefaultLinkProtocol(editor))
+ ], f => f(data)).fold(() => Promise.resolve(data), transform => new Promise(callback => {
+ delayedConfirm(editor, transform.message, state => {
+ callback(state ? transform.preprocess(data) : data);
+ });
+ }));
+ const DialogConfirms = { preprocess };
+
+ const getAnchors = editor => {
+ const anchorNodes = editor.dom.select('a:not([href])');
+ const anchors = bind(anchorNodes, anchor => {
+ const id = anchor.name || anchor.id;
+ return id ? [{
+ text: id,
+ value: '#' + id
+ }] : [];
+ });
+ return anchors.length > 0 ? Optional.some([{
+ text: 'None',
+ value: ''
+ }].concat(anchors)) : Optional.none();
+ };
+ const AnchorListOptions = { getAnchors };
+
+ const getClasses = editor => {
+ const list = getLinkClassList(editor);
+ if (list.length > 0) {
+ return ListOptions.sanitize(list);
+ }
+ return Optional.none();
+ };
+ const ClassListOptions = { getClasses };
+
+ const parseJson = text => {
+ try {
+ return Optional.some(JSON.parse(text));
+ } catch (err) {
+ return Optional.none();
+ }
+ };
+ const getLinks = editor => {
+ const extractor = item => editor.convertURL(item.value || item.url || '', 'href');
+ const linkList = getLinkList(editor);
+ return new Promise(resolve => {
+ if (isString(linkList)) {
+ fetch(linkList).then(res => res.ok ? res.text().then(parseJson) : Promise.reject()).then(resolve, () => resolve(Optional.none()));
+ } else if (isFunction(linkList)) {
+ linkList(output => resolve(Optional.some(output)));
+ } else {
+ resolve(Optional.from(linkList));
+ }
+ }).then(optItems => optItems.bind(ListOptions.sanitizeWith(extractor)).map(items => {
+ if (items.length > 0) {
+ const noneItem = [{
+ text: 'None',
+ value: ''
+ }];
+ return noneItem.concat(items);
+ } else {
+ return items;
+ }
+ }));
+ };
+ const LinkListOptions = { getLinks };
+
+ const getRels = (editor, initialTarget) => {
+ const list = getRelList(editor);
+ if (list.length > 0) {
+ const isTargetBlank = is(initialTarget, '_blank');
+ const enforceSafe = allowUnsafeLinkTarget(editor) === false;
+ const safeRelExtractor = item => applyRelTargetRules(ListOptions.getValue(item), isTargetBlank);
+ const sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
+ return sanitizer(list);
+ }
+ return Optional.none();
+ };
+ const RelOptions = { getRels };
+
+ const fallbacks = [
+ {
+ text: 'Current window',
+ value: ''
+ },
+ {
+ text: 'New window',
+ value: '_blank'
+ }
+ ];
+ const getTargets = editor => {
+ const list = getTargetList(editor);
+ if (isArray(list)) {
+ return ListOptions.sanitize(list).orThunk(() => Optional.some(fallbacks));
+ } else if (list === false) {
+ return Optional.none();
+ }
+ return Optional.some(fallbacks);
+ };
+ const TargetOptions = { getTargets };
+
+ const nonEmptyAttr = (dom, elem, name) => {
+ const val = dom.getAttrib(elem, name);
+ return val !== null && val.length > 0 ? Optional.some(val) : Optional.none();
+ };
+ const extractFromAnchor = (editor, anchor) => {
+ const dom = editor.dom;
+ const onlyText = isOnlyTextSelected(editor);
+ const text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)) : Optional.none();
+ const url = anchor.bind(anchorElm => Optional.from(dom.getAttrib(anchorElm, 'href')));
+ const target = anchor.bind(anchorElm => Optional.from(dom.getAttrib(anchorElm, 'target')));
+ const rel = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, 'rel'));
+ const linkClass = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, 'class'));
+ const title = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, 'title'));
+ return {
+ url,
+ text,
+ title,
+ target,
+ rel,
+ linkClass
+ };
+ };
+ const collect = (editor, linkNode) => LinkListOptions.getLinks(editor).then(links => {
+ const anchor = extractFromAnchor(editor, linkNode);
+ return {
+ anchor,
+ catalogs: {
+ targets: TargetOptions.getTargets(editor),
+ rels: RelOptions.getRels(editor, anchor.target),
+ classes: ClassListOptions.getClasses(editor),
+ anchor: AnchorListOptions.getAnchors(editor),
+ link: links
+ },
+ optNode: linkNode,
+ flags: { titleEnabled: shouldShowLinkTitle(editor) }
+ };
+ });
+ const DialogInfo = { collect };
+
+ const handleSubmit = (editor, info) => api => {
+ const data = api.getData();
+ if (!data.url.value) {
+ unlink(editor);
+ api.close();
+ return;
+ }
+ const getChangedValue = key => Optional.from(data[key]).filter(value => !is(info.anchor[key], value));
+ const changedData = {
+ href: data.url.value,
+ text: getChangedValue('text'),
+ target: getChangedValue('target'),
+ rel: getChangedValue('rel'),
+ class: getChangedValue('linkClass'),
+ title: getChangedValue('title')
+ };
+ const attachState = {
+ href: data.url.value,
+ attach: data.url.meta !== undefined && data.url.meta.attach ? data.url.meta.attach : noop
+ };
+ DialogConfirms.preprocess(editor, changedData).then(pData => {
+ link(editor, attachState, pData);
+ });
+ api.close();
+ };
+ const collectData = editor => {
+ const anchorNode = getAnchorElement(editor);
+ return DialogInfo.collect(editor, anchorNode);
+ };
+ const getInitialData = (info, defaultTarget) => {
+ const anchor = info.anchor;
+ const url = anchor.url.getOr('');
+ return {
+ url: {
+ value: url,
+ meta: { original: { value: url } }
+ },
+ text: anchor.text.getOr(''),
+ title: anchor.title.getOr(''),
+ anchor: url,
+ link: url,
+ rel: anchor.rel.getOr(''),
+ target: anchor.target.or(defaultTarget).getOr(''),
+ linkClass: anchor.linkClass.getOr('')
+ };
+ };
+ const makeDialog = (settings, onSubmit, editor) => {
+ const urlInput = [{
+ name: 'url',
+ type: 'urlinput',
+ filetype: 'file',
+ label: 'URL'
+ }];
+ const displayText = settings.anchor.text.map(() => ({
+ name: 'text',
+ type: 'input',
+ label: 'Text to display'
+ })).toArray();
+ const titleText = settings.flags.titleEnabled ? [{
+ name: 'title',
+ type: 'input',
+ label: 'Title'
+ }] : [];
+ const defaultTarget = Optional.from(getDefaultLinkTarget(editor));
+ const initialData = getInitialData(settings, defaultTarget);
+ const catalogs = settings.catalogs;
+ const dialogDelta = DialogChanges.init(initialData, catalogs);
+ const body = {
+ type: 'panel',
+ items: flatten([
+ urlInput,
+ displayText,
+ titleText,
+ cat([
+ catalogs.anchor.map(ListOptions.createUi('anchor', 'Anchors')),
+ catalogs.rels.map(ListOptions.createUi('rel', 'Rel')),
+ catalogs.targets.map(ListOptions.createUi('target', 'Open link in...')),
+ catalogs.link.map(ListOptions.createUi('link', 'Link list')),
+ catalogs.classes.map(ListOptions.createUi('linkClass', 'Class'))
+ ])
+ ])
+ };
+ return {
+ title: 'Insert/Edit Link',
+ size: 'normal',
+ body,
+ buttons: [
+ {
+ type: 'cancel',
+ name: 'cancel',
+ text: 'Cancel'
+ },
+ {
+ type: 'submit',
+ name: 'save',
+ text: 'Save',
+ primary: true
+ }
+ ],
+ initialData,
+ onChange: (api, {name}) => {
+ dialogDelta.onChange(api.getData, { name }).each(newData => {
+ api.setData(newData);
+ });
+ },
+ onSubmit
+ };
+ };
+ const open$1 = editor => {
+ const data = collectData(editor);
+ data.then(info => {
+ const onSubmit = handleSubmit(editor, info);
+ return makeDialog(info, onSubmit, editor);
+ }).then(spec => {
+ editor.windowManager.open(spec);
+ });
+ };
+
+ const register = editor => {
+ editor.addCommand('mceLink', (_ui, value) => {
+ if (value?.dialog === true || !useQuickLink(editor)) {
+ open$1(editor);
+ } else {
+ editor.dispatch('contexttoolbar-show', { toolbarKey: 'quicklink' });
+ }
+ });
+ };
+
+ var global = tinymce.util.Tools.resolve('tinymce.util.VK');
+
+ const appendClickRemove = (link, evt) => {
+ document.body.appendChild(link);
+ link.dispatchEvent(evt);
+ document.body.removeChild(link);
+ };
+ const open = url => {
+ const link = document.createElement('a');
+ link.target = '_blank';
+ link.href = url;
+ link.rel = 'noreferrer noopener';
+ const evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ appendClickRemove(link, evt);
+ };
+
+ const getLink = (editor, elm) => editor.dom.getParent(elm, 'a[href]');
+ const getSelectedLink = editor => getLink(editor, editor.selection.getStart());
+ const hasOnlyAltModifier = e => {
+ return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
+ };
+ const gotoLink = (editor, a) => {
+ if (a) {
+ const href = getHref(a);
+ if (/^#/.test(href)) {
+ const targetEl = editor.dom.select(href);
+ if (targetEl.length) {
+ editor.selection.scrollIntoView(targetEl[0], true);
+ }
+ } else {
+ open(a.href);
+ }
+ }
+ };
+ const openDialog = editor => () => {
+ editor.execCommand('mceLink', false, { dialog: true });
+ };
+ const gotoSelectedLink = editor => () => {
+ gotoLink(editor, getSelectedLink(editor));
+ };
+ const setupGotoLinks = editor => {
+ editor.on('click', e => {
+ const link = getLink(editor, e.target);
+ if (link && global.metaKeyPressed(e)) {
+ e.preventDefault();
+ gotoLink(editor, link);
+ }
+ });
+ editor.on('keydown', e => {
+ if (!e.isDefaultPrevented() && e.keyCode === 13 && hasOnlyAltModifier(e)) {
+ const link = getSelectedLink(editor);
+ if (link) {
+ e.preventDefault();
+ gotoLink(editor, link);
+ }
+ }
+ });
+ };
+ const toggleState = (editor, toggler) => {
+ editor.on('NodeChange', toggler);
+ return () => editor.off('NodeChange', toggler);
+ };
+ const toggleActiveState = editor => api => {
+ const updateState = () => api.setActive(!editor.mode.isReadOnly() && isInAnchor(editor, editor.selection.getNode()));
+ updateState();
+ return toggleState(editor, updateState);
+ };
+ const toggleEnabledState = editor => api => {
+ const updateState = () => api.setEnabled(isInAnchor(editor, editor.selection.getNode()));
+ updateState();
+ return toggleState(editor, updateState);
+ };
+ const toggleUnlinkState = editor => api => {
+ const hasLinks$1 = parents => hasLinks(parents) || hasLinksInSelection(editor.selection.getRng());
+ const parents = editor.dom.getParents(editor.selection.getStart());
+ api.setEnabled(hasLinks$1(parents));
+ return toggleState(editor, e => api.setEnabled(hasLinks$1(e.parents)));
+ };
+
+ const setup = editor => {
+ editor.addShortcut('Meta+K', '', () => {
+ editor.execCommand('mceLink');
+ });
+ };
+
+ const setupButtons = editor => {
+ editor.ui.registry.addToggleButton('link', {
+ icon: 'link',
+ tooltip: 'Insert/edit link',
+ onAction: openDialog(editor),
+ onSetup: toggleActiveState(editor)
+ });
+ editor.ui.registry.addButton('openlink', {
+ icon: 'new-tab',
+ tooltip: 'Open link',
+ onAction: gotoSelectedLink(editor),
+ onSetup: toggleEnabledState(editor)
+ });
+ editor.ui.registry.addButton('unlink', {
+ icon: 'unlink',
+ tooltip: 'Remove link',
+ onAction: () => unlink(editor),
+ onSetup: toggleUnlinkState(editor)
+ });
+ };
+ const setupMenuItems = editor => {
+ editor.ui.registry.addMenuItem('openlink', {
+ text: 'Open link',
+ icon: 'new-tab',
+ onAction: gotoSelectedLink(editor),
+ onSetup: toggleEnabledState(editor)
+ });
+ editor.ui.registry.addMenuItem('link', {
+ icon: 'link',
+ text: 'Link...',
+ shortcut: 'Meta+K',
+ onAction: openDialog(editor)
+ });
+ editor.ui.registry.addMenuItem('unlink', {
+ icon: 'unlink',
+ text: 'Remove link',
+ onAction: () => unlink(editor),
+ onSetup: toggleUnlinkState(editor)
+ });
+ };
+ const setupContextMenu = editor => {
+ const inLink = 'link unlink openlink';
+ const noLink = 'link';
+ editor.ui.registry.addContextMenu('link', { update: element => hasLinks(editor.dom.getParents(element, 'a')) ? inLink : noLink });
+ };
+ const setupContextToolbars = editor => {
+ const collapseSelectionToEnd = editor => {
+ editor.selection.collapse(false);
+ };
+ const onSetupLink = buttonApi => {
+ const node = editor.selection.getNode();
+ buttonApi.setEnabled(isInAnchor(editor, node));
+ return noop;
+ };
+ const getLinkText = value => {
+ const anchor = getAnchorElement(editor);
+ const onlyText = isOnlyTextSelected(editor);
+ if (anchor.isNone() && onlyText) {
+ const text = getAnchorText(editor.selection, anchor);
+ return Optional.some(text.length > 0 ? text : value);
+ } else {
+ return Optional.none();
+ }
+ };
+ editor.ui.registry.addContextForm('quicklink', {
+ launch: {
+ type: 'contextformtogglebutton',
+ icon: 'link',
+ tooltip: 'Link',
+ onSetup: toggleActiveState(editor)
+ },
+ label: 'Link',
+ predicate: node => hasContextToolbar(editor) && isInAnchor(editor, node),
+ initValue: () => {
+ const elm = getAnchorElement(editor);
+ return elm.fold(constant(''), getHref);
+ },
+ commands: [
+ {
+ type: 'contextformtogglebutton',
+ icon: 'link',
+ tooltip: 'Link',
+ primary: true,
+ onSetup: buttonApi => {
+ const node = editor.selection.getNode();
+ buttonApi.setActive(isInAnchor(editor, node));
+ return toggleActiveState(editor)(buttonApi);
+ },
+ onAction: formApi => {
+ const value = formApi.getValue();
+ const text = getLinkText(value);
+ const attachState = {
+ href: value,
+ attach: noop
+ };
+ link(editor, attachState, {
+ href: value,
+ text,
+ title: Optional.none(),
+ rel: Optional.none(),
+ target: Optional.none(),
+ class: Optional.none()
+ });
+ collapseSelectionToEnd(editor);
+ formApi.hide();
+ }
+ },
+ {
+ type: 'contextformbutton',
+ icon: 'unlink',
+ tooltip: 'Remove link',
+ onSetup: onSetupLink,
+ onAction: formApi => {
+ unlink(editor);
+ formApi.hide();
+ }
+ },
+ {
+ type: 'contextformbutton',
+ icon: 'new-tab',
+ tooltip: 'Open link',
+ onSetup: onSetupLink,
+ onAction: formApi => {
+ gotoSelectedLink(editor)();
+ formApi.hide();
+ }
+ }
+ ]
+ });
+ };
+
+ var Plugin = () => {
+ global$5.add('link', editor => {
+ register$1(editor);
+ setupButtons(editor);
+ setupMenuItems(editor);
+ setupContextMenu(editor);
+ setupContextToolbars(editor);
+ setupGotoLinks(editor);
+ register(editor);
+ setup(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/link/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/link/plugin.min.js
new file mode 100644
index 00000000000..32aefce064a
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/link/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||o.constructor?.name===r.name)?"string":t;var n,o,r})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),l=t("array"),a=(null,e=>null===e);const s=n("boolean"),i=e=>!(e=>null==e)(e),c=n("function"),u=(e,t)=>{if(l(e)){for(let n=0,o=e.length;n{},m=(e,t)=>e===t;class d{constructor(e,t){this.tag=e,this.value=t}static some(e){return new d(!0,e)}static none(){return d.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?d.some(e(this.value)):d.none()}bind(e){return this.tag?e(this.value):d.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:d.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(e??"Called getOrDie on None")}static from(e){return i(e)?d.some(e):d.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}d.singletonNone=new d(!1);const h=Array.prototype.indexOf,f=Array.prototype.push,p=e=>{const t=[];for(let n=0,o=e.length;n{for(let n=0;ne.exists((e=>n(e,t))),y=e=>{const t=[],n=e=>{t.push(e)};for(let t=0;te?d.some(t):d.none(),b=e=>t=>t.options.get(e),_=b("link_assume_external_targets"),w=b("link_context_toolbar"),C=b("link_list"),O=b("link_default_target"),N=b("link_default_protocol"),A=b("link_target_list"),S=b("link_rel_list"),T=b("link_class_list"),E=b("link_title"),P=b("allow_unsafe_link_target"),R=b("link_quicklink");var L=tinymce.util.Tools.resolve("tinymce.util.Tools");const M=e=>o(e.value)?e.value:"",D=(e,t)=>{const n=[];return L.each(e,(e=>{const r=(e=>o(e.text)?e.text:o(e.title)?e.title:"")(e);if(void 0!==e.menu){const o=D(e.menu,t);n.push({text:r,items:o})}else{const o=t(e);n.push({text:r,value:o})}})),n},B=(e=M)=>t=>d.from(t).map((t=>D(t,e))),I=e=>B(M)(e),j=B,K=(e,t)=>n=>({name:e,type:"listbox",label:t,items:n}),U=M,q=Object.keys,F=Object.hasOwnProperty,V=(e,t)=>F.call(e,t);var $=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),z=tinymce.util.Tools.resolve("tinymce.util.URI");const G=e=>i(e)&&"a"===e.nodeName.toLowerCase(),H=e=>G(e)&&!!Q(e),J=(e,t)=>{if(e.collapsed)return[];{const n=e.cloneContents(),o=n.firstChild,r=new $(o,n),l=[];let a=o;do{t(a)&&l.push(a)}while(a=r.next());return l}},W=e=>/^\w+:/i.test(e),Q=e=>e.getAttribute("data-mce-href")??e.getAttribute("href")??"",X=(e,t)=>{const n=["noopener"],o=e?e.split(/\s+/):[],r=e=>e.filter((e=>-1===L.inArray(n,e))),l=t?(e=>(e=r(e)).length>0?e.concat(n):n)(o):r(o);return l.length>0?(e=>L.trim(e.sort().join(" ")))(l):""},Y=(e,t)=>(t=t||e.selection.getNode(),oe(t)?d.from(e.dom.select("a[href]",t)[0]):d.from(e.dom.getParent(t,"a[href]"))),Z=(e,t)=>Y(e,t).isSome(),ee=(e,t)=>t.fold((()=>e.getContent({format:"text"})),(e=>e.innerText||e.textContent||"")).replace(/\uFEFF/g,""),te=e=>L.grep(e,H).length>0,ne=e=>{const t=e.schema.getTextInlineElements();return 0===J(e.selection.getRng(),(e=>1===e.nodeType&&!G(e)&&!V(t,e.nodeName.toLowerCase()))).length},oe=e=>i(e)&&"FIGURE"===e.nodeName&&/\bimage\b/i.test(e.className),re=(e,t,n)=>{const o=e.selection.getNode(),r=Y(e,o),l=((e,t)=>{const n={...t};if(0===S(e).length&&!P(e)){const e=X(n.rel,"_blank"===n.target);n.rel=e||null}return d.from(n.target).isNone()&&!1===A(e)&&(n.target=O(e)),n.href=((e,t)=>"http"!==t&&"https"!==t||W(e)?e:t+"://"+e)(n.href,_(e)),n})(e,(e=>{return t=["title","rel","class","target"],n=(t,n)=>(e[n].each((e=>{t[n]=e.length>0?e:null})),t),o={href:e.href},((e,t)=>{for(let n=0,o=e.length;n{o=n(o,e)})),o;var t,n,o})(n));e.undoManager.transact((()=>{n.href===t.href&&t.attach(),r.fold((()=>{((e,t,n,o)=>{const r=e.dom;oe(t)?ce(r,t,o):n.fold((()=>{e.execCommand("mceInsertLink",!1,o)}),(t=>{e.insertContent(r.createHTML("a",o,r.encode(t)))}))})(e,o,n.text,l)}),(t=>{e.focus(),((e,t,n,o)=>{n.each((e=>{V(t,"innerText")?t.innerText=e:t.textContent=e})),e.dom.setAttribs(t,o),e.selection.select(t)})(e,t,n.text,l)}))}))},le=e=>{const{class:t,href:n,rel:o,target:r,text:l,title:s}=e;return((e,t)=>{const n={};var o;return((e,t,n,o)=>{((e,t)=>{const n=q(e);for(let o=0,r=n.length;o{(t(e,r)?n:o)(e,r)}))})(e,((e,t)=>!1===a(e)),(o=n,(e,t)=>{o[t]=e}),g),n})({class:t.getOrNull(),href:n,rel:o.getOrNull(),target:r.getOrNull(),text:l.getOrNull(),title:s.getOrNull()})},ae=(e,t,n)=>{const o=((e,t)=>{const n=e.options.get,o={allow_html_data_urls:n("allow_html_data_urls"),allow_script_urls:n("allow_script_urls"),allow_svg_data_urls:n("allow_svg_data_urls")},r=t.href;return{...t,href:z.isDomSafe(r,"a",o)?r:""}})(e,n);e.hasPlugin("rtc",!0)?e.execCommand("createlink",!1,le(o)):re(e,t,o)},se=e=>{e.hasPlugin("rtc",!0)?e.execCommand("unlink"):(e=>{e.undoManager.transact((()=>{const t=e.selection.getNode();oe(t)?ie(e,t):(e=>{const t=e.dom,n=e.selection,o=n.getBookmark(),r=n.getRng().cloneRange(),l=t.getParent(r.startContainer,"a[href]",e.getBody()),a=t.getParent(r.endContainer,"a[href]",e.getBody());l&&r.setStartBefore(l),a&&r.setEndAfter(a),n.setRng(r),e.execCommand("unlink"),n.moveToBookmark(o)})(e),e.focus()}))})(e)},ie=(e,t)=>{const n=e.dom.select("img",t)[0];if(n){const o=e.dom.getParents(n,"a[href]",t)[0];o&&(o.parentNode?.insertBefore(n,o),e.dom.remove(o))}},ce=(e,t,n)=>{const o=e.select("img",t)[0];if(o){const t=e.create("a",n);o.parentNode?.insertBefore(t,o),t.appendChild(o)}},ue=(e,t)=>k(t,(t=>(e=>{return V(t=e,n="items")&&void 0!==t[n]&&null!==t[n];var t,n})(t)?ue(e,t.items):x(t.value===e,t))),ge=(e,t)=>{const n={text:e.text,title:e.title},o=(e,o)=>{const r=(l=t,a=o,"link"===a?l.link:"anchor"===a?l.anchor:d.none()).getOr([]);var l,a;return((e,t,n,o)=>{const r=o[t],l=e.length>0;return void 0!==r?ue(r,n).map((t=>({url:{value:t.value,meta:{text:l?e:t.text,attach:g}},text:l?e:t.text}))):d.none()})(n.text,o,r,e)};return{onChange:(e,t)=>{const r=t.name;return"url"===r?(e=>{const t=(o=e.url,x(n.text.length<=0,d.from(o.meta?.text).getOr(o.value)));var o;const r=(e=>x(n.title.length<=0,d.from(e.meta?.title).getOr("")))(e.url);return t.isSome()||r.isSome()?d.some({...t.map((e=>({text:e}))).getOr({}),...r.map((e=>({title:e}))).getOr({})}):d.none()})(e()):((e,t)=>h.call(e,t))(["anchor","link"],r)>-1?o(e(),r):"text"===r||"title"===r?(n[r]=e()[r],d.none()):d.none()}}};var me=tinymce.util.Tools.resolve("tinymce.util.Delay");const de=e=>{const t=e.href;return t.indexOf("@")>0&&-1===t.indexOf("/")&&-1===t.indexOf("mailto:")?d.some({message:"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",preprocess:e=>({...e,href:"mailto:"+t})}):d.none()},he=(e,t)=>n=>{const o=n.href;return 1===e&&!W(o)||0===e&&/^\s*www(\.|\d\.)/i.test(o)?d.some({message:`The URL you entered seems to be an external link. Do you want to add the required ${t}:// prefix?`,preprocess:e=>({...e,href:t+"://"+o})}):d.none()},fe=e=>{const t=e.dom.select("a:not([href])"),n=p(((e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r{const t=e.name||e.id;return t?[{text:t,value:"#"+t}]:[]})));return n.length>0?d.some([{text:"None",value:""}].concat(n)):d.none()},pe=e=>{const t=T(e);return t.length>0?I(t):d.none()},ke=e=>{try{return d.some(JSON.parse(e))}catch(e){return d.none()}},ve=(e,t)=>{const n=S(e);if(n.length>0){const o=v(t,"_blank"),r=e=>X(U(e),o);return(!1===P(e)?j(r):I)(n)}return d.none()},ye=[{text:"Current window",value:""},{text:"New window",value:"_blank"}],xe=e=>{const t=A(e);return l(t)?I(t).orThunk((()=>d.some(ye))):!1===t?d.none():d.some(ye)},be=(e,t,n)=>{const o=e.getAttrib(t,n);return null!==o&&o.length>0?d.some(o):d.none()},_e=(e,t)=>(e=>{const t=t=>e.convertURL(t.value||t.url||"","href"),n=C(e);return new Promise((e=>{o(n)?fetch(n).then((e=>e.ok?e.text().then(ke):Promise.reject())).then(e,(()=>e(d.none()))):c(n)?n((t=>e(d.some(t)))):e(d.from(n))})).then((e=>e.bind(j(t)).map((e=>e.length>0?[{text:"None",value:""}].concat(e):e))))})(e).then((n=>{const o=((e,t)=>{const n=e.dom,o=ne(e)?d.some(ee(e.selection,t)):d.none(),r=t.bind((e=>d.from(n.getAttrib(e,"href")))),l=t.bind((e=>d.from(n.getAttrib(e,"target")))),a=t.bind((e=>be(n,e,"rel"))),s=t.bind((e=>be(n,e,"class")));return{url:r,text:o,title:t.bind((e=>be(n,e,"title"))),target:l,rel:a,linkClass:s}})(e,t);return{anchor:o,catalogs:{targets:xe(e),rels:ve(e,o.target),classes:pe(e),anchor:fe(e),link:n},optNode:t,flags:{titleEnabled:E(e)}}})),we=e=>{const t=(e=>{const t=Y(e);return _e(e,t)})(e);t.then((t=>{const n=((e,t)=>n=>{const o=n.getData();if(!o.url.value)return se(e),void n.close();const r=e=>d.from(o[e]).filter((n=>!v(t.anchor[e],n))),l={href:o.url.value,text:r("text"),target:r("target"),rel:r("rel"),class:r("linkClass"),title:r("title")},a={href:o.url.value,attach:void 0!==o.url.meta&&o.url.meta.attach?o.url.meta.attach:g};((e,t)=>k([de,he(_(e),N(e))],(e=>e(t))).fold((()=>Promise.resolve(t)),(n=>new Promise((o=>{((e,t,n)=>{const o=e.selection.getRng();me.setEditorTimeout(e,(()=>{e.windowManager.confirm(t,(t=>{e.selection.setRng(o),n(t)}))}))})(e,n.message,(e=>{o(e?n.preprocess(t):t)}))})))))(e,l).then((t=>{ae(e,a,t)})),n.close()})(e,t);return((e,t,n)=>{const o=e.anchor.text.map((()=>({name:"text",type:"input",label:"Text to display"}))).toArray(),r=e.flags.titleEnabled?[{name:"title",type:"input",label:"Title"}]:[],l=((e,t)=>{const n=e.anchor,o=n.url.getOr("");return{url:{value:o,meta:{original:{value:o}}},text:n.text.getOr(""),title:n.title.getOr(""),anchor:o,link:o,rel:n.rel.getOr(""),target:n.target.or(t).getOr(""),linkClass:n.linkClass.getOr("")}})(e,d.from(O(n))),a=e.catalogs,s=ge(l,a);return{title:"Insert/Edit Link",size:"normal",body:{type:"panel",items:p([[{name:"url",type:"urlinput",filetype:"file",label:"URL"}],o,r,y([a.anchor.map(K("anchor","Anchors")),a.rels.map(K("rel","Rel")),a.targets.map(K("target","Open link in...")),a.link.map(K("link","Link list")),a.classes.map(K("linkClass","Class"))])])},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:l,onChange:(e,{name:t})=>{s.onChange(e.getData,{name:t}).each((t=>{e.setData(t)}))},onSubmit:t}})(t,n,e)})).then((t=>{e.windowManager.open(t)}))};var Ce=tinymce.util.Tools.resolve("tinymce.util.VK");const Oe=(e,t)=>e.dom.getParent(t,"a[href]"),Ne=e=>Oe(e,e.selection.getStart()),Ae=(e,t)=>{if(t){const n=Q(t);if(/^#/.test(n)){const t=e.dom.select(n);t.length&&e.selection.scrollIntoView(t[0],!0)}else(e=>{const t=document.createElement("a");t.target="_blank",t.href=e,t.rel="noreferrer noopener";const n=document.createEvent("MouseEvents");n.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),((e,t)=>{document.body.appendChild(e),e.dispatchEvent(t),document.body.removeChild(e)})(t,n)})(t.href)}},Se=e=>()=>{e.execCommand("mceLink",!1,{dialog:!0})},Te=e=>()=>{Ae(e,Ne(e))},Ee=(e,t)=>(e.on("NodeChange",t),()=>e.off("NodeChange",t)),Pe=e=>t=>{const n=()=>t.setActive(!e.mode.isReadOnly()&&Z(e,e.selection.getNode()));return n(),Ee(e,n)},Re=e=>t=>{const n=()=>t.setEnabled(Z(e,e.selection.getNode()));return n(),Ee(e,n)},Le=e=>t=>{const n=t=>{return te(t)||(n=e.selection.getRng(),J(n,H).length>0);var n},o=e.dom.getParents(e.selection.getStart());return t.setEnabled(n(o)),Ee(e,(e=>t.setEnabled(n(e.parents))))};e.add("link",(e=>{(e=>{const t=e.options.register;t("link_assume_external_targets",{processor:e=>{const t=o(e)||s(e);return t?!0===e?{value:1,valid:t}:"http"===e||"https"===e?{value:e,valid:t}:{value:0,valid:t}:{valid:!1,message:"Must be a string or a boolean."}},default:!1}),t("link_context_toolbar",{processor:"boolean",default:!1}),t("link_list",{processor:e=>o(e)||c(e)||u(e,r)}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"}),t("link_target_list",{processor:e=>s(e)||u(e,r),default:!0}),t("link_rel_list",{processor:"object[]",default:[]}),t("link_class_list",{processor:"object[]",default:[]}),t("link_title",{processor:"boolean",default:!0}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("link_quicklink",{processor:"boolean",default:!1})})(e),(e=>{e.ui.registry.addToggleButton("link",{icon:"link",tooltip:"Insert/edit link",onAction:Se(e),onSetup:Pe(e)}),e.ui.registry.addButton("openlink",{icon:"new-tab",tooltip:"Open link",onAction:Te(e),onSetup:Re(e)}),e.ui.registry.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onAction:()=>se(e),onSetup:Le(e)})})(e),(e=>{e.ui.registry.addMenuItem("openlink",{text:"Open link",icon:"new-tab",onAction:Te(e),onSetup:Re(e)}),e.ui.registry.addMenuItem("link",{icon:"link",text:"Link...",shortcut:"Meta+K",onAction:Se(e)}),e.ui.registry.addMenuItem("unlink",{icon:"unlink",text:"Remove link",onAction:()=>se(e),onSetup:Le(e)})})(e),(e=>{e.ui.registry.addContextMenu("link",{update:t=>te(e.dom.getParents(t,"a"))?"link unlink openlink":"link"})})(e),(e=>{const t=t=>{const n=e.selection.getNode();return t.setEnabled(Z(e,n)),g};e.ui.registry.addContextForm("quicklink",{launch:{type:"contextformtogglebutton",icon:"link",tooltip:"Link",onSetup:Pe(e)},label:"Link",predicate:t=>w(e)&&Z(e,t),initValue:()=>Y(e).fold((()=>""),Q),commands:[{type:"contextformtogglebutton",icon:"link",tooltip:"Link",primary:!0,onSetup:t=>{const n=e.selection.getNode();return t.setActive(Z(e,n)),Pe(e)(t)},onAction:t=>{const n=t.getValue(),o=(t=>{const n=Y(e),o=ne(e);if(n.isNone()&&o){const o=ee(e.selection,n);return d.some(o.length>0?o:t)}return d.none()})(n);ae(e,{href:n,attach:g},{href:n,text:o,title:d.none(),rel:d.none(),target:d.none(),class:d.none()}),(e=>{e.selection.collapse(!1)})(e),t.hide()}},{type:"contextformbutton",icon:"unlink",tooltip:"Remove link",onSetup:t,onAction:t=>{se(e),t.hide()}},{type:"contextformbutton",icon:"new-tab",tooltip:"Open link",onSetup:t,onAction:t=>{Te(e)(),t.hide()}}]})})(e),(e=>{e.on("click",(t=>{const n=Oe(e,t.target);n&&Ce.metaKeyPressed(t)&&(t.preventDefault(),Ae(e,n))})),e.on("keydown",(t=>{if(!t.isDefaultPrevented()&&13===t.keyCode&&(e=>!0===e.altKey&&!1===e.shiftKey&&!1===e.ctrlKey&&!1===e.metaKey)(t)){const n=Ne(e);n&&(t.preventDefault(),Ae(e,n))}}))})(e),(e=>{e.addCommand("mceLink",((t,n)=>{!0!==n?.dialog&&R(e)?e.dispatch("contexttoolbar-show",{toolbarKey:"quicklink"}):we(e)}))})(e),(e=>{e.addShortcut("Meta+K","",(()=>{e.execCommand("mceLink")}))})(e)}))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/lists/plugin.js b/lib/editor/tiny/js/tinymce/plugins/lists/plugin.js
new file mode 100644
index 00000000000..9990bfbf1d0
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/lists/plugin.js
@@ -0,0 +1,1860 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ var global$6 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ const hasProto = (v, constructor, predicate) => {
+ if (predicate(v, constructor.prototype)) {
+ return true;
+ } else {
+ return v.constructor?.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$1 = type => value => typeOf(value) === type;
+ const isSimpleType = type => value => typeof value === type;
+ const isString = isType$1('string');
+ const isObject = isType$1('object');
+ const isArray = isType$1('array');
+ const isBoolean = isSimpleType('boolean');
+ const isNullable = a => a === null || a === undefined;
+ const isNonNullable = a => !isNullable(a);
+ const isFunction = isSimpleType('function');
+ const isNumber = isSimpleType('number');
+
+ const noop = () => {
+ };
+ const constant = value => {
+ return () => {
+ return value;
+ };
+ };
+ const tripleEquals = (a, b) => {
+ return a === b;
+ };
+ const not = f => t => !f(t);
+ const never = constant(false);
+
+ 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 ?? '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 nativeSlice = Array.prototype.slice;
+ const nativeIndexOf = Array.prototype.indexOf;
+ const nativePush = Array.prototype.push;
+ const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
+ const contains$1 = (xs, x) => rawIndexOf(xs, x) > -1;
+ const exists = (xs, pred) => {
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ if (pred(x, i)) {
+ return true;
+ }
+ }
+ return false;
+ };
+ const map = (xs, f) => {
+ const len = xs.length;
+ const r = new Array(len);
+ for (let i = 0; i < len; i++) {
+ const x = xs[i];
+ r[i] = f(x, i);
+ }
+ return r;
+ };
+ const each$1 = (xs, f) => {
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ f(x, i);
+ }
+ };
+ const filter$1 = (xs, pred) => {
+ const r = [];
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ if (pred(x, i)) {
+ r.push(x);
+ }
+ }
+ return r;
+ };
+ const groupBy = (xs, f) => {
+ if (xs.length === 0) {
+ return [];
+ } else {
+ let wasType = f(xs[0]);
+ const r = [];
+ let group = [];
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ const type = f(x);
+ if (type !== wasType) {
+ r.push(group);
+ group = [];
+ }
+ wasType = type;
+ group.push(x);
+ }
+ if (group.length !== 0) {
+ r.push(group);
+ }
+ return r;
+ }
+ };
+ const foldl = (xs, f, acc) => {
+ each$1(xs, (x, i) => {
+ acc = f(acc, x, i);
+ });
+ return acc;
+ };
+ const findUntil = (xs, pred, until) => {
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ if (pred(x, i)) {
+ return Optional.some(x);
+ } else if (until(x, i)) {
+ break;
+ }
+ }
+ return Optional.none();
+ };
+ const find = (xs, pred) => {
+ return findUntil(xs, pred, never);
+ };
+ 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 bind = (xs, f) => flatten(map(xs, f));
+ const reverse = xs => {
+ const r = nativeSlice.call(xs, 0);
+ r.reverse();
+ return r;
+ };
+ const get$1 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
+ const head = xs => get$1(xs, 0);
+ const last = xs => get$1(xs, xs.length - 1);
+ const unique = (xs, comparator) => {
+ const r = [];
+ const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$1(r, x);
+ for (let i = 0, len = xs.length; i < len; i++) {
+ const x = xs[i];
+ if (!isDuplicated(x)) {
+ r.push(x);
+ }
+ }
+ return r;
+ };
+
+ const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
+ const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
+ const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
+
+ const ELEMENT = 1;
+
+ const fromHtml = (html, scope) => {
+ const doc = scope || document;
+ const div = doc.createElement('div');
+ div.innerHTML = html;
+ if (!div.hasChildNodes() || div.childNodes.length > 1) {
+ const message = 'HTML does not have a single root node';
+ console.error(message, html);
+ throw new Error(message);
+ }
+ return fromDom$1(div.childNodes[0]);
+ };
+ const fromTag = (tag, scope) => {
+ const doc = scope || document;
+ const node = doc.createElement(tag);
+ return fromDom$1(node);
+ };
+ const fromText = (text, scope) => {
+ const doc = scope || document;
+ const node = doc.createTextNode(text);
+ return fromDom$1(node);
+ };
+ const fromDom$1 = node => {
+ if (node === null || node === undefined) {
+ throw new Error('Node cannot be null or undefined');
+ }
+ return { dom: node };
+ };
+ const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
+ const SugarElement = {
+ fromHtml,
+ fromTag,
+ fromText,
+ fromDom: fromDom$1,
+ fromPoint
+ };
+
+ const is$1 = (element, selector) => {
+ const dom = element.dom;
+ if (dom.nodeType !== ELEMENT) {
+ return false;
+ } else {
+ const elem = dom;
+ if (elem.matches !== undefined) {
+ return elem.matches(selector);
+ } else if (elem.msMatchesSelector !== undefined) {
+ return elem.msMatchesSelector(selector);
+ } else if (elem.webkitMatchesSelector !== undefined) {
+ return elem.webkitMatchesSelector(selector);
+ } else if (elem.mozMatchesSelector !== undefined) {
+ return elem.mozMatchesSelector(selector);
+ } else {
+ throw new Error('Browser lacks native selectors');
+ }
+ }
+ };
+
+ const eq = (e1, e2) => e1.dom === e2.dom;
+ const contains = (e1, e2) => {
+ const d1 = e1.dom;
+ const d2 = e2.dom;
+ return d1 === d2 ? false : d1.contains(d2);
+ };
+ const is = is$1;
+
+ var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
+ if (is(scope, a)) {
+ return Optional.some(scope);
+ } else if (isFunction(isRoot) && isRoot(scope)) {
+ return Optional.none();
+ } else {
+ return ancestor(scope, a, isRoot);
+ }
+ };
+
+ typeof window !== 'undefined' ? window : Function('return this;')();
+
+ const name = element => {
+ const r = element.dom.nodeName;
+ return r.toLowerCase();
+ };
+ const type = element => element.dom.nodeType;
+ const isType = t => element => type(element) === t;
+ const isElement$1 = isType(ELEMENT);
+ const isTag = tag => e => isElement$1(e) && name(e) === tag;
+
+ const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
+ const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
+ const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
+ const children = element => map(element.dom.childNodes, SugarElement.fromDom);
+ const child = (element, index) => {
+ const cs = element.dom.childNodes;
+ return Optional.from(cs[index]).map(SugarElement.fromDom);
+ };
+ const firstChild = element => child(element, 0);
+ const lastChild = element => child(element, element.dom.childNodes.length - 1);
+
+ const ancestor = (scope, predicate, isRoot) => {
+ let element = scope.dom;
+ const stop = isFunction(isRoot) ? isRoot : never;
+ while (element.parentNode) {
+ element = element.parentNode;
+ const el = SugarElement.fromDom(element);
+ if (predicate(el)) {
+ return Optional.some(el);
+ } else if (stop(el)) {
+ break;
+ }
+ }
+ return Optional.none();
+ };
+ const closest = (scope, predicate, isRoot) => {
+ const is = (s, test) => test(s);
+ return ClosestOrAncestor(is, ancestor, scope, predicate, isRoot);
+ };
+
+ const before$1 = (marker, element) => {
+ const parent$1 = parent(marker);
+ parent$1.each(v => {
+ v.dom.insertBefore(element.dom, marker.dom);
+ });
+ };
+ const after = (marker, element) => {
+ const sibling = nextSibling(marker);
+ sibling.fold(() => {
+ const parent$1 = parent(marker);
+ parent$1.each(v => {
+ append$1(v, element);
+ });
+ }, v => {
+ before$1(v, element);
+ });
+ };
+ const append$1 = (parent, element) => {
+ parent.dom.appendChild(element.dom);
+ };
+
+ const before = (marker, elements) => {
+ each$1(elements, x => {
+ before$1(marker, x);
+ });
+ };
+ const append = (parent, elements) => {
+ each$1(elements, x => {
+ append$1(parent, x);
+ });
+ };
+
+ const empty = element => {
+ element.dom.textContent = '';
+ each$1(children(element), rogue => {
+ remove(rogue);
+ });
+ };
+ const remove = element => {
+ const dom = element.dom;
+ if (dom.parentNode !== null) {
+ dom.parentNode.removeChild(dom);
+ }
+ };
+
+ var global$5 = tinymce.util.Tools.resolve('tinymce.dom.RangeUtils');
+
+ var global$4 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
+
+ var global$3 = tinymce.util.Tools.resolve('tinymce.util.VK');
+
+ const fromDom = nodes => map(nodes, SugarElement.fromDom);
+
+ const keys = Object.keys;
+ 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 objAcc = r => (x, i) => {
+ r[i] = x;
+ };
+ const internalFilter = (obj, pred, onTrue, onFalse) => {
+ each(obj, (x, i) => {
+ (pred(x, i) ? onTrue : onFalse)(x, i);
+ });
+ };
+ const filter = (obj, pred) => {
+ const t = {};
+ internalFilter(obj, pred, objAcc(t), noop);
+ return t;
+ };
+
+ const rawSet = (dom, key, value) => {
+ if (isString(value) || isBoolean(value) || isNumber(value)) {
+ dom.setAttribute(key, value + '');
+ } else {
+ console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
+ throw new Error('Attribute value was not simple');
+ }
+ };
+ const setAll = (element, attrs) => {
+ const dom = element.dom;
+ each(attrs, (v, k) => {
+ rawSet(dom, k, v);
+ });
+ };
+ const clone$1 = element => foldl(element.dom.attributes, (acc, attr) => {
+ acc[attr.name] = attr.value;
+ return acc;
+ }, {});
+
+ const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
+ const deep = original => clone(original, true);
+ const shallowAs = (original, tag) => {
+ const nu = SugarElement.fromTag(tag);
+ const attributes = clone$1(original);
+ setAll(nu, attributes);
+ return nu;
+ };
+ const mutate = (original, tag) => {
+ const nu = shallowAs(original, tag);
+ after(original, nu);
+ const children$1 = children(original);
+ append(nu, children$1);
+ remove(original);
+ return nu;
+ };
+
+ var global$2 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
+
+ var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
+
+ const matchNodeName = name => node => isNonNullable(node) && node.nodeName.toLowerCase() === name;
+ const matchNodeNames = regex => node => isNonNullable(node) && regex.test(node.nodeName);
+ const isTextNode = node => isNonNullable(node) && node.nodeType === 3;
+ const isElement = node => isNonNullable(node) && node.nodeType === 1;
+ const isListNode = matchNodeNames(/^(OL|UL|DL)$/);
+ const isOlUlNode = matchNodeNames(/^(OL|UL)$/);
+ const isOlNode = matchNodeName('ol');
+ const isListItemNode = matchNodeNames(/^(LI|DT|DD)$/);
+ const isDlItemNode = matchNodeNames(/^(DT|DD)$/);
+ const isTableCellNode = matchNodeNames(/^(TH|TD)$/);
+ const isBr = matchNodeName('br');
+ const isFirstChild = node => node.parentNode?.firstChild === node;
+ const isTextBlock = (editor, node) => isNonNullable(node) && node.nodeName in editor.schema.getTextBlockElements();
+ const isBlock = (node, blockElements) => isNonNullable(node) && node.nodeName in blockElements;
+ const isBogusBr = (dom, node) => {
+ if (!isBr(node)) {
+ return false;
+ }
+ return dom.isBlock(node.nextSibling) && !isBr(node.previousSibling);
+ };
+ const isEmpty$1 = (dom, elm, keepBookmarks) => {
+ const empty = dom.isEmpty(elm);
+ if (keepBookmarks && dom.select('span[data-mce-type=bookmark]', elm).length > 0) {
+ return false;
+ }
+ return empty;
+ };
+ const isChildOfBody = (dom, elm) => dom.isChildOf(elm, dom.getRoot());
+
+ const option = name => editor => editor.options.get(name);
+ const register$3 = editor => {
+ const registerOption = editor.options.register;
+ registerOption('lists_indent_on_tab', {
+ processor: 'boolean',
+ default: true
+ });
+ };
+ const shouldIndentOnTab = option('lists_indent_on_tab');
+ const getForcedRootBlock = option('forced_root_block');
+ const getForcedRootBlockAttrs = option('forced_root_block_attrs');
+
+ const createTextBlock = (editor, contentNode) => {
+ const dom = editor.dom;
+ const blockElements = editor.schema.getBlockElements();
+ const fragment = dom.createFragment();
+ const blockName = getForcedRootBlock(editor);
+ const blockAttrs = getForcedRootBlockAttrs(editor);
+ let node;
+ let textBlock;
+ let hasContentNode = false;
+ textBlock = dom.create(blockName, blockAttrs);
+ if (!isBlock(contentNode.firstChild, blockElements)) {
+ fragment.appendChild(textBlock);
+ }
+ while (node = contentNode.firstChild) {
+ const nodeName = node.nodeName;
+ if (!hasContentNode && (nodeName !== 'SPAN' || node.getAttribute('data-mce-type') !== 'bookmark')) {
+ hasContentNode = true;
+ }
+ if (isBlock(node, blockElements)) {
+ fragment.appendChild(node);
+ textBlock = null;
+ } else {
+ if (!textBlock) {
+ textBlock = dom.create(blockName, blockAttrs);
+ fragment.appendChild(textBlock);
+ }
+ textBlock.appendChild(node);
+ }
+ }
+ if (!hasContentNode && textBlock) {
+ textBlock.appendChild(dom.create('br', { 'data-mce-bogus': '1' }));
+ }
+ return fragment;
+ };
+
+ const DOM$2 = global$2.DOM;
+ const splitList = (editor, list, li) => {
+ const removeAndKeepBookmarks = targetNode => {
+ const parent = targetNode.parentNode;
+ if (parent) {
+ global$1.each(bookmarks, node => {
+ parent.insertBefore(node, li.parentNode);
+ });
+ }
+ DOM$2.remove(targetNode);
+ };
+ const bookmarks = DOM$2.select('span[data-mce-type="bookmark"]', list);
+ const newBlock = createTextBlock(editor, li);
+ const tmpRng = DOM$2.createRng();
+ tmpRng.setStartAfter(li);
+ tmpRng.setEndAfter(list);
+ const fragment = tmpRng.extractContents();
+ for (let node = fragment.firstChild; node; node = node.firstChild) {
+ if (node.nodeName === 'LI' && editor.dom.isEmpty(node)) {
+ DOM$2.remove(node);
+ break;
+ }
+ }
+ if (!editor.dom.isEmpty(fragment)) {
+ DOM$2.insertAfter(fragment, list);
+ }
+ DOM$2.insertAfter(newBlock, list);
+ const parent = li.parentElement;
+ if (parent && isEmpty$1(editor.dom, parent)) {
+ removeAndKeepBookmarks(parent);
+ }
+ DOM$2.remove(li);
+ if (isEmpty$1(editor.dom, list)) {
+ DOM$2.remove(list);
+ }
+ };
+
+ const isDescriptionDetail = isTag('dd');
+ const isDescriptionTerm = isTag('dt');
+ const outdentDlItem = (editor, item) => {
+ if (isDescriptionDetail(item)) {
+ mutate(item, 'dt');
+ } else if (isDescriptionTerm(item)) {
+ parentElement(item).each(dl => splitList(editor, dl.dom, item.dom));
+ }
+ };
+ const indentDlItem = item => {
+ if (isDescriptionTerm(item)) {
+ mutate(item, 'dd');
+ }
+ };
+ const dlIndentation = (editor, indentation, dlItems) => {
+ if (indentation === 'Indent') {
+ each$1(dlItems, indentDlItem);
+ } else {
+ each$1(dlItems, item => outdentDlItem(editor, item));
+ }
+ };
+
+ const getNormalizedPoint = (container, offset) => {
+ if (isTextNode(container)) {
+ return {
+ container,
+ offset
+ };
+ }
+ const node = global$5.getNode(container, offset);
+ if (isTextNode(node)) {
+ return {
+ container: node,
+ offset: offset >= container.childNodes.length ? node.data.length : 0
+ };
+ } else if (node.previousSibling && isTextNode(node.previousSibling)) {
+ return {
+ container: node.previousSibling,
+ offset: node.previousSibling.data.length
+ };
+ } else if (node.nextSibling && isTextNode(node.nextSibling)) {
+ return {
+ container: node.nextSibling,
+ offset: 0
+ };
+ }
+ return {
+ container,
+ offset
+ };
+ };
+ const normalizeRange = rng => {
+ const outRng = rng.cloneRange();
+ const rangeStart = getNormalizedPoint(rng.startContainer, rng.startOffset);
+ outRng.setStart(rangeStart.container, rangeStart.offset);
+ const rangeEnd = getNormalizedPoint(rng.endContainer, rng.endOffset);
+ outRng.setEnd(rangeEnd.container, rangeEnd.offset);
+ return outRng;
+ };
+
+ const listNames = [
+ 'OL',
+ 'UL',
+ 'DL'
+ ];
+ const listSelector = listNames.join(',');
+ const getParentList = (editor, node) => {
+ const selectionStart = node || editor.selection.getStart(true);
+ return editor.dom.getParent(selectionStart, listSelector, getClosestListHost(editor, selectionStart));
+ };
+ const isParentListSelected = (parentList, selectedBlocks) => isNonNullable(parentList) && selectedBlocks.length === 1 && selectedBlocks[0] === parentList;
+ const findSubLists = parentList => filter$1(parentList.querySelectorAll(listSelector), isListNode);
+ const getSelectedSubLists = editor => {
+ const parentList = getParentList(editor);
+ const selectedBlocks = editor.selection.getSelectedBlocks();
+ if (isParentListSelected(parentList, selectedBlocks)) {
+ return findSubLists(parentList);
+ } else {
+ return filter$1(selectedBlocks, elm => {
+ return isListNode(elm) && parentList !== elm;
+ });
+ }
+ };
+ const findParentListItemsNodes = (editor, elms) => {
+ const listItemsElms = global$1.map(elms, elm => {
+ const parentLi = editor.dom.getParent(elm, 'li,dd,dt', getClosestListHost(editor, elm));
+ return parentLi ? parentLi : elm;
+ });
+ return unique(listItemsElms);
+ };
+ const getSelectedListItems = editor => {
+ const selectedBlocks = editor.selection.getSelectedBlocks();
+ return filter$1(findParentListItemsNodes(editor, selectedBlocks), isListItemNode);
+ };
+ const getSelectedDlItems = editor => filter$1(getSelectedListItems(editor), isDlItemNode);
+ const getClosestEditingHost = (editor, elm) => {
+ const parentTableCell = editor.dom.getParents(elm, 'TD,TH');
+ return parentTableCell.length > 0 ? parentTableCell[0] : editor.getBody();
+ };
+ const isListHost = (schema, node) => !isListNode(node) && !isListItemNode(node) && exists(listNames, listName => schema.isValidChild(node.nodeName, listName));
+ const getClosestListHost = (editor, elm) => {
+ const parentBlocks = editor.dom.getParents(elm, editor.dom.isBlock);
+ const parentBlock = find(parentBlocks, elm => isListHost(editor.schema, elm));
+ return parentBlock.getOr(editor.getBody());
+ };
+ const findLastParentListNode = (editor, elm) => {
+ const parentLists = editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
+ return last(parentLists);
+ };
+ const getSelectedLists = editor => {
+ const firstList = findLastParentListNode(editor, editor.selection.getStart());
+ const subsequentLists = filter$1(editor.selection.getSelectedBlocks(), isOlUlNode);
+ return firstList.toArray().concat(subsequentLists);
+ };
+ const getSelectedListRoots = editor => {
+ const selectedLists = getSelectedLists(editor);
+ return getUniqueListRoots(editor, selectedLists);
+ };
+ const getUniqueListRoots = (editor, lists) => {
+ const listRoots = map(lists, list => findLastParentListNode(editor, list).getOr(list));
+ return unique(listRoots);
+ };
+
+ const isCustomList = list => /\btox\-/.test(list.className);
+ const inList = (parents, listName) => findUntil(parents, isListNode, isTableCellNode).exists(list => list.nodeName === listName && !isCustomList(list));
+ const isWithinNonEditable = (editor, element) => element !== null && editor.dom.getContentEditableParent(element) === 'false';
+ const selectionIsWithinNonEditableList = editor => {
+ const parentList = getParentList(editor);
+ return isWithinNonEditable(editor, parentList);
+ };
+ const isWithinNonEditableList = (editor, element) => {
+ const parentList = editor.dom.getParent(element, 'ol,ul,dl');
+ return isWithinNonEditable(editor, parentList);
+ };
+ const setNodeChangeHandler = (editor, nodeChangeHandler) => {
+ const initialNode = editor.selection.getNode();
+ nodeChangeHandler({
+ parents: editor.dom.getParents(initialNode),
+ element: initialNode
+ });
+ editor.on('NodeChange', nodeChangeHandler);
+ return () => editor.off('NodeChange', nodeChangeHandler);
+ };
+
+ const fromElements = (elements, scope) => {
+ const doc = scope || document;
+ const fragment = doc.createDocumentFragment();
+ each$1(elements, element => {
+ fragment.appendChild(element.dom);
+ });
+ return SugarElement.fromDom(fragment);
+ };
+
+ const fireListEvent = (editor, action, element) => editor.dispatch('ListMutation', {
+ action,
+ element
+ });
+
+ const blank = r => s => s.replace(r, '');
+ const trim = blank(/^\s+|\s+$/g);
+ const isNotEmpty = s => s.length > 0;
+ const isEmpty = s => !isNotEmpty(s);
+
+ const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
+
+ const internalSet = (dom, property, value) => {
+ if (!isString(value)) {
+ console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
+ throw new Error('CSS value must be a string: ' + value);
+ }
+ if (isSupported(dom)) {
+ dom.style.setProperty(property, value);
+ }
+ };
+ const set = (element, property, value) => {
+ const dom = element.dom;
+ internalSet(dom, property, value);
+ };
+
+ const joinSegment = (parent, child) => {
+ append$1(parent.item, child.list);
+ };
+ const joinSegments = segments => {
+ for (let i = 1; i < segments.length; i++) {
+ joinSegment(segments[i - 1], segments[i]);
+ }
+ };
+ const appendSegments = (head$1, tail) => {
+ lift2(last(head$1), head(tail), joinSegment);
+ };
+ const createSegment = (scope, listType) => {
+ const segment = {
+ list: SugarElement.fromTag(listType, scope),
+ item: SugarElement.fromTag('li', scope)
+ };
+ append$1(segment.list, segment.item);
+ return segment;
+ };
+ const createSegments = (scope, entry, size) => {
+ const segments = [];
+ for (let i = 0; i < size; i++) {
+ segments.push(createSegment(scope, entry.listType));
+ }
+ return segments;
+ };
+ const populateSegments = (segments, entry) => {
+ for (let i = 0; i < segments.length - 1; i++) {
+ set(segments[i].item, 'list-style-type', 'none');
+ }
+ last(segments).each(segment => {
+ setAll(segment.list, entry.listAttributes);
+ setAll(segment.item, entry.itemAttributes);
+ append(segment.item, entry.content);
+ });
+ };
+ const normalizeSegment = (segment, entry) => {
+ if (name(segment.list) !== entry.listType) {
+ segment.list = mutate(segment.list, entry.listType);
+ }
+ setAll(segment.list, entry.listAttributes);
+ };
+ const createItem = (scope, attr, content) => {
+ const item = SugarElement.fromTag('li', scope);
+ setAll(item, attr);
+ append(item, content);
+ return item;
+ };
+ const appendItem = (segment, item) => {
+ append$1(segment.list, item);
+ segment.item = item;
+ };
+ const writeShallow = (scope, cast, entry) => {
+ const newCast = cast.slice(0, entry.depth);
+ last(newCast).each(segment => {
+ const item = createItem(scope, entry.itemAttributes, entry.content);
+ appendItem(segment, item);
+ normalizeSegment(segment, entry);
+ });
+ return newCast;
+ };
+ const writeDeep = (scope, cast, entry) => {
+ const segments = createSegments(scope, entry, entry.depth - cast.length);
+ joinSegments(segments);
+ populateSegments(segments, entry);
+ appendSegments(cast, segments);
+ return cast.concat(segments);
+ };
+ const composeList = (scope, entries) => {
+ const cast = foldl(entries, (cast, entry) => {
+ return entry.depth > cast.length ? writeDeep(scope, cast, entry) : writeShallow(scope, cast, entry);
+ }, []);
+ return head(cast).map(segment => segment.list);
+ };
+
+ const isList = el => is(el, 'OL,UL');
+ const hasFirstChildList = el => firstChild(el).exists(isList);
+ const hasLastChildList = el => lastChild(el).exists(isList);
+
+ const isIndented = entry => entry.depth > 0;
+ const isSelected = entry => entry.isSelected;
+ const cloneItemContent = li => {
+ const children$1 = children(li);
+ const content = hasLastChildList(li) ? children$1.slice(0, -1) : children$1;
+ return map(content, deep);
+ };
+ const createEntry = (li, depth, isSelected) => parent(li).filter(isElement$1).map(list => ({
+ depth,
+ dirty: false,
+ isSelected,
+ content: cloneItemContent(li),
+ itemAttributes: clone$1(li),
+ listAttributes: clone$1(list),
+ listType: name(list)
+ }));
+
+ const indentEntry = (indentation, entry) => {
+ switch (indentation) {
+ case 'Indent':
+ entry.depth++;
+ break;
+ case 'Outdent':
+ entry.depth--;
+ break;
+ case 'Flatten':
+ entry.depth = 0;
+ }
+ entry.dirty = true;
+ };
+
+ const cloneListProperties = (target, source) => {
+ target.listType = source.listType;
+ target.listAttributes = { ...source.listAttributes };
+ };
+ const cleanListProperties = entry => {
+ entry.listAttributes = filter(entry.listAttributes, (_value, key) => key !== 'start');
+ };
+ const closestSiblingEntry = (entries, start) => {
+ const depth = entries[start].depth;
+ const matches = entry => entry.depth === depth && !entry.dirty;
+ const until = entry => entry.depth < depth;
+ return findUntil(reverse(entries.slice(0, start)), matches, until).orThunk(() => findUntil(entries.slice(start + 1), matches, until));
+ };
+ const normalizeEntries = entries => {
+ each$1(entries, (entry, i) => {
+ closestSiblingEntry(entries, i).fold(() => {
+ if (entry.dirty) {
+ cleanListProperties(entry);
+ }
+ }, matchingEntry => cloneListProperties(entry, matchingEntry));
+ });
+ return entries;
+ };
+
+ const Cell = initial => {
+ let value = initial;
+ const get = () => {
+ return value;
+ };
+ const set = v => {
+ value = v;
+ };
+ return {
+ get,
+ set
+ };
+ };
+
+ const parseItem = (depth, itemSelection, selectionState, item) => firstChild(item).filter(isList).fold(() => {
+ itemSelection.each(selection => {
+ if (eq(selection.start, item)) {
+ selectionState.set(true);
+ }
+ });
+ const currentItemEntry = createEntry(item, depth, selectionState.get());
+ itemSelection.each(selection => {
+ if (eq(selection.end, item)) {
+ selectionState.set(false);
+ }
+ });
+ const childListEntries = lastChild(item).filter(isList).map(list => parseList(depth, itemSelection, selectionState, list)).getOr([]);
+ return currentItemEntry.toArray().concat(childListEntries);
+ }, list => parseList(depth, itemSelection, selectionState, list));
+ const parseList = (depth, itemSelection, selectionState, list) => bind(children(list), element => {
+ const parser = isList(element) ? parseList : parseItem;
+ const newDepth = depth + 1;
+ return parser(newDepth, itemSelection, selectionState, element);
+ });
+ const parseLists = (lists, itemSelection) => {
+ const selectionState = Cell(false);
+ const initialDepth = 0;
+ return map(lists, list => ({
+ sourceList: list,
+ entries: parseList(initialDepth, itemSelection, selectionState, list)
+ }));
+ };
+
+ const outdentedComposer = (editor, entries) => {
+ const normalizedEntries = normalizeEntries(entries);
+ return map(normalizedEntries, entry => {
+ const content = fromElements(entry.content);
+ return SugarElement.fromDom(createTextBlock(editor, content.dom));
+ });
+ };
+ const indentedComposer = (editor, entries) => {
+ const normalizedEntries = normalizeEntries(entries);
+ return composeList(editor.contentDocument, normalizedEntries).toArray();
+ };
+ const composeEntries = (editor, entries) => bind(groupBy(entries, isIndented), entries => {
+ const groupIsIndented = head(entries).exists(isIndented);
+ return groupIsIndented ? indentedComposer(editor, entries) : outdentedComposer(editor, entries);
+ });
+ const indentSelectedEntries = (entries, indentation) => {
+ each$1(filter$1(entries, isSelected), entry => indentEntry(indentation, entry));
+ };
+ const getItemSelection = editor => {
+ const selectedListItems = map(getSelectedListItems(editor), SugarElement.fromDom);
+ return lift2(find(selectedListItems, not(hasFirstChildList)), find(reverse(selectedListItems), not(hasFirstChildList)), (start, end) => ({
+ start,
+ end
+ }));
+ };
+ const listIndentation = (editor, lists, indentation) => {
+ const entrySets = parseLists(lists, getItemSelection(editor));
+ each$1(entrySets, entrySet => {
+ indentSelectedEntries(entrySet.entries, indentation);
+ const composedLists = composeEntries(editor, entrySet.entries);
+ each$1(composedLists, composedList => {
+ fireListEvent(editor, indentation === 'Indent' ? 'IndentList' : 'OutdentList', composedList.dom);
+ });
+ before(entrySet.sourceList, composedLists);
+ remove(entrySet.sourceList);
+ });
+ };
+
+ const selectionIndentation = (editor, indentation) => {
+ const lists = fromDom(getSelectedListRoots(editor));
+ const dlItems = fromDom(getSelectedDlItems(editor));
+ let isHandled = false;
+ if (lists.length || dlItems.length) {
+ const bookmark = editor.selection.getBookmark();
+ listIndentation(editor, lists, indentation);
+ dlIndentation(editor, indentation, dlItems);
+ editor.selection.moveToBookmark(bookmark);
+ editor.selection.setRng(normalizeRange(editor.selection.getRng()));
+ editor.nodeChanged();
+ isHandled = true;
+ }
+ return isHandled;
+ };
+ const handleIndentation = (editor, indentation) => !selectionIsWithinNonEditableList(editor) && selectionIndentation(editor, indentation);
+ const indentListSelection = editor => handleIndentation(editor, 'Indent');
+ const outdentListSelection = editor => handleIndentation(editor, 'Outdent');
+ const flattenListSelection = editor => handleIndentation(editor, 'Flatten');
+
+ var global = tinymce.util.Tools.resolve('tinymce.dom.BookmarkManager');
+
+ const DOM$1 = global$2.DOM;
+ const createBookmark = rng => {
+ const bookmark = {};
+ const setupEndPoint = start => {
+ let container = rng[start ? 'startContainer' : 'endContainer'];
+ let offset = rng[start ? 'startOffset' : 'endOffset'];
+ if (isElement(container)) {
+ const offsetNode = DOM$1.create('span', { 'data-mce-type': 'bookmark' });
+ if (container.hasChildNodes()) {
+ offset = Math.min(offset, container.childNodes.length - 1);
+ if (start) {
+ container.insertBefore(offsetNode, container.childNodes[offset]);
+ } else {
+ DOM$1.insertAfter(offsetNode, container.childNodes[offset]);
+ }
+ } else {
+ container.appendChild(offsetNode);
+ }
+ container = offsetNode;
+ offset = 0;
+ }
+ bookmark[start ? 'startContainer' : 'endContainer'] = container;
+ bookmark[start ? 'startOffset' : 'endOffset'] = offset;
+ };
+ setupEndPoint(true);
+ if (!rng.collapsed) {
+ setupEndPoint();
+ }
+ return bookmark;
+ };
+ const resolveBookmark = bookmark => {
+ const restoreEndPoint = start => {
+ const nodeIndex = container => {
+ let node = container.parentNode?.firstChild;
+ let idx = 0;
+ while (node) {
+ if (node === container) {
+ return idx;
+ }
+ if (!isElement(node) || node.getAttribute('data-mce-type') !== 'bookmark') {
+ idx++;
+ }
+ node = node.nextSibling;
+ }
+ return -1;
+ };
+ let container = bookmark[start ? 'startContainer' : 'endContainer'];
+ let offset = bookmark[start ? 'startOffset' : 'endOffset'];
+ if (!container) {
+ return;
+ }
+ if (isElement(container) && container.parentNode) {
+ const node = container;
+ offset = nodeIndex(container);
+ container = container.parentNode;
+ DOM$1.remove(node);
+ if (!container.hasChildNodes() && DOM$1.isBlock(container)) {
+ container.appendChild(DOM$1.create('br'));
+ }
+ }
+ bookmark[start ? 'startContainer' : 'endContainer'] = container;
+ bookmark[start ? 'startOffset' : 'endOffset'] = offset;
+ };
+ restoreEndPoint(true);
+ restoreEndPoint();
+ const rng = DOM$1.createRng();
+ rng.setStart(bookmark.startContainer, bookmark.startOffset);
+ if (bookmark.endContainer) {
+ rng.setEnd(bookmark.endContainer, bookmark.endOffset);
+ }
+ return normalizeRange(rng);
+ };
+
+ const listToggleActionFromListName = listName => {
+ switch (listName) {
+ case 'UL':
+ return 'ToggleUlList';
+ case 'OL':
+ return 'ToggleOlList';
+ case 'DL':
+ return 'ToggleDLList';
+ }
+ };
+
+ const updateListStyle = (dom, el, detail) => {
+ const type = detail['list-style-type'] ? detail['list-style-type'] : null;
+ dom.setStyle(el, 'list-style-type', type);
+ };
+ const setAttribs = (elm, attrs) => {
+ global$1.each(attrs, (value, key) => {
+ elm.setAttribute(key, value);
+ });
+ };
+ const updateListAttrs = (dom, el, detail) => {
+ setAttribs(el, detail['list-attributes']);
+ global$1.each(dom.select('li', el), li => {
+ setAttribs(li, detail['list-item-attributes']);
+ });
+ };
+ const updateListWithDetails = (dom, el, detail) => {
+ updateListStyle(dom, el, detail);
+ updateListAttrs(dom, el, detail);
+ };
+ const removeStyles = (dom, element, styles) => {
+ global$1.each(styles, style => dom.setStyle(element, style, ''));
+ };
+ const getEndPointNode = (editor, rng, start, root) => {
+ let container = rng[start ? 'startContainer' : 'endContainer'];
+ const offset = rng[start ? 'startOffset' : 'endOffset'];
+ if (isElement(container)) {
+ container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
+ }
+ if (!start && isBr(container.nextSibling)) {
+ container = container.nextSibling;
+ }
+ while (container.parentNode !== root) {
+ const parent = container.parentNode;
+ if (isTextBlock(editor, container)) {
+ return container;
+ }
+ if (/^(TD|TH)$/.test(parent.nodeName)) {
+ return container;
+ }
+ container = parent;
+ }
+ return container;
+ };
+ const getSelectedTextBlocks = (editor, rng, root) => {
+ const textBlocks = [];
+ const dom = editor.dom;
+ const startNode = getEndPointNode(editor, rng, true, root);
+ const endNode = getEndPointNode(editor, rng, false, root);
+ let block;
+ const siblings = [];
+ for (let node = startNode; node; node = node.nextSibling) {
+ siblings.push(node);
+ if (node === endNode) {
+ break;
+ }
+ }
+ global$1.each(siblings, node => {
+ if (isTextBlock(editor, node)) {
+ textBlocks.push(node);
+ block = null;
+ return;
+ }
+ if (dom.isBlock(node) || isBr(node)) {
+ if (isBr(node)) {
+ dom.remove(node);
+ }
+ block = null;
+ return;
+ }
+ const nextSibling = node.nextSibling;
+ if (global.isBookmarkNode(node)) {
+ if (isListNode(nextSibling) || isTextBlock(editor, nextSibling) || !nextSibling && node.parentNode === root) {
+ block = null;
+ return;
+ }
+ }
+ if (!block) {
+ block = dom.create('p');
+ node.parentNode?.insertBefore(block, node);
+ textBlocks.push(block);
+ }
+ block.appendChild(node);
+ });
+ return textBlocks;
+ };
+ const hasCompatibleStyle = (dom, sib, detail) => {
+ const sibStyle = dom.getStyle(sib, 'list-style-type');
+ let detailStyle = detail ? detail['list-style-type'] : '';
+ detailStyle = detailStyle === null ? '' : detailStyle;
+ return sibStyle === detailStyle;
+ };
+ const applyList = (editor, listName, detail) => {
+ const rng = editor.selection.getRng();
+ let listItemName = 'LI';
+ const root = getClosestListHost(editor, editor.selection.getStart(true));
+ const dom = editor.dom;
+ if (dom.getContentEditable(editor.selection.getNode()) === 'false') {
+ return;
+ }
+ listName = listName.toUpperCase();
+ if (listName === 'DL') {
+ listItemName = 'DT';
+ }
+ const bookmark = createBookmark(rng);
+ const selectedTextBlocks = getSelectedTextBlocks(editor, rng, root);
+ global$1.each(selectedTextBlocks, block => {
+ let listBlock;
+ const sibling = block.previousSibling;
+ const parent = block.parentNode;
+ if (!isListItemNode(parent)) {
+ if (sibling && isListNode(sibling) && sibling.nodeName === listName && hasCompatibleStyle(dom, sibling, detail)) {
+ listBlock = sibling;
+ block = dom.rename(block, listItemName);
+ sibling.appendChild(block);
+ } else {
+ listBlock = dom.create(listName);
+ parent.insertBefore(listBlock, block);
+ listBlock.appendChild(block);
+ block = dom.rename(block, listItemName);
+ }
+ removeStyles(dom, block, [
+ 'margin',
+ 'margin-right',
+ 'margin-bottom',
+ 'margin-left',
+ 'margin-top',
+ 'padding',
+ 'padding-right',
+ 'padding-bottom',
+ 'padding-left',
+ 'padding-top'
+ ]);
+ updateListWithDetails(dom, listBlock, detail);
+ mergeWithAdjacentLists(editor.dom, listBlock);
+ }
+ });
+ editor.selection.setRng(resolveBookmark(bookmark));
+ };
+ const isValidLists = (list1, list2) => {
+ return isListNode(list1) && list1.nodeName === list2?.nodeName;
+ };
+ const hasSameListStyle = (dom, list1, list2) => {
+ const targetStyle = dom.getStyle(list1, 'list-style-type', true);
+ const style = dom.getStyle(list2, 'list-style-type', true);
+ return targetStyle === style;
+ };
+ const hasSameClasses = (elm1, elm2) => {
+ return elm1.className === elm2.className;
+ };
+ const shouldMerge = (dom, list1, list2) => {
+ return isValidLists(list1, list2) && hasSameListStyle(dom, list1, list2) && hasSameClasses(list1, list2);
+ };
+ const mergeWithAdjacentLists = (dom, listBlock) => {
+ let node;
+ let sibling = listBlock.nextSibling;
+ if (shouldMerge(dom, listBlock, sibling)) {
+ const liSibling = sibling;
+ while (node = liSibling.firstChild) {
+ listBlock.appendChild(node);
+ }
+ dom.remove(liSibling);
+ }
+ sibling = listBlock.previousSibling;
+ if (shouldMerge(dom, listBlock, sibling)) {
+ const liSibling = sibling;
+ while (node = liSibling.lastChild) {
+ listBlock.insertBefore(node, listBlock.firstChild);
+ }
+ dom.remove(liSibling);
+ }
+ };
+ const updateList$1 = (editor, list, listName, detail) => {
+ if (list.nodeName !== listName) {
+ const newList = editor.dom.rename(list, listName);
+ updateListWithDetails(editor.dom, newList, detail);
+ fireListEvent(editor, listToggleActionFromListName(listName), newList);
+ } else {
+ updateListWithDetails(editor.dom, list, detail);
+ fireListEvent(editor, listToggleActionFromListName(listName), list);
+ }
+ };
+ const toggleMultipleLists = (editor, parentList, lists, listName, detail) => {
+ const parentIsList = isListNode(parentList);
+ if (parentIsList && parentList.nodeName === listName && !hasListStyleDetail(detail)) {
+ flattenListSelection(editor);
+ } else {
+ applyList(editor, listName, detail);
+ const bookmark = createBookmark(editor.selection.getRng());
+ const allLists = parentIsList ? [
+ parentList,
+ ...lists
+ ] : lists;
+ global$1.each(allLists, elm => {
+ updateList$1(editor, elm, listName, detail);
+ });
+ editor.selection.setRng(resolveBookmark(bookmark));
+ }
+ };
+ const hasListStyleDetail = detail => {
+ return 'list-style-type' in detail;
+ };
+ const toggleSingleList = (editor, parentList, listName, detail) => {
+ if (parentList === editor.getBody()) {
+ return;
+ }
+ if (parentList) {
+ if (parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
+ flattenListSelection(editor);
+ } else {
+ const bookmark = createBookmark(editor.selection.getRng());
+ updateListWithDetails(editor.dom, parentList, detail);
+ const newList = editor.dom.rename(parentList, listName);
+ mergeWithAdjacentLists(editor.dom, newList);
+ editor.selection.setRng(resolveBookmark(bookmark));
+ applyList(editor, listName, detail);
+ fireListEvent(editor, listToggleActionFromListName(listName), newList);
+ }
+ } else {
+ applyList(editor, listName, detail);
+ fireListEvent(editor, listToggleActionFromListName(listName), parentList);
+ }
+ };
+ const toggleList = (editor, listName, _detail) => {
+ const parentList = getParentList(editor);
+ if (isWithinNonEditableList(editor, parentList)) {
+ return;
+ }
+ const selectedSubLists = getSelectedSubLists(editor);
+ const detail = isObject(_detail) ? _detail : {};
+ if (selectedSubLists.length > 0) {
+ toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
+ } else {
+ toggleSingleList(editor, parentList, listName, detail);
+ }
+ };
+
+ const DOM = global$2.DOM;
+ const normalizeList = (dom, list) => {
+ const parentNode = list.parentElement;
+ if (parentNode && parentNode.nodeName === 'LI' && parentNode.firstChild === list) {
+ const sibling = parentNode.previousSibling;
+ if (sibling && sibling.nodeName === 'LI') {
+ sibling.appendChild(list);
+ if (isEmpty$1(dom, parentNode)) {
+ DOM.remove(parentNode);
+ }
+ } else {
+ DOM.setStyle(parentNode, 'listStyleType', 'none');
+ }
+ }
+ if (isListNode(parentNode)) {
+ const sibling = parentNode.previousSibling;
+ if (sibling && sibling.nodeName === 'LI') {
+ sibling.appendChild(list);
+ }
+ }
+ };
+ const normalizeLists = (dom, element) => {
+ const lists = global$1.grep(dom.select('ol,ul', element));
+ global$1.each(lists, list => {
+ normalizeList(dom, list);
+ });
+ };
+
+ const findNextCaretContainer = (editor, rng, isForward, root) => {
+ let node = rng.startContainer;
+ const offset = rng.startOffset;
+ if (isTextNode(node) && (isForward ? offset < node.data.length : offset > 0)) {
+ return node;
+ }
+ const nonEmptyBlocks = editor.schema.getNonEmptyElements();
+ if (isElement(node)) {
+ node = global$5.getNode(node, offset);
+ }
+ const walker = new global$4(node, root);
+ if (isForward) {
+ if (isBogusBr(editor.dom, node)) {
+ walker.next();
+ }
+ }
+ const walkFn = isForward ? walker.next.bind(walker) : walker.prev2.bind(walker);
+ while (node = walkFn()) {
+ if (node.nodeName === 'LI' && !node.hasChildNodes()) {
+ return node;
+ }
+ if (nonEmptyBlocks[node.nodeName]) {
+ return node;
+ }
+ if (isTextNode(node) && node.data.length > 0) {
+ return node;
+ }
+ }
+ return null;
+ };
+ const hasOnlyOneBlockChild = (dom, elm) => {
+ const childNodes = elm.childNodes;
+ return childNodes.length === 1 && !isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
+ };
+ const unwrapSingleBlockChild = (dom, elm) => {
+ if (hasOnlyOneBlockChild(dom, elm)) {
+ dom.remove(elm.firstChild, true);
+ }
+ };
+ const moveChildren = (dom, fromElm, toElm) => {
+ let node;
+ const targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
+ unwrapSingleBlockChild(dom, fromElm);
+ if (!isEmpty$1(dom, fromElm, true)) {
+ while (node = fromElm.firstChild) {
+ targetElm.appendChild(node);
+ }
+ }
+ };
+ const mergeLiElements = (dom, fromElm, toElm) => {
+ let listNode;
+ const ul = fromElm.parentNode;
+ if (!isChildOfBody(dom, fromElm) || !isChildOfBody(dom, toElm)) {
+ return;
+ }
+ if (isListNode(toElm.lastChild)) {
+ listNode = toElm.lastChild;
+ }
+ if (ul === toElm.lastChild) {
+ if (isBr(ul.previousSibling)) {
+ dom.remove(ul.previousSibling);
+ }
+ }
+ const node = toElm.lastChild;
+ if (node && isBr(node) && fromElm.hasChildNodes()) {
+ dom.remove(node);
+ }
+ if (isEmpty$1(dom, toElm, true)) {
+ empty(SugarElement.fromDom(toElm));
+ }
+ moveChildren(dom, fromElm, toElm);
+ if (listNode) {
+ toElm.appendChild(listNode);
+ }
+ const contains$1 = contains(SugarElement.fromDom(toElm), SugarElement.fromDom(fromElm));
+ const nestedLists = contains$1 ? dom.getParents(fromElm, isListNode, toElm) : [];
+ dom.remove(fromElm);
+ each$1(nestedLists, list => {
+ if (isEmpty$1(dom, list) && list !== dom.getRoot()) {
+ dom.remove(list);
+ }
+ });
+ };
+ const mergeIntoEmptyLi = (editor, fromLi, toLi) => {
+ empty(SugarElement.fromDom(toLi));
+ mergeLiElements(editor.dom, fromLi, toLi);
+ editor.selection.setCursorLocation(toLi, 0);
+ };
+ const mergeForward = (editor, rng, fromLi, toLi) => {
+ const dom = editor.dom;
+ if (dom.isEmpty(toLi)) {
+ mergeIntoEmptyLi(editor, fromLi, toLi);
+ } else {
+ const bookmark = createBookmark(rng);
+ mergeLiElements(dom, fromLi, toLi);
+ editor.selection.setRng(resolveBookmark(bookmark));
+ }
+ };
+ const mergeBackward = (editor, rng, fromLi, toLi) => {
+ const bookmark = createBookmark(rng);
+ mergeLiElements(editor.dom, fromLi, toLi);
+ const resolvedBookmark = resolveBookmark(bookmark);
+ editor.selection.setRng(resolvedBookmark);
+ };
+ const backspaceDeleteFromListToListCaret = (editor, isForward) => {
+ const dom = editor.dom, selection = editor.selection;
+ const selectionStartElm = selection.getStart();
+ const root = getClosestEditingHost(editor, selectionStartElm);
+ const li = dom.getParent(selection.getStart(), 'LI', root);
+ if (li) {
+ const ul = li.parentElement;
+ if (ul === editor.getBody() && isEmpty$1(dom, ul)) {
+ return true;
+ }
+ const rng = normalizeRange(selection.getRng());
+ const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
+ if (otherLi && otherLi !== li) {
+ editor.undoManager.transact(() => {
+ if (isForward) {
+ mergeForward(editor, rng, otherLi, li);
+ } else {
+ if (isFirstChild(li)) {
+ outdentListSelection(editor);
+ } else {
+ mergeBackward(editor, rng, li, otherLi);
+ }
+ }
+ });
+ return true;
+ } else if (!otherLi) {
+ if (!isForward && rng.startOffset === 0 && rng.endOffset === 0) {
+ editor.undoManager.transact(() => {
+ flattenListSelection(editor);
+ });
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ const removeBlock = (dom, block, root) => {
+ const parentBlock = dom.getParent(block.parentNode, dom.isBlock, root);
+ dom.remove(block);
+ if (parentBlock && dom.isEmpty(parentBlock)) {
+ dom.remove(parentBlock);
+ }
+ };
+ const backspaceDeleteIntoListCaret = (editor, isForward) => {
+ const dom = editor.dom;
+ const selectionStartElm = editor.selection.getStart();
+ const root = getClosestEditingHost(editor, selectionStartElm);
+ const block = dom.getParent(selectionStartElm, dom.isBlock, root);
+ if (block && dom.isEmpty(block)) {
+ const rng = normalizeRange(editor.selection.getRng());
+ const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
+ if (otherLi) {
+ const findValidElement = element => contains$1([
+ 'td',
+ 'th',
+ 'caption'
+ ], name(element));
+ const findRoot = node => node.dom === root;
+ const otherLiCell = closest(SugarElement.fromDom(otherLi), findValidElement, findRoot);
+ const caretCell = closest(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
+ if (!equals(otherLiCell, caretCell, eq)) {
+ return false;
+ }
+ editor.undoManager.transact(() => {
+ removeBlock(dom, block, root);
+ mergeWithAdjacentLists(dom, otherLi.parentNode);
+ editor.selection.select(otherLi, true);
+ editor.selection.collapse(isForward);
+ });
+ return true;
+ }
+ }
+ return false;
+ };
+ const backspaceDeleteCaret = (editor, isForward) => {
+ return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
+ };
+ const hasListSelection = editor => {
+ const selectionStartElm = editor.selection.getStart();
+ const root = getClosestEditingHost(editor, selectionStartElm);
+ const startListParent = editor.dom.getParent(selectionStartElm, 'LI,DT,DD', root);
+ return startListParent || getSelectedListItems(editor).length > 0;
+ };
+ const backspaceDeleteRange = editor => {
+ if (hasListSelection(editor)) {
+ editor.undoManager.transact(() => {
+ editor.execCommand('Delete');
+ normalizeLists(editor.dom, editor.getBody());
+ });
+ return true;
+ }
+ return false;
+ };
+ const backspaceDelete = (editor, isForward) => {
+ const selection = editor.selection;
+ return !isWithinNonEditableList(editor, selection.getNode()) && (selection.isCollapsed() ? backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor));
+ };
+ const setup$1 = editor => {
+ editor.on('ExecCommand', e => {
+ const cmd = e.command.toLowerCase();
+ if ((cmd === 'delete' || cmd === 'forwarddelete') && hasListSelection(editor)) {
+ normalizeLists(editor.dom, editor.getBody());
+ }
+ });
+ editor.on('keydown', e => {
+ if (e.keyCode === global$3.BACKSPACE) {
+ if (backspaceDelete(editor, false)) {
+ e.preventDefault();
+ }
+ } else if (e.keyCode === global$3.DELETE) {
+ if (backspaceDelete(editor, true)) {
+ e.preventDefault();
+ }
+ }
+ });
+ };
+
+ const get = editor => ({
+ backspaceDelete: isForward => {
+ backspaceDelete(editor, isForward);
+ }
+ });
+
+ const updateList = (editor, update) => {
+ const parentList = getParentList(editor);
+ if (parentList === null || isWithinNonEditableList(editor, parentList)) {
+ return;
+ }
+ editor.undoManager.transact(() => {
+ if (isObject(update.styles)) {
+ editor.dom.setStyles(parentList, update.styles);
+ }
+ if (isObject(update.attrs)) {
+ each(update.attrs, (v, k) => editor.dom.setAttrib(parentList, k, v));
+ }
+ });
+ };
+
+ const parseAlphabeticBase26 = str => {
+ const chars = reverse(trim(str).split(''));
+ const values = map(chars, (char, i) => {
+ const charValue = char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0) + 1;
+ return Math.pow(26, i) * charValue;
+ });
+ return foldl(values, (sum, v) => sum + v, 0);
+ };
+ const composeAlphabeticBase26 = value => {
+ value--;
+ if (value < 0) {
+ return '';
+ } else {
+ const remainder = value % 26;
+ const quotient = Math.floor(value / 26);
+ const rest = composeAlphabeticBase26(quotient);
+ const char = String.fromCharCode('A'.charCodeAt(0) + remainder);
+ return rest + char;
+ }
+ };
+ const isUppercase = str => /^[A-Z]+$/.test(str);
+ const isLowercase = str => /^[a-z]+$/.test(str);
+ const isNumeric = str => /^[0-9]+$/.test(str);
+ const deduceListType = start => {
+ if (isNumeric(start)) {
+ return 2;
+ } else if (isUppercase(start)) {
+ return 0;
+ } else if (isLowercase(start)) {
+ return 1;
+ } else if (isEmpty(start)) {
+ return 3;
+ } else {
+ return 4;
+ }
+ };
+ const parseStartValue = start => {
+ switch (deduceListType(start)) {
+ case 2:
+ return Optional.some({
+ listStyleType: Optional.none(),
+ start
+ });
+ case 0:
+ return Optional.some({
+ listStyleType: Optional.some('upper-alpha'),
+ start: parseAlphabeticBase26(start).toString()
+ });
+ case 1:
+ return Optional.some({
+ listStyleType: Optional.some('lower-alpha'),
+ start: parseAlphabeticBase26(start).toString()
+ });
+ case 3:
+ return Optional.some({
+ listStyleType: Optional.none(),
+ start: ''
+ });
+ case 4:
+ return Optional.none();
+ }
+ };
+ const parseDetail = detail => {
+ const start = parseInt(detail.start, 10);
+ if (is$2(detail.listStyleType, 'upper-alpha')) {
+ return composeAlphabeticBase26(start);
+ } else if (is$2(detail.listStyleType, 'lower-alpha')) {
+ return composeAlphabeticBase26(start).toLowerCase();
+ } else {
+ return detail.start;
+ }
+ };
+
+ const open = editor => {
+ const currentList = getParentList(editor);
+ if (!isOlNode(currentList) || isWithinNonEditableList(editor, currentList)) {
+ return;
+ }
+ editor.windowManager.open({
+ title: 'List Properties',
+ body: {
+ type: 'panel',
+ items: [{
+ type: 'input',
+ name: 'start',
+ label: 'Start list at number',
+ inputMode: 'numeric'
+ }]
+ },
+ initialData: {
+ start: parseDetail({
+ start: editor.dom.getAttrib(currentList, 'start', '1'),
+ listStyleType: Optional.from(editor.dom.getStyle(currentList, 'list-style-type'))
+ })
+ },
+ buttons: [
+ {
+ type: 'cancel',
+ name: 'cancel',
+ text: 'Cancel'
+ },
+ {
+ type: 'submit',
+ name: 'save',
+ text: 'Save',
+ primary: true
+ }
+ ],
+ onSubmit: api => {
+ const data = api.getData();
+ parseStartValue(data.start).each(detail => {
+ editor.execCommand('mceListUpdate', false, {
+ attrs: { start: detail.start === '1' ? '' : detail.start },
+ styles: { 'list-style-type': detail.listStyleType.getOr('') }
+ });
+ });
+ api.close();
+ }
+ });
+ };
+
+ const queryListCommandState = (editor, listName) => () => {
+ const parentList = getParentList(editor);
+ return isNonNullable(parentList) && parentList.nodeName === listName;
+ };
+ const registerDialog = editor => {
+ editor.addCommand('mceListProps', () => {
+ open(editor);
+ });
+ };
+ const register$2 = editor => {
+ editor.on('BeforeExecCommand', e => {
+ const cmd = e.command.toLowerCase();
+ if (cmd === 'indent') {
+ indentListSelection(editor);
+ } else if (cmd === 'outdent') {
+ outdentListSelection(editor);
+ }
+ });
+ editor.addCommand('InsertUnorderedList', (ui, detail) => {
+ toggleList(editor, 'UL', detail);
+ });
+ editor.addCommand('InsertOrderedList', (ui, detail) => {
+ toggleList(editor, 'OL', detail);
+ });
+ editor.addCommand('InsertDefinitionList', (ui, detail) => {
+ toggleList(editor, 'DL', detail);
+ });
+ editor.addCommand('RemoveList', () => {
+ flattenListSelection(editor);
+ });
+ registerDialog(editor);
+ editor.addCommand('mceListUpdate', (ui, detail) => {
+ if (isObject(detail)) {
+ updateList(editor, detail);
+ }
+ });
+ editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState(editor, 'UL'));
+ editor.addQueryStateHandler('InsertOrderedList', queryListCommandState(editor, 'OL'));
+ editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState(editor, 'DL'));
+ };
+
+ const setupTabKey = editor => {
+ editor.on('keydown', e => {
+ if (e.keyCode !== global$3.TAB || global$3.metaKeyPressed(e)) {
+ return;
+ }
+ editor.undoManager.transact(() => {
+ if (e.shiftKey ? outdentListSelection(editor) : indentListSelection(editor)) {
+ e.preventDefault();
+ }
+ });
+ });
+ };
+ const setup = editor => {
+ if (shouldIndentOnTab(editor)) {
+ setupTabKey(editor);
+ }
+ setup$1(editor);
+ };
+
+ const setupToggleButtonHandler = (editor, listName) => api => {
+ const toggleButtonHandler = e => {
+ api.setActive(inList(e.parents, listName));
+ api.setEnabled(!isWithinNonEditableList(editor, e.element));
+ };
+ return setNodeChangeHandler(editor, toggleButtonHandler);
+ };
+ const register$1 = editor => {
+ const exec = command => () => editor.execCommand(command);
+ if (!editor.hasPlugin('advlist')) {
+ editor.ui.registry.addToggleButton('numlist', {
+ icon: 'ordered-list',
+ active: false,
+ tooltip: 'Numbered list',
+ onAction: exec('InsertOrderedList'),
+ onSetup: setupToggleButtonHandler(editor, 'OL')
+ });
+ editor.ui.registry.addToggleButton('bullist', {
+ icon: 'unordered-list',
+ active: false,
+ tooltip: 'Bullet list',
+ onAction: exec('InsertUnorderedList'),
+ onSetup: setupToggleButtonHandler(editor, 'UL')
+ });
+ }
+ };
+
+ const setupMenuButtonHandler = (editor, listName) => api => {
+ const menuButtonHandler = e => api.setEnabled(inList(e.parents, listName) && !isWithinNonEditableList(editor, e.element));
+ return setNodeChangeHandler(editor, menuButtonHandler);
+ };
+ const register = editor => {
+ const listProperties = {
+ text: 'List properties...',
+ icon: 'ordered-list',
+ onAction: () => editor.execCommand('mceListProps'),
+ onSetup: setupMenuButtonHandler(editor, 'OL')
+ };
+ editor.ui.registry.addMenuItem('listprops', listProperties);
+ editor.ui.registry.addContextMenu('lists', {
+ update: node => {
+ const parentList = getParentList(editor, node);
+ return isOlNode(parentList) ? ['listprops'] : [];
+ }
+ });
+ };
+
+ var Plugin = () => {
+ global$6.add('lists', editor => {
+ register$3(editor);
+ if (!editor.hasPlugin('rtc', true)) {
+ setup(editor);
+ register$2(editor);
+ } else {
+ registerDialog(editor);
+ }
+ register$1(editor);
+ register(editor);
+ return get(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/lists/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/lists/plugin.min.js
new file mode 100644
index 00000000000..3174dfa8c66
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/lists/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(n=r=t,(o=String).prototype.isPrototypeOf(n)||r.constructor?.name===o.name)?"string":e;var n,r,o})(e)===t,n=t=>e=>typeof e===t,r=e("string"),o=e("object"),s=e("array"),i=n("boolean"),a=t=>!(t=>null==t)(t),l=n("function"),d=n("number"),c=()=>{},m=(t,e)=>t===e,u=t=>e=>!t(e),p=(!1,()=>false);class g{constructor(t,e){this.tag=t,this.value=e}static some(t){return new g(!0,t)}static none(){return g.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?g.some(t(this.value)):g.none()}bind(t){return this.tag?t(this.value):g.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:g.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(t??"Called getOrDie on None")}static from(t){return a(t)?g.some(t):g.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}g.singletonNone=new g(!1);const h=Array.prototype.slice,f=Array.prototype.indexOf,y=Array.prototype.push,C=(t,e)=>{return n=t,r=e,f.call(n,r)>-1;var n,r},v=(t,e)=>{for(let n=0,r=t.length;n{const n=t.length,r=new Array(n);for(let o=0;o{for(let n=0,r=t.length;n{const n=[];for(let r=0,o=t.length;r(S(t,((t,r)=>{n=e(n,t,r)})),n),O=(t,e,n)=>{for(let r=0,o=t.length;rO(t,e,p),T=(t,e)=>(t=>{const e=[];for(let n=0,r=t.length;n{const e=h.call(t,0);return e.reverse(),e},w=(t,e)=>e>=0&&ew(t,0),E=t=>w(t,t.length-1),B=(t,e)=>{const n=[],r=l(e)?t=>v(n,(n=>e(n,t))):t=>C(n,t);for(let e=0,o=t.length;et.exists((t=>n(t,e))),I=(t,e,n)=>t.isSome()&&e.isSome()?g.some(n(t.getOrDie(),e.getOrDie())):g.none(),P=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},M=(t,e)=>{const n=(e||document).createElement(t);return P(n)},R=P,U=(t,e)=>t.dom===e.dom;"undefined"!=typeof window?window:Function("return this;")();const $=t=>t.dom.nodeName.toLowerCase(),_=(1,t=>1===(t=>t.dom.nodeType)(t));const H=t=>e=>_(e)&&$(e)===t,j=t=>g.from(t.dom.parentNode).map(R),F=t=>b(t.dom.childNodes,R),K=(t,e)=>{const n=t.dom.childNodes;return g.from(n[e]).map(R)},V=t=>K(t,0),z=t=>K(t,t.dom.childNodes.length-1),Q=(t,e,n)=>{let r=t.dom;const o=l(n)?n:p;for(;r.parentNode;){r=r.parentNode;const t=R(r);if(e(t))return g.some(t);if(o(t))break}return g.none()},q=(t,e,n)=>((t,e,n,r,o)=>r(n)?g.some(n):l(o)&&o(n)?g.none():e(n,r,o))(0,Q,t,e,n),W=(t,e)=>{j(t).each((n=>{n.dom.insertBefore(e.dom,t.dom)}))},Z=(t,e)=>{t.dom.appendChild(e.dom)},G=(t,e)=>{S(e,(e=>{Z(t,e)}))},J=t=>{t.dom.textContent="",S(F(t),(t=>{X(t)}))},X=t=>{const e=t.dom;null!==e.parentNode&&e.parentNode.removeChild(e)};var Y=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),tt=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),et=tinymce.util.Tools.resolve("tinymce.util.VK");const nt=t=>b(t,R),rt=Object.keys,ot=(t,e)=>{const n=rt(t);for(let r=0,o=n.length;r{const n=t.dom;ot(e,((t,e)=>{((t,e,n)=>{if(!(r(n)||i(n)||d(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(n,e,t)}))},it=t=>L(t.dom.attributes,((t,e)=>(t[e.name]=e.value,t)),{}),at=t=>((t,e)=>R(t.dom.cloneNode(!0)))(t),lt=(t,e)=>{const n=((t,e)=>{const n=M(e),r=it(t);return st(n,r),n})(t,e);((t,e)=>{const n=(t=>g.from(t.dom.nextSibling).map(R))(t);n.fold((()=>{j(t).each((t=>{Z(t,e)}))}),(t=>{W(t,e)}))})(t,n);const r=F(t);return G(n,r),X(t),n};var dt=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),ct=tinymce.util.Tools.resolve("tinymce.util.Tools");const mt=t=>e=>a(e)&&e.nodeName.toLowerCase()===t,ut=t=>e=>a(e)&&t.test(e.nodeName),pt=t=>a(t)&&3===t.nodeType,gt=t=>a(t)&&1===t.nodeType,ht=ut(/^(OL|UL|DL)$/),ft=ut(/^(OL|UL)$/),yt=mt("ol"),Ct=ut(/^(LI|DT|DD)$/),vt=ut(/^(DT|DD)$/),bt=ut(/^(TH|TD)$/),St=mt("br"),Nt=(t,e)=>a(e)&&e.nodeName in t.schema.getTextBlockElements(),Lt=(t,e)=>a(t)&&t.nodeName in e,Ot=(t,e,n)=>{const r=t.isEmpty(e);return!(n&&t.select("span[data-mce-type=bookmark]",e).length>0)&&r},kt=(t,e)=>t.isChildOf(e,t.getRoot()),Tt=t=>e=>e.options.get(t),At=Tt("lists_indent_on_tab"),wt=Tt("forced_root_block"),Dt=Tt("forced_root_block_attrs"),Et=(t,e)=>{const n=t.dom,r=t.schema.getBlockElements(),o=n.createFragment(),s=wt(t),i=Dt(t);let a,l,d=!1;for(l=n.create(s,i),Lt(e.firstChild,r)||o.appendChild(l);a=e.firstChild;){const t=a.nodeName;d||"SPAN"===t&&"bookmark"===a.getAttribute("data-mce-type")||(d=!0),Lt(a,r)?(o.appendChild(a),l=null):(l||(l=n.create(s,i),o.appendChild(l)),l.appendChild(a))}return!d&&l&&l.appendChild(n.create("br",{"data-mce-bogus":"1"})),o},Bt=dt.DOM,xt=H("dd"),It=H("dt"),Pt=(t,e)=>{var n;xt(e)?lt(e,"dt"):It(e)&&(n=e,g.from(n.dom.parentElement).map(R)).each((n=>((t,e,n)=>{const r=Bt.select('span[data-mce-type="bookmark"]',e),o=Et(t,n),s=Bt.createRng();s.setStartAfter(n),s.setEndAfter(e);const i=s.extractContents();for(let e=i.firstChild;e;e=e.firstChild)if("LI"===e.nodeName&&t.dom.isEmpty(e)){Bt.remove(e);break}t.dom.isEmpty(i)||Bt.insertAfter(i,e),Bt.insertAfter(o,e);const a=n.parentElement;a&&Ot(t.dom,a)&&(t=>{const e=t.parentNode;e&&ct.each(r,(t=>{e.insertBefore(t,n.parentNode)})),Bt.remove(t)})(a),Bt.remove(n),Ot(t.dom,e)&&Bt.remove(e)})(t,n.dom,e.dom)))},Mt=t=>{It(t)&<(t,"dd")},Rt=(t,e)=>{if(pt(t))return{container:t,offset:e};const n=Y.getNode(t,e);return pt(n)?{container:n,offset:e>=t.childNodes.length?n.data.length:0}:n.previousSibling&&pt(n.previousSibling)?{container:n.previousSibling,offset:n.previousSibling.data.length}:n.nextSibling&&pt(n.nextSibling)?{container:n.nextSibling,offset:0}:{container:t,offset:e}},Ut=t=>{const e=t.cloneRange(),n=Rt(t.startContainer,t.startOffset);e.setStart(n.container,n.offset);const r=Rt(t.endContainer,t.endOffset);return e.setEnd(r.container,r.offset),e},$t=["OL","UL","DL"],_t=$t.join(","),Ht=(t,e)=>{const n=e||t.selection.getStart(!0);return t.dom.getParent(n,_t,Kt(t,n))},jt=t=>{const e=t.selection.getSelectedBlocks();return N(((t,e)=>{const n=ct.map(e,(e=>t.dom.getParent(e,"li,dd,dt",Kt(t,e))||e));return B(n)})(t,e),Ct)},Ft=(t,e)=>{const n=t.dom.getParents(e,"TD,TH");return n.length>0?n[0]:t.getBody()},Kt=(t,e)=>{const n=t.dom.getParents(e,t.dom.isBlock),r=k(n,(e=>{return n=t.schema,!ht(r=e)&&!Ct(r)&&v($t,(t=>n.isValidChild(r.nodeName,t)));var n,r}));return r.getOr(t.getBody())},Vt=(t,e)=>{const n=t.dom.getParents(e,"ol,ul",Kt(t,e));return E(n)},zt=(t,e)=>{const n=b(e,(e=>Vt(t,e).getOr(e)));return B(n)},Qt=t=>/\btox\-/.test(t.className),qt=(t,e)=>O(t,ht,bt).exists((t=>t.nodeName===e&&!Qt(t))),Wt=(t,e)=>null!==e&&"false"===t.dom.getContentEditableParent(e),Zt=(t,e)=>{const n=t.dom.getParent(e,"ol,ul,dl");return Wt(t,n)},Gt=(t,e)=>{const n=t.selection.getNode();return e({parents:t.dom.getParents(n),element:n}),t.on("NodeChange",e),()=>t.off("NodeChange",e)},Jt=(t,e,n)=>t.dispatch("ListMutation",{action:e,element:n}),Xt=(Yt=/^\s+|\s+$/g,t=>t.replace(Yt,""));var Yt;const te=(t,e,n)=>{((t,e,n)=>{if(!r(n))throw console.error("Invalid call to CSS.set. Property ",e,":: Value ",n,":: Element ",t),new Error("CSS value must be a string: "+n);(t=>void 0!==t.style&&l(t.style.getPropertyValue))(t)&&t.style.setProperty(e,n)})(t.dom,e,n)},ee=(t,e)=>{Z(t.item,e.list)},ne=(t,e)=>{const n={list:M(e,t),item:M("li",t)};return Z(n.list,n.item),n},re=t=>((t,e)=>{const n=t.dom;if(1!==n.nodeType)return!1;{const t=n;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}})(t,"OL,UL"),oe=t=>V(t).exists(re),se=t=>t.depth>0,ie=t=>t.isSelected,ae=t=>{const e=F(t),n=z(t).exists(re)?e.slice(0,-1):e;return b(n,at)},le=t=>(S(t,((e,n)=>{((t,e)=>{const n=t[e].depth,r=t=>t.depth===n&&!t.dirty,o=t=>t.depthO(t.slice(e+1),r,o)))})(t,n).fold((()=>{e.dirty&&(t=>{t.listAttributes=((t,e)=>{const n={};var r;return((t,e,n,r)=>{ot(t,((t,o)=>{(e(t,o)?n:r)(t,o)}))})(t,e,(r=n,(t,e)=>{r[e]=t}),c),n})(t.listAttributes,((t,e)=>"start"!==e))})(e)}),(t=>{return r=t,(n=e).listType=r.listType,void(n.listAttributes={...r.listAttributes});var n,r}))})),t),de=(t,e,n,r)=>V(r).filter(re).fold((()=>{e.each((t=>{U(t.start,r)&&n.set(!0)}));const o=((t,e,n)=>j(t).filter(_).map((r=>({depth:e,dirty:!1,isSelected:n,content:ae(t),itemAttributes:it(t),listAttributes:it(r),listType:$(r)}))))(r,t,n.get());e.each((t=>{U(t.end,r)&&n.set(!1)}));const s=z(r).filter(re).map((r=>ce(t,e,n,r))).getOr([]);return o.toArray().concat(s)}),(r=>ce(t,e,n,r))),ce=(t,e,n,r)=>T(F(r),(r=>(re(r)?ce:de)(t+1,e,n,r))),me=(t,e)=>{const n=le(e);return((t,e)=>{const n=L(e,((e,n)=>n.depth>e.length?((t,e,n)=>{const r=((t,e,n)=>{const r=[];for(let o=0;o{for(let e=1;e{for(let e=0;e{st(t.list,e.listAttributes),st(t.item,e.itemAttributes),G(t.item,e.content)}))})(r,n),o=r,I(E(e),D(o),ee),e.concat(r)})(t,e,n):((t,e,n)=>{const r=e.slice(0,n.depth);return E(r).each((e=>{const r=((t,e,n)=>{const r=M("li",t);return st(r,e),G(r,n),r})(t,n.itemAttributes,n.content);((t,e)=>{Z(t.list,e),t.item=e})(e,r),((t,e)=>{$(t.list)!==e.listType&&(t.list=lt(t.list,e.listType)),st(t.list,e.listAttributes)})(e,n)})),r})(t,e,n)),[]);return D(n).map((t=>t.list))})(t.contentDocument,n).toArray()},ue=(t,e,n)=>{const r=((t,e)=>{const n=(t=>{let e=!1;return{get:()=>e,set:t=>{e=t}}})();return b(t,(t=>({sourceList:t,entries:ce(0,e,n,t)})))})(e,(t=>{const e=b(jt(t),R);return I(k(e,u(oe)),k(A(e),u(oe)),((t,e)=>({start:t,end:e})))})(t));S(r,(e=>{((t,e)=>{S(N(t,ie),(t=>((t,e)=>{switch(t){case"Indent":e.depth++;break;case"Outdent":e.depth--;break;case"Flatten":e.depth=0}e.dirty=!0})(e,t)))})(e.entries,n);const r=((t,e)=>T(((t,e)=>{if(0===t.length)return[];{let n=e(t[0]);const r=[];let o=[];for(let s=0,i=t.length;sD(e).exists(se)?me(t,e):((t,e)=>{const n=le(e);return b(n,(e=>{const n=((t,e)=>{const n=document.createDocumentFragment();return S(t,(t=>{n.appendChild(t.dom)})),R(n)})(e.content);return R(Et(t,n.dom))}))})(t,e))))(t,e.entries);var o;S(r,(e=>{Jt(t,"Indent"===n?"IndentList":"OutdentList",e.dom)})),o=e.sourceList,S(r,(t=>{W(o,t)})),X(e.sourceList)}))},pe=(t,e)=>{const n=nt((t=>{const e=(t=>{const e=Vt(t,t.selection.getStart()),n=N(t.selection.getSelectedBlocks(),ft);return e.toArray().concat(n)})(t);return zt(t,e)})(t)),r=nt((t=>N(jt(t),vt))(t));let o=!1;if(n.length||r.length){const s=t.selection.getBookmark();ue(t,n,e),((t,e,n)=>{S(n,"Indent"===e?Mt:e=>Pt(t,e))})(t,e,r),t.selection.moveToBookmark(s),t.selection.setRng(Ut(t.selection.getRng())),t.nodeChanged(),o=!0}return o},ge=(t,e)=>!(t=>{const e=Ht(t);return Wt(t,e)})(t)&&pe(t,e),he=t=>ge(t,"Indent"),fe=t=>ge(t,"Outdent"),ye=t=>ge(t,"Flatten");var Ce=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const ve=dt.DOM,be=t=>{const e={},n=n=>{let r=t[n?"startContainer":"endContainer"],o=t[n?"startOffset":"endOffset"];if(gt(r)){const t=ve.create("span",{"data-mce-type":"bookmark"});r.hasChildNodes()?(o=Math.min(o,r.childNodes.length-1),n?r.insertBefore(t,r.childNodes[o]):ve.insertAfter(t,r.childNodes[o])):r.appendChild(t),r=t,o=0}e[n?"startContainer":"endContainer"]=r,e[n?"startOffset":"endOffset"]=o};return n(!0),t.collapsed||n(),e},Se=t=>{const e=e=>{let n=t[e?"startContainer":"endContainer"],r=t[e?"startOffset":"endOffset"];if(n){if(gt(n)&&n.parentNode){const t=n;r=(t=>{let e=t.parentNode?.firstChild,n=0;for(;e;){if(e===t)return n;gt(e)&&"bookmark"===e.getAttribute("data-mce-type")||n++,e=e.nextSibling}return-1})(n),n=n.parentNode,ve.remove(t),!n.hasChildNodes()&&ve.isBlock(n)&&n.appendChild(ve.create("br"))}t[e?"startContainer":"endContainer"]=n,t[e?"startOffset":"endOffset"]=r}};e(!0),e();const n=ve.createRng();return n.setStart(t.startContainer,t.startOffset),t.endContainer&&n.setEnd(t.endContainer,t.endOffset),Ut(n)},Ne=t=>{switch(t){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},Le=(t,e)=>{ct.each(e,((e,n)=>{t.setAttribute(n,e)}))},Oe=(t,e,n)=>{((t,e,n)=>{const r=n["list-style-type"]?n["list-style-type"]:null;t.setStyle(e,"list-style-type",r)})(t,e,n),((t,e,n)=>{Le(e,n["list-attributes"]),ct.each(t.select("li",e),(t=>{Le(t,n["list-item-attributes"])}))})(t,e,n)},ke=(t,e,n,r)=>{let o=e[n?"startContainer":"endContainer"];const s=e[n?"startOffset":"endOffset"];for(gt(o)&&(o=o.childNodes[Math.min(s,o.childNodes.length-1)]||o),!n&&St(o.nextSibling)&&(o=o.nextSibling);o.parentNode!==r;){const e=o.parentNode;if(Nt(t,o))return o;if(/^(TD|TH)$/.test(e.nodeName))return o;o=e}return o},Te=(t,e,n)=>{const r=t.selection.getRng();let o="LI";const s=Kt(t,t.selection.getStart(!0)),i=t.dom;if("false"===i.getContentEditable(t.selection.getNode()))return;"DL"===(e=e.toUpperCase())&&(o="DT");const a=be(r),l=((t,e,n)=>{const r=[],o=t.dom,s=ke(t,e,!0,n),i=ke(t,e,!1,n);let a;const l=[];for(let t=s;t&&(l.push(t),t!==i);t=t.nextSibling);return ct.each(l,(e=>{if(Nt(t,e))return r.push(e),void(a=null);if(o.isBlock(e)||St(e))return St(e)&&o.remove(e),void(a=null);const s=e.nextSibling;Ce.isBookmarkNode(e)&&(ht(s)||Nt(t,s)||!s&&e.parentNode===n)?a=null:(a||(a=o.create("p"),e.parentNode?.insertBefore(a,e),r.push(a)),a.appendChild(e))})),r})(t,r,s);ct.each(l,(r=>{let s;const a=r.previousSibling,l=r.parentNode;Ct(l)||(a&&ht(a)&&a.nodeName===e&&((t,e,n)=>{const r=t.getStyle(e,"list-style-type");let o=n?n["list-style-type"]:"";return o=null===o?"":o,r===o})(i,a,n)?(s=a,r=i.rename(r,o),a.appendChild(r)):(s=i.create(e),l.insertBefore(s,r),s.appendChild(r),r=i.rename(r,o)),((t,e,n)=>{ct.each(["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"],(n=>t.setStyle(e,n,"")))})(i,r),Oe(i,s,n),we(t.dom,s))})),t.selection.setRng(Se(a))},Ae=(t,e,n)=>{return((t,e)=>ht(t)&&t.nodeName===e?.nodeName)(e,n)&&((t,e,n)=>t.getStyle(e,"list-style-type",!0)===t.getStyle(n,"list-style-type",!0))(t,e,n)&&(r=n,e.className===r.className);var r},we=(t,e)=>{let n,r=e.nextSibling;if(Ae(t,e,r)){const o=r;for(;n=o.firstChild;)e.appendChild(n);t.remove(o)}if(r=e.previousSibling,Ae(t,e,r)){const o=r;for(;n=o.lastChild;)e.insertBefore(n,e.firstChild);t.remove(o)}},De=t=>"list-style-type"in t,Ee=(t,e,n)=>{const r=Ht(t);if(Zt(t,r))return;const s=(t=>{const e=Ht(t),n=t.selection.getSelectedBlocks();return((t,e)=>a(t)&&1===e.length&&e[0]===t)(e,n)?(t=>N(t.querySelectorAll(_t),ht))(e):N(n,(t=>ht(t)&&e!==t))})(t),i=o(n)?n:{};s.length>0?((t,e,n,r,o)=>{const s=ht(e);if(s&&e.nodeName===r&&!De(o))ye(t);else{Te(t,r,o);const i=be(t.selection.getRng()),a=s?[e,...n]:n;ct.each(a,(e=>{((t,e,n,r)=>{if(e.nodeName!==n){const o=t.dom.rename(e,n);Oe(t.dom,o,r),Jt(t,Ne(n),o)}else Oe(t.dom,e,r),Jt(t,Ne(n),e)})(t,e,r,o)})),t.selection.setRng(Se(i))}})(t,r,s,e,i):((t,e,n,r)=>{if(e!==t.getBody())if(e)if(e.nodeName!==n||De(r)||Qt(e)){const o=be(t.selection.getRng());Oe(t.dom,e,r);const s=t.dom.rename(e,n);we(t.dom,s),t.selection.setRng(Se(o)),Te(t,n,r),Jt(t,Ne(n),s)}else ye(t);else Te(t,n,r),Jt(t,Ne(n),e)})(t,r,e,i)},Be=dt.DOM,xe=(t,e)=>{const n=ct.grep(t.select("ol,ul",e));ct.each(n,(e=>{((t,e)=>{const n=e.parentElement;if(n&&"LI"===n.nodeName&&n.firstChild===e){const r=n.previousSibling;r&&"LI"===r.nodeName?(r.appendChild(e),Ot(t,n)&&Be.remove(n)):Be.setStyle(n,"listStyleType","none")}if(ht(n)){const t=n.previousSibling;t&&"LI"===t.nodeName&&t.appendChild(e)}})(t,e)}))},Ie=(t,e,n,r)=>{let o=e.startContainer;const s=e.startOffset;if(pt(o)&&(n?s0))return o;const i=t.schema.getNonEmptyElements();gt(o)&&(o=Y.getNode(o,s));const a=new tt(o,r);n&&((t,e)=>!!St(e)&&t.isBlock(e.nextSibling)&&!St(e.previousSibling))(t.dom,o)&&a.next();const l=n?a.next.bind(a):a.prev2.bind(a);for(;o=l();){if("LI"===o.nodeName&&!o.hasChildNodes())return o;if(i[o.nodeName])return o;if(pt(o)&&o.data.length>0)return o}return null},Pe=(t,e)=>{const n=e.childNodes;return 1===n.length&&!ht(n[0])&&t.isBlock(n[0])},Me=(t,e,n)=>{let r;const o=e.parentNode;if(!kt(t,e)||!kt(t,n))return;ht(n.lastChild)&&(r=n.lastChild),o===n.lastChild&&St(o.previousSibling)&&t.remove(o.previousSibling);const s=n.lastChild;s&&St(s)&&e.hasChildNodes()&&t.remove(s),Ot(t,n,!0)&&J(R(n)),((t,e,n)=>{let r;const o=Pe(t,n)?n.firstChild:n;if(((t,e)=>{Pe(t,e)&&t.remove(e.firstChild,!0)})(t,e),!Ot(t,e,!0))for(;r=e.firstChild;)o.appendChild(r)})(t,e,n),r&&n.appendChild(r);const i=((t,e)=>{const n=t.dom,r=e.dom;return n!==r&&n.contains(r)})(R(n),R(e))?t.getParents(e,ht,n):[];t.remove(e),S(i,(e=>{Ot(t,e)&&e!==t.getRoot()&&t.remove(e)}))},Re=(t,e)=>{const n=t.dom,r=t.selection,o=r.getStart(),s=Ft(t,o),i=n.getParent(r.getStart(),"LI",s);if(i){const o=i.parentElement;if(o===t.getBody()&&Ot(n,o))return!0;const a=Ut(r.getRng()),l=n.getParent(Ie(t,a,e,s),"LI",s);if(l&&l!==i)return t.undoManager.transact((()=>{var n;e?((t,e,n,r)=>{const o=t.dom;if(o.isEmpty(r))((t,e,n)=>{J(R(n)),Me(t.dom,e,n),t.selection.setCursorLocation(n,0)})(t,n,r);else{const s=be(e);Me(o,n,r),t.selection.setRng(Se(s))}})(t,a,l,i):(n=i).parentNode?.firstChild===n?fe(t):((t,e,n,r)=>{const o=be(e);Me(t.dom,n,r);const s=Se(o);t.selection.setRng(s)})(t,a,i,l)})),!0;if(!l&&!e&&0===a.startOffset&&0===a.endOffset)return t.undoManager.transact((()=>{ye(t)})),!0}return!1},Ue=t=>{const e=t.selection.getStart(),n=Ft(t,e);return t.dom.getParent(e,"LI,DT,DD",n)||jt(t).length>0},$e=(t,e)=>{const n=t.selection;return!Zt(t,n.getNode())&&(n.isCollapsed()?((t,e)=>Re(t,e)||((t,e)=>{const n=t.dom,r=t.selection.getStart(),o=Ft(t,r),s=n.getParent(r,n.isBlock,o);if(s&&n.isEmpty(s)){const r=Ut(t.selection.getRng()),i=n.getParent(Ie(t,r,e,o),"LI",o);if(i){const a=t=>C(["td","th","caption"],$(t)),l=t=>t.dom===o;return!!((t,e,n=m)=>I(t,e,n).getOr(t.isNone()&&e.isNone()))(q(R(i),a,l),q(R(r.startContainer),a,l),U)&&(t.undoManager.transact((()=>{((t,e,n)=>{const r=t.getParent(e.parentNode,t.isBlock,n);t.remove(e),r&&t.isEmpty(r)&&t.remove(r)})(n,s,o),we(n,i.parentNode),t.selection.select(i,!0),t.selection.collapse(e)})),!0)}}return!1})(t,e))(t,e):(t=>!!Ue(t)&&(t.undoManager.transact((()=>{t.execCommand("Delete"),xe(t.dom,t.getBody())})),!0))(t))},_e=t=>{const e=A(Xt(t).split("")),n=b(e,((t,e)=>{const n=t.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,e)*n}));return L(n,((t,e)=>t+e),0)},He=t=>{if(--t<0)return"";{const e=t%26,n=Math.floor(t/26);return He(n)+String.fromCharCode("A".charCodeAt(0)+e)}},je=t=>{const e=parseInt(t.start,10);return x(t.listStyleType,"upper-alpha")?He(e):x(t.listStyleType,"lower-alpha")?He(e).toLowerCase():t.start},Fe=(t,e)=>()=>{const n=Ht(t);return a(n)&&n.nodeName===e},Ke=t=>{t.addCommand("mceListProps",(()=>{(t=>{const e=Ht(t);yt(e)&&!Zt(t,e)&&t.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:je({start:t.dom.getAttrib(e,"start","1"),listStyleType:g.from(t.dom.getStyle(e,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:e=>{(t=>{switch((t=>/^[0-9]+$/.test(t)?2:/^[A-Z]+$/.test(t)?0:/^[a-z]+$/.test(t)?1:t.length>0?4:3)(t)){case 2:return g.some({listStyleType:g.none(),start:t});case 0:return g.some({listStyleType:g.some("upper-alpha"),start:_e(t).toString()});case 1:return g.some({listStyleType:g.some("lower-alpha"),start:_e(t).toString()});case 3:return g.some({listStyleType:g.none(),start:""});case 4:return g.none()}})(e.getData().start).each((e=>{t.execCommand("mceListUpdate",!1,{attrs:{start:"1"===e.start?"":e.start},styles:{"list-style-type":e.listStyleType.getOr("")}})})),e.close()}})})(t)}))},Ve=(t,e)=>n=>Gt(t,(r=>{n.setActive(qt(r.parents,e)),n.setEnabled(!Zt(t,r.element))})),ze=(t,e)=>n=>Gt(t,(r=>n.setEnabled(qt(r.parents,e)&&!Zt(t,r.element))));t.add("lists",(t=>((t=>{(0,t.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(t),t.hasPlugin("rtc",!0)?Ke(t):((t=>{At(t)&&(t=>{t.on("keydown",(e=>{e.keyCode!==et.TAB||et.metaKeyPressed(e)||t.undoManager.transact((()=>{(e.shiftKey?fe(t):he(t))&&e.preventDefault()}))}))})(t),(t=>{t.on("ExecCommand",(e=>{const n=e.command.toLowerCase();"delete"!==n&&"forwarddelete"!==n||!Ue(t)||xe(t.dom,t.getBody())})),t.on("keydown",(e=>{e.keyCode===et.BACKSPACE?$e(t,!1)&&e.preventDefault():e.keyCode===et.DELETE&&$e(t,!0)&&e.preventDefault()}))})(t)})(t),(t=>{t.on("BeforeExecCommand",(e=>{const n=e.command.toLowerCase();"indent"===n?he(t):"outdent"===n&&fe(t)})),t.addCommand("InsertUnorderedList",((e,n)=>{Ee(t,"UL",n)})),t.addCommand("InsertOrderedList",((e,n)=>{Ee(t,"OL",n)})),t.addCommand("InsertDefinitionList",((e,n)=>{Ee(t,"DL",n)})),t.addCommand("RemoveList",(()=>{ye(t)})),Ke(t),t.addCommand("mceListUpdate",((e,n)=>{o(n)&&((t,e)=>{const n=Ht(t);null===n||Zt(t,n)||t.undoManager.transact((()=>{o(e.styles)&&t.dom.setStyles(n,e.styles),o(e.attrs)&&ot(e.attrs,((e,r)=>t.dom.setAttrib(n,r,e)))}))})(t,n)})),t.addQueryStateHandler("InsertUnorderedList",Fe(t,"UL")),t.addQueryStateHandler("InsertOrderedList",Fe(t,"OL")),t.addQueryStateHandler("InsertDefinitionList",Fe(t,"DL"))})(t)),(t=>{const e=e=>()=>t.execCommand(e);t.hasPlugin("advlist")||(t.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:e("InsertOrderedList"),onSetup:Ve(t,"OL")}),t.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:e("InsertUnorderedList"),onSetup:Ve(t,"UL")}))})(t),(t=>{const e={text:"List properties...",icon:"ordered-list",onAction:()=>t.execCommand("mceListProps"),onSetup:ze(t,"OL")};t.ui.registry.addMenuItem("listprops",e),t.ui.registry.addContextMenu("lists",{update:e=>{const n=Ht(t,e);return yt(n)?["listprops"]:[]}})})(t),(t=>({backspaceDelete:e=>{$e(t,e)}}))(t))))}();
\ No newline at end of file
diff --git a/lib/editor/tiny/js/tinymce/plugins/media/plugin.js b/lib/editor/tiny/js/tinymce/plugins/media/plugin.js
new file mode 100644
index 00000000000..0b53bc86c8c
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/media/plugin.js
@@ -0,0 +1,1164 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+
+(function () {
+ 'use strict';
+
+ var global$6 = tinymce.util.Tools.resolve('tinymce.PluginManager');
+
+ const hasProto = (v, constructor, predicate) => {
+ if (predicate(v, constructor.prototype)) {
+ return true;
+ } else {
+ return v.constructor?.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 ?? '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.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() ?? '';
+ return get$1(mimes, fileEnd).getOr('');
+ };
+
+ 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) : {};
+ if (isNonNullable(data.width)) {
+ styleMap['max-width'] = addPx(data.width);
+ }
+ if (isNonNullable(data.height)) {
+ 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&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;
+ if (isNonNullable(match)) {
+ 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 '';
+ }
+ };
+ const getFlashHtml = data => {
+ let html = '';
+ if (data.poster) {
+ html += ' ';
+ }
+ html += ' ';
+ return html;
+ };
+ const getAudioHtml = (data, audioTemplateCallback) => {
+ if (audioTemplateCallback) {
+ return audioTemplateCallback(data);
+ } else {
+ return '' + (data.altsource ? '\n \n' : '') + ' ';
+ }
+ };
+ const getVideoHtml = (data, videoTemplateCallback) => {
+ if (videoTemplateCallback) {
+ return videoTemplateCallback(data);
+ } else {
+ return '\n' + ' \n' + (data.altsource ? ' \n' : '') + ' ';
+ }
+ };
+ const getScriptHtml = data => {
+ return '';
+ };
+ 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 && sourceInput !== 'dimensions' ? 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 isString(nodeClass) && /\btiny-pageembed\b/.test(nodeClass);
+ };
+ const isWithinEmbedWrapper = node => {
+ let tempNode = node;
+ while (tempNode = tempNode.parent) {
+ if (tempNode.attr('data-ephox-embed-iri') || isPageEmbedWrapper(tempNode)) {
+ 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);
+ if (rule) {
+ 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 && node.firstChild) {
+ 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();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/media/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/media/plugin.min.js
new file mode 100644
index 00000000000..400c66ef485
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/media/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(o=String).prototype.isPrototypeOf(r)||a.constructor?.name===o.name)?"string":t;var r,a,o})(t)===e,r=t("string"),a=t("object"),o=t("array"),s=e=>!(e=>null==e)(e);class i{constructor(e,t){this.tag=e,this.value=t}static some(e){return new i(!0,e)}static none(){return i.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?i.some(e(this.value)):i.none()}bind(e){return this.tag?e(this.value):i.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:i.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(e??"Called getOrDie on None")}static from(e){return s(e)?i.some(e):i.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}i.singletonNone=new i(!1);const c=Array.prototype.push,n=(e,t)=>{for(let r=0,a=e.length;r{const t=[];for(let r=0,a=e.length;r h(e,t)?i.from(e[t]):i.none(),h=(e,t)=>u.call(e,t),p=e=>t=>t.options.get(e),g=p("audio_template_callback"),b=p("video_template_callback"),w=p("iframe_template_callback"),f=p("media_live_embeds"),y=p("media_filter_html"),v=p("media_url_resolver"),x=p("media_alt_source"),_=p("media_poster"),j=p("media_dimensions");var k=tinymce.util.Tools.resolve("tinymce.util.Tools"),O=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),A=tinymce.util.Tools.resolve("tinymce.html.DomParser");const S=O.DOM,C=e=>e.replace(/px$/,""),D=e=>{const t=e.attr("style"),r=t?S.parseStyle(t):{};return{type:"ephox-embed-iri",source:e.attr("data-ephox-embed-iri"),altsource:"",poster:"",width:d(r,"max-width").map(C).getOr(""),height:d(r,"max-height").map(C).getOr("")}},T=(e,t)=>{let r={};for(let a=A({validate:!1,forced_root_block:!1},t).parse(e);a;a=a.walk())if(1===a.type){const e=a.name;if(a.attr("data-ephox-embed-iri")){r=D(a);break}r.source||"param"!==e||(r.source=a.attr("movie")),"iframe"!==e&&"object"!==e&&"embed"!==e&&"video"!==e&&"audio"!==e||(r.type||(r.type=e),r=k.extend(a.attributes.map,r)),"script"===e&&(r={type:"script",source:a.attr("src")}),"source"===e&&(r.source?r.altsource||(r.altsource=a.attr("src")):r.source=a.attr("src")),"img"!==e||r.poster||(r.poster=a.attr("src"))}return r.source=r.source||r.src||"",r.altsource=r.altsource||"",r.poster=r.poster||"",r},$=e=>{const t=e.toLowerCase().split(".").pop()??"";return d({mp3:"audio/mpeg",m4a:"audio/x-m4a",wav:"audio/wav",mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",swf:"application/x-shockwave-flash"},t).getOr("")};var z=tinymce.util.Tools.resolve("tinymce.html.Node"),M=tinymce.util.Tools.resolve("tinymce.html.Serializer");const F=(e,t={})=>A({forced_root_block:!1,validate:!1,allow_conditional_comments:!0,...t},e),N=O.DOM,R=e=>/^[0-9.]+$/.test(e)?e+"px":e,U=(e,t)=>{const r=t.attr("style"),a=r?N.parseStyle(r):{};s(e.width)&&(a["max-width"]=R(e.width)),s(e.height)&&(a["max-height"]=R(e.height)),t.attr("style",N.serializeStyle(a))},P=["source","altsource"],E=(e,t,r,a)=>{let o=0,s=0;const i=F(a);i.addNodeFilter("source",(e=>o=e.length));const c=i.parse(e);for(let e=c;e;e=e.walk())if(1===e.type){const a=e.name;if(e.attr("data-ephox-embed-iri")){U(t,e);break}switch(a){case"video":case"object":case"embed":case"img":case"iframe":void 0!==t.height&&void 0!==t.width&&(e.attr("width",t.width),e.attr("height",t.height))}if(r)switch(a){case"video":e.attr("poster",t.poster),e.attr("src",null);for(let r=o;r<2;r++)if(t[P[r]]){const a=new z("source",1);a.attr("src",t[P[r]]),a.attr("type",t[P[r]+"mime"]||null),e.append(a)}break;case"iframe":e.attr("src",t.source);break;case"object":const r=e.getAll("img").length>0;if(t.poster&&!r){e.attr("src",t.poster);const r=new z("img",1);r.attr("src",t.poster),r.attr("width",t.width),r.attr("height",t.height),e.append(r)}break;case"source":if(s<2&&(e.attr("src",t[P[s]]),e.attr("type",t[P[s]+"mime"]||null),!t[P[s]])){e.remove();continue}s++;break;case"img":t.poster||e.remove()}}return M({},a).serialize(c)},L=[{regex:/youtu\.be\/([\w\-_\?&=.]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$2?$4",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{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:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?title=0&byline=0",allowFullscreen:!0},{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:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0},{regex:/dai\.ly\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],I=(e,t)=>{const r=(e=>{const t=e.match(/^(https?:\/\/|www\.)(.+)$/i);return t&&t.length>1?"www."===t[1]?"https://":t[1]:"https://"})(t),a=e.regex.exec(t);let o=r+e.url;if(s(a))for(let e=0;e a[e]?a[e]:""));return o.replace(/\?$/,"")},B=(e,t)=>{const r=k.extend({},t);if(!r.source&&(k.extend(r,T(r.embed??"",e.schema)),!r.source))return"";r.altsource||(r.altsource=""),r.poster||(r.poster=""),r.source=e.convertURL(r.source,"source"),r.altsource=e.convertURL(r.altsource,"source"),r.sourcemime=$(r.source),r.altsourcemime=$(r.altsource),r.poster=e.convertURL(r.poster,"poster");const a=(e=>{const t=L.filter((t=>t.regex.test(e)));return t.length>0?k.extend({},t[0],{url:I(t[0],e)}):null})(r.source);if(a&&(r.source=a.url,r.type=a.type,r.allowfullscreen=a.allowFullscreen,r.width=r.width||String(a.w),r.height=r.height||String(a.h)),r.embed)return E(r.embed,r,!0,e.schema);{const t=g(e),a=b(e),o=w(e);return r.width=r.width||"300",r.height=r.height||"150",k.each(r,((t,a)=>{r[a]=e.dom.encode(""+t)})),"iframe"===r.type?((e,t)=>{if(t)return t(e);{const t=e.allowfullscreen?' allowFullscreen="1"':"";return'"}})(r,o):"application/x-shockwave-flash"===r.sourcemime?(e=>{let t='';return e.poster&&(t+=' '),t+=" ",t})(r):-1!==r.sourcemime.indexOf("audio")?((e,t)=>t?t(e):''+(e.altsource?'\n \n":"")+" ")(r,t):"script"===r.type?(e=>' ';
+ const directionality = editor.getBody().dir;
+ const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
+ const previewHtml = '' + '' + '' + headHtml + '' + '' + editor.getContent() + preventClicksOnLinksScript + '' + '';
+ return previewHtml;
+ };
+
+ const open = editor => {
+ const content = getPreviewHtml(editor);
+ const dataApi = editor.windowManager.open({
+ title: 'Preview',
+ size: 'large',
+ body: {
+ type: 'panel',
+ items: [{
+ name: 'preview',
+ type: 'iframe',
+ sandboxed: true,
+ transparent: false
+ }]
+ },
+ buttons: [{
+ type: 'cancel',
+ name: 'close',
+ text: 'Close',
+ primary: true
+ }],
+ initialData: { preview: content }
+ });
+ dataApi.focus('close');
+ };
+
+ const register$1 = editor => {
+ editor.addCommand('mcePreview', () => {
+ open(editor);
+ });
+ };
+
+ const register = editor => {
+ const onAction = () => editor.execCommand('mcePreview');
+ editor.ui.registry.addButton('preview', {
+ icon: 'preview',
+ tooltip: 'Preview',
+ onAction
+ });
+ editor.ui.registry.addMenuItem('preview', {
+ icon: 'preview',
+ text: 'Preview',
+ onAction
+ });
+ };
+
+ var Plugin = () => {
+ global$2.add('preview', editor => {
+ register$1(editor);
+ register(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/preview/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/preview/plugin.min.js
new file mode 100644
index 00000000000..30eca9ba1b8
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/preview/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{let n="";const a=e.dom.encode,l=i(e)??"";n+=' ';const d=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{n+=' "})),l&&(n+='");const m=r(e),y=c(e),p=' ';
+ const directionality = editor.getBody().dir;
+ const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
+ html = '' + '' + '' + ' ' + contentCssEntries + preventClicksOnLinksScript + '' + '' + html + '' + '';
+ }
+ return replaceTemplateValues(html, getPreviewReplaceValues(editor));
+ };
+ const open = (editor, templateList) => {
+ const createTemplates = () => {
+ if (!templateList || templateList.length === 0) {
+ const message = editor.translate('No templates defined.');
+ editor.notificationManager.open({
+ text: message,
+ type: 'info'
+ });
+ return Optional.none();
+ }
+ return Optional.from(global$1.map(templateList, (template, index) => {
+ const isUrlTemplate = t => t.url !== undefined;
+ return {
+ selected: index === 0,
+ text: template.title,
+ value: {
+ url: isUrlTemplate(template) ? Optional.from(template.url) : Optional.none(),
+ content: !isUrlTemplate(template) ? Optional.from(template.content) : Optional.none(),
+ description: template.description
+ }
+ };
+ }));
+ };
+ const createSelectBoxItems = templates => map(templates, t => ({
+ text: t.text,
+ value: t.text
+ }));
+ const findTemplate = (templates, templateTitle) => find(templates, t => t.text === templateTitle);
+ const loadFailedAlert = api => {
+ editor.windowManager.alert('Could not load the specified template.', () => api.focus('template'));
+ };
+ const getTemplateContent = t => t.value.url.fold(() => Promise.resolve(t.value.content.getOr('')), url => fetch(url).then(res => res.ok ? res.text() : Promise.reject()));
+ const onChange = (templates, updateDialog) => (api, change) => {
+ if (change.name === 'template') {
+ const newTemplateTitle = api.getData().template;
+ findTemplate(templates, newTemplateTitle).each(t => {
+ api.block('Loading...');
+ getTemplateContent(t).then(previewHtml => {
+ updateDialog(api, t, previewHtml);
+ }).catch(() => {
+ updateDialog(api, t, '');
+ api.setEnabled('save', false);
+ loadFailedAlert(api);
+ });
+ });
+ }
+ };
+ const onSubmit = templates => api => {
+ const data = api.getData();
+ findTemplate(templates, data.template).each(t => {
+ getTemplateContent(t).then(previewHtml => {
+ editor.execCommand('mceInsertTemplate', false, previewHtml);
+ api.close();
+ }).catch(() => {
+ api.setEnabled('save', false);
+ loadFailedAlert(api);
+ });
+ });
+ };
+ const openDialog = templates => {
+ const selectBoxItems = createSelectBoxItems(templates);
+ const buildDialogSpec = (bodyItems, initialData) => ({
+ title: 'Insert Template',
+ size: 'large',
+ body: {
+ type: 'panel',
+ items: bodyItems
+ },
+ initialData,
+ buttons: [
+ {
+ type: 'cancel',
+ name: 'cancel',
+ text: 'Cancel'
+ },
+ {
+ type: 'submit',
+ name: 'save',
+ text: 'Save',
+ primary: true
+ }
+ ],
+ onSubmit: onSubmit(templates),
+ onChange: onChange(templates, updateDialog)
+ });
+ const updateDialog = (dialogApi, template, previewHtml) => {
+ const content = getPreviewContent(editor, previewHtml);
+ const bodyItems = [
+ {
+ type: 'selectbox',
+ name: 'template',
+ label: 'Templates',
+ items: selectBoxItems
+ },
+ {
+ type: 'htmlpanel',
+ html: `${ htmlEscape(template.value.description) }
`
+ },
+ {
+ label: 'Preview',
+ type: 'iframe',
+ name: 'preview',
+ sandboxed: false,
+ transparent: false
+ }
+ ];
+ const initialData = {
+ template: template.text,
+ preview: content
+ };
+ dialogApi.unblock();
+ dialogApi.redial(buildDialogSpec(bodyItems, initialData));
+ dialogApi.focus('template');
+ };
+ const dialogApi = editor.windowManager.open(buildDialogSpec([], {
+ template: '',
+ preview: ''
+ }));
+ dialogApi.block('Loading...');
+ getTemplateContent(templates[0]).then(previewHtml => {
+ updateDialog(dialogApi, templates[0], previewHtml);
+ }).catch(() => {
+ updateDialog(dialogApi, templates[0], '');
+ dialogApi.setEnabled('save', false);
+ loadFailedAlert(dialogApi);
+ });
+ };
+ const optTemplates = createTemplates();
+ optTemplates.each(openDialog);
+ };
+
+ const showDialog = editor => templates => {
+ open(editor, templates);
+ };
+ const register$1 = editor => {
+ editor.addCommand('mceInsertTemplate', curry(insertTemplate, editor));
+ editor.addCommand('mceTemplate', createTemplateList(editor, showDialog(editor)));
+ };
+
+ const setup = editor => {
+ editor.on('PreProcess', o => {
+ const dom = editor.dom, dateFormat = getMdateFormat(editor);
+ global$1.each(dom.select('div', o.node), e => {
+ if (dom.hasClass(e, 'mceTmpl')) {
+ global$1.each(dom.select('*', e), e => {
+ if (hasAnyClasses(dom, e, getModificationDateClasses(editor))) {
+ e.innerHTML = getDateTime(editor, dateFormat);
+ }
+ });
+ replaceVals(editor, e);
+ }
+ });
+ });
+ };
+
+ const register = editor => {
+ const onAction = () => editor.execCommand('mceTemplate');
+ editor.ui.registry.addButton('template', {
+ icon: 'template',
+ tooltip: 'Insert template',
+ onAction
+ });
+ editor.ui.registry.addMenuItem('template', {
+ icon: 'template',
+ text: 'Insert template...',
+ onAction
+ });
+ };
+
+ var Plugin = () => {
+ global$2.add('template', editor => {
+ register$2(editor);
+ register(editor);
+ register$1(editor);
+ setup(editor);
+ });
+ };
+
+ Plugin();
+
+})();
diff --git a/lib/editor/tiny/js/tinymce/plugins/template/plugin.min.js b/lib/editor/tiny/js/tinymce/plugins/template/plugin.min.js
new file mode 100644
index 00000000000..99c2d2bc117
--- /dev/null
+++ b/lib/editor/tiny/js/tinymce/plugins/template/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.2.0 (2022-09-08)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(a=n=e,(r=String).prototype.isPrototypeOf(a)||n.constructor?.name===r.name)?"string":t;var a,n,r})(t)===e,a=t("string"),n=t("object"),r=t("array"),s=("function",e=>"function"==typeof e);const l=(!1,()=>false);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");const c=e=>t=>t.options.get(e),i=c("template_cdate_classes"),u=c("template_mdate_classes"),m=c("template_selected_content_classes"),p=c("template_preview_replace_values"),d=c("template_replace_values"),h=c("templates"),g=c("template_cdate_format"),f=c("template_mdate_format"),y=c("content_style"),v=c("content_css_cors"),_=c("body_class"),b=(e,t)=>{if((e=""+e).length{const n="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),r="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),s="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),l="January February March April May June July August September October November December".split(" ");return(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",b(a.getMonth()+1,2))).replace("%d",b(a.getDate(),2))).replace("%H",""+b(a.getHours(),2))).replace("%M",""+b(a.getMinutes(),2))).replace("%S",""+b(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(l[a.getMonth()]))).replace("%b",""+e.translate(s[a.getMonth()]))).replace("%A",""+e.translate(r[a.getDay()]))).replace("%a",""+e.translate(n[a.getDay()]))).replace("%%","%")};class T{constructor(e,t){this.tag=e,this.value=t}static some(e){return new T(!0,e)}static none(){return T.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?T.some(e(this.value)):T.none()}bind(e){return this.tag?e(this.value):T.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:T.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(e??"Called getOrDie on None")}static from(e){return null==e?T.none():T.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}T.singletonNone=new T(!1);const x=Object.hasOwnProperty,S={'"':""","<":"<",">":">","&":"&","'":"'"},w=e=>e.replace(/["'<>&]/g,(e=>{return(t=S,a=e,((e,t)=>x.call(e,t))(t,a)?T.from(t[a]):T.none()).getOr(e);var t,a})),C=(e,t,a)=>((a,n)=>{for(let n=0,s=a.length;n(o.each(t,((t,a)=>{s(t)&&(t=t(a)),e=e.replace(new RegExp("\\{\\$"+a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\}","g"),t)})),e),A=(e,t)=>{const a=e.dom,n=d(e);o.each(a.select("*",t),(e=>{o.each(n,((t,n)=>{a.hasClass(e,n)&&s(t)&&t(e)}))}))},D=(e,t,a)=>{const n=e.dom,r=e.selection.getContent();a=O(a,d(e));let s=n.create("div",{},a);const l=n.select(".mceTmpl",s);l&&l.length>0&&(s=n.create("div"),s.appendChild(l[0].cloneNode(!0))),o.each(n.select("*",s),(t=>{C(n,t,i(e))&&(t.innerHTML=M(e,g(e))),C(n,t,u(e))&&(t.innerHTML=M(e,f(e))),C(n,t,m(e))&&(t.innerHTML=r)})),A(e,s),e.execCommand("mceInsertContent",!1,s.innerHTML),e.addVisual()};var I=tinymce.util.Tools.resolve("tinymce.Env");const N=(e,t)=>{const a=(e,t)=>((e,t,a)=>{for(let n=0,r=e.length;ne.text===t),l),n=t=>{e.windowManager.alert("Could not load the specified template.",(()=>t.focus("template")))},r=e=>e.value.url.fold((()=>Promise.resolve(e.value.content.getOr(""))),(e=>fetch(e).then((e=>e.ok?e.text():Promise.reject())))),s=(e,t)=>(s,l)=>{if("template"===l.name){const l=s.getData().template;a(e,l).each((e=>{s.block("Loading..."),r(e).then((a=>{t(s,e,a)})).catch((()=>{t(s,e,""),s.setEnabled("save",!1),n(s)}))}))}},c=t=>s=>{const l=s.getData();a(t,l.template).each((t=>{r(t).then((t=>{e.execCommand("mceInsertTemplate",!1,t),s.close()})).catch((()=>{s.setEnabled("save",!1),n(s)}))}))};(()=>{if(!t||0===t.length){const t=e.translate("No templates defined.");return e.notificationManager.open({text:t,type:"info"}),T.none()}return T.from(o.map(t,((e,t)=>{const a=e=>void 0!==e.url;return{selected:0===t,text:e.title,value:{url:a(e)?T.from(e.url):T.none(),content:a(e)?T.none():T.from(e.content),description:e.description}}})))})().each((t=>{const a=(e=>((e,t)=>{const a=e.length,n=new Array(a);for(let t=0;t({title:"Insert Template",size:"large",body:{type:"panel",items:e},initialData:a,buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:c(t),onChange:s(t,i)}),i=(t,n,r)=>{const s=((e,t)=>{if(-1===t.indexOf("")){let a="";const n=y(e)??"",r=v(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{a+=' "})),n&&(a+='");const s=_(e),l=e.dom.encode,c='