diff --git a/.changes/unreleased/tinymce-TINY-10654-2024-02-23.yaml b/.changes/unreleased/tinymce-TINY-10654-2024-02-23.yaml
new file mode 100644
index 0000000000..2307ad017e
--- /dev/null
+++ b/.changes/unreleased/tinymce-TINY-10654-2024-02-23.yaml
@@ -0,0 +1,6 @@
+project: tinymce
+kind: Removed
+body: Removed deprecated `template` plugin.
+time: 2024-02-23T12:25:39.49598509+10:00
+custom:
+ Issue: TINY-10654
diff --git a/modules/bridge/src/demo/ts/Demo.ts b/modules/bridge/src/demo/ts/Demo.ts
index 6a41647d83..84f3c69a60 100644
--- a/modules/bridge/src/demo/ts/Demo.ts
+++ b/modules/bridge/src/demo/ts/Demo.ts
@@ -15,7 +15,6 @@ import { createPreviewDialog } from './dialogs/PreviewDialog';
import { createTableCellDialog } from './dialogs/TableCellDialog';
import { createTableDialog } from './dialogs/TableDialog';
import { createTableRowDialog } from './dialogs/TableRowDialog';
-import { createTemplateDialog } from './dialogs/TemplateDialog';
import { createWordcountDialog } from './dialogs/WordcountDialog';
import { registerDemoContextMenus } from './menus/ContextMenuDemo';
import { registerDemoMenuItems } from './menus/MenuItemDemo';
@@ -36,7 +35,6 @@ createPreviewDialog();
createTableCellDialog();
createTableDialog();
createTableRowDialog();
-createTemplateDialog();
registerDemoButtons();
registerDemoMenuItems();
registerDemoContextMenus();
diff --git a/modules/bridge/src/demo/ts/dialogs/TemplateDialog.ts b/modules/bridge/src/demo/ts/dialogs/TemplateDialog.ts
deleted file mode 100644
index cf7ad7454c..0000000000
--- a/modules/bridge/src/demo/ts/dialogs/TemplateDialog.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { openDemoDialog } from './DemoDialogHelpers';
-
-export const createTemplateDialog = (): void => {
- openDemoDialog(
- {
- title: 'Insert template',
- size: 'large',
- body: {
- type: 'panel',
- items: [
- {
- name: 'template',
- type: 'selectbox',
- label: 'Template',
- items: [
- {
- text: 'Some template 1',
- value: 'url1.html'
- },
- {
- text: 'Some template 2',
- value: 'url2.html'
- }
- ]
- },
- {
- name: 'preview',
- type: 'iframe',
- label: 'Preview of template',
- sandboxed: false
- }
- ]
- },
- buttons: [
- {
- type: 'submit',
- name: 'ok',
- text: 'Ok',
- primary: true
- },
- {
- type: 'cancel',
- name: 'cancel',
- text: 'Cancel'
- }
- ],
- initialData: {
- template: 'url2.html',
- preview: 'some html url'
- },
- onSubmit: (api) => {
- const data = api.getData();
-
- // eslint-disable-next-line no-console
- console.log({
- template: data.template
- });
-
- api.close();
- }
- }
- );
-};
diff --git a/modules/bridge/src/demo/ts/plugins/TemplateItems.ts b/modules/bridge/src/demo/ts/plugins/TemplateItems.ts
deleted file mode 100644
index 37f37113df..0000000000
--- a/modules/bridge/src/demo/ts/plugins/TemplateItems.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { getDemoRegistry } from '../buttons/DemoRegistry';
-
-export const registerTemplateItems = (): void => {
- getDemoRegistry().addButton('template', {
- type: 'button',
- enabled: true,
- onAction: (_buttonApi) => {
- // show dialog
- }
- });
-};
diff --git a/modules/tinymce/Gruntfile.js b/modules/tinymce/Gruntfile.js
index ac6aaaac0a..89669ed376 100644
--- a/modules/tinymce/Gruntfile.js
+++ b/modules/tinymce/Gruntfile.js
@@ -14,7 +14,7 @@ let plugins = [
'accordion', 'advlist', 'anchor', 'autolink', 'autoresize', 'autosave', 'charmap', 'code', 'codesample',
'directionality', 'emoticons', 'help', 'fullscreen', 'image', 'importcss', 'insertdatetime',
'link', 'lists', 'media', 'nonbreaking', 'pagebreak', 'preview', 'save', 'searchreplace',
- 'table', 'template', 'visualblocks', 'visualchars', 'wordcount', 'quickbars'
+ 'table', 'visualblocks', 'visualchars', 'wordcount', 'quickbars'
];
let themes = [
diff --git a/modules/tinymce/src/core/demo/ts/demo/CommandsDemo.ts b/modules/tinymce/src/core/demo/ts/demo/CommandsDemo.ts
index 95b8f9ff77..f99712aca0 100644
--- a/modules/tinymce/src/core/demo/ts/demo/CommandsDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/CommandsDemo.ts
@@ -66,7 +66,6 @@ export default (): void => {
cmd('mceSave'),
cmd('SearchReplace'),
cmd('mceSpellcheck'),
- cmd('mceInsertTemplate', '{$user}'),
cmd('mceVisualBlocks'),
cmd('mceVisualChars'),
cmd('mceMedia'),
@@ -107,7 +106,7 @@ export default (): void => {
plugins: [
'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'importcss', 'codesample'
+ 'save', 'table', 'directionality', 'emoticons', 'importcss', 'codesample'
],
toolbar1: 'bold italic',
menubar: false
diff --git a/modules/tinymce/src/core/demo/ts/demo/ContentSecurityPolicyDemo.ts b/modules/tinymce/src/core/demo/ts/demo/ContentSecurityPolicyDemo.ts
index a4c0783af7..80517f6fae 100644
--- a/modules/tinymce/src/core/demo/ts/demo/ContentSecurityPolicyDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/ContentSecurityPolicyDemo.ts
@@ -73,12 +73,6 @@ const settings: RawEditorOptions = {
callback('movie.mp4', { embed: '
test
' });
}
},
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'cdatemdateMy content2
' }
- ],
- template_cdate_format: '[CDATE: %m/%d/%Y : %H:%M:%S]',
- template_mdate_format: '[MDATE: %m/%d/%Y : %H:%M:%S]',
image_caption: true,
theme: 'silver',
setup: (ed) => {
@@ -87,7 +81,7 @@ const settings: RawEditorOptions = {
plugins: [
'autosave', 'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'importcss', 'codesample', 'help'
+ 'save', 'table', 'directionality', 'emoticons', 'importcss', 'codesample', 'help'
],
// rtl_ui: true,
add_unload_trigger: false,
diff --git a/modules/tinymce/src/core/demo/ts/demo/FixedToolbarContainerDemo.ts b/modules/tinymce/src/core/demo/ts/demo/FixedToolbarContainerDemo.ts
index d6aa41ae74..85361c5b27 100644
--- a/modules/tinymce/src/core/demo/ts/demo/FixedToolbarContainerDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/FixedToolbarContainerDemo.ts
@@ -7,6 +7,5 @@ export default (): void => {
selector: '#editor',
inline: true,
fixed_toolbar_container: '#toolbar',
- plugins: 'template' // lets you check notification positioning
});
};
diff --git a/modules/tinymce/src/core/demo/ts/demo/FullDemo.ts b/modules/tinymce/src/core/demo/ts/demo/FullDemo.ts
index 425a433c78..cfc1c44550 100644
--- a/modules/tinymce/src/core/demo/ts/demo/FullDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/FullDemo.ts
@@ -107,12 +107,6 @@ export default (): void => {
callback('movie.mp4', { embed: 'test
' });
}
},
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'cdatemdateMy content2
' }
- ],
- template_cdate_format: '[CDATE: %m/%d/%Y : %H:%M:%S]',
- template_mdate_format: '[MDATE: %m/%d/%Y : %H:%M:%S]',
image_caption: true,
theme: 'silver',
setup: (ed) => {
@@ -123,7 +117,7 @@ export default (): void => {
plugins: [
'autosave', 'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'importcss', 'codesample', 'help', 'accordion'
+ 'save', 'table', 'directionality', 'emoticons', 'importcss', 'codesample', 'help', 'accordion'
],
// rtl_ui: true,
add_unload_trigger: false,
diff --git a/modules/tinymce/src/core/demo/ts/demo/InlineDemo.ts b/modules/tinymce/src/core/demo/ts/demo/InlineDemo.ts
index e5abafa2b4..f156b2d0c1 100644
--- a/modules/tinymce/src/core/demo/ts/demo/InlineDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/InlineDemo.ts
@@ -21,14 +21,10 @@ export default (): void => {
{ title: 'None', value: '' },
{ title: 'Some class', value: 'class-name' }
],
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'cdatemdateMy content2
' }
- ],
plugins: [
'autosave', 'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'codesample', 'help'
+ 'save', 'table', 'directionality', 'emoticons', 'codesample', 'help'
]
};
diff --git a/modules/tinymce/src/core/demo/ts/demo/ResponsiveDemo.ts b/modules/tinymce/src/core/demo/ts/demo/ResponsiveDemo.ts
index e23af75fea..421877c83b 100644
--- a/modules/tinymce/src/core/demo/ts/demo/ResponsiveDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/ResponsiveDemo.ts
@@ -58,12 +58,6 @@ export default (): void => {
callback('movie.mp4', { source2: 'alt.ogg', poster: 'https://www.google.com/logos/google.jpg' });
}
},
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'cdatemdateMy content2
' }
- ],
- template_cdate_format: '[CDATE: %m/%d/%Y : %H:%M:%S]',
- template_mdate_format: '[MDATE: %m/%d/%Y : %H:%M:%S]',
image_caption: true,
theme: 'silver',
mobile: {
@@ -80,7 +74,7 @@ export default (): void => {
plugins: [
'fullscreen', 'help', 'autosave', 'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'importcss', 'codesample', 'help'
+ 'save', 'table', 'directionality', 'emoticons', 'importcss', 'codesample', 'help'
],
// rtl_ui: true,
add_unload_trigger: false,
diff --git a/modules/tinymce/src/core/demo/ts/demo/SourceDumpDemo.ts b/modules/tinymce/src/core/demo/ts/demo/SourceDumpDemo.ts
index 34f459f872..f07c3878e2 100644
--- a/modules/tinymce/src/core/demo/ts/demo/SourceDumpDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/SourceDumpDemo.ts
@@ -9,15 +9,11 @@ export default (): void => {
selector: 'textarea#editor',
skin_url: '../../../../js/tinymce/skins/ui/oxide',
content_css: '../../../../js/tinymce/skins/content/default/content.css',
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'cdatemdateMy content2
' }
- ],
image_caption: true,
plugins: [
'autosave', 'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'importcss', 'codesample', 'help'
+ 'save', 'table', 'directionality', 'emoticons', 'importcss', 'codesample', 'help'
],
add_unload_trigger: false,
autosave_ask_before_unload: false,
diff --git a/modules/tinymce/src/core/demo/ts/demo/StickyToolbarDemo.ts b/modules/tinymce/src/core/demo/ts/demo/StickyToolbarDemo.ts
index dc4891f29f..9b47460b3a 100644
--- a/modules/tinymce/src/core/demo/ts/demo/StickyToolbarDemo.ts
+++ b/modules/tinymce/src/core/demo/ts/demo/StickyToolbarDemo.ts
@@ -62,12 +62,6 @@ export default (): void => {
callback('movie.mp4', { source2: 'alt.ogg', poster: 'https://www.google.com/logos/google.jpg' });
}
},
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'cdatemdateMy content2
' }
- ],
- template_cdate_format: '[CDATE: %m/%d/%Y : %H:%M:%S]',
- template_mdate_format: '[MDATE: %m/%d/%Y : %H:%M:%S]',
image_caption: true,
theme: 'silver',
setup: (ed) => {
@@ -76,7 +70,7 @@ export default (): void => {
plugins: [
'autosave', 'advlist', 'autolink', 'link', 'image', 'lists', 'charmap', 'preview', 'anchor', 'pagebreak',
'searchreplace', 'wordcount', 'visualblocks', 'visualchars', 'code', 'fullscreen', 'insertdatetime', 'media', 'nonbreaking',
- 'save', 'table', 'directionality', 'emoticons', 'template', 'importcss', 'codesample', 'help'
+ 'save', 'table', 'directionality', 'emoticons', 'importcss', 'codesample', 'help'
],
// rtl_ui: true,
add_unload_trigger: false,
diff --git a/modules/tinymce/src/plugins/help/main/ts/data/PluginUrls.ts b/modules/tinymce/src/plugins/help/main/ts/data/PluginUrls.ts
index 1964efa580..cf04d91e17 100644
--- a/modules/tinymce/src/plugins/help/main/ts/data/PluginUrls.ts
+++ b/modules/tinymce/src/plugins/help/main/ts/data/PluginUrls.ts
@@ -46,7 +46,6 @@ const urls = Arr.map([
{ 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' },
diff --git a/modules/tinymce/src/plugins/template/demo/html/demo.html b/modules/tinymce/src/plugins/template/demo/html/demo.html
deleted file mode 100644
index b5d92bca22..0000000000
--- a/modules/tinymce/src/plugins/template/demo/html/demo.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- Plugin: template Demo Page
-
-
-
- Plugin: template Demo Page
-
-
-
-
-
-
-
diff --git a/modules/tinymce/src/plugins/template/demo/html/development.html b/modules/tinymce/src/plugins/template/demo/html/development.html
deleted file mode 100644
index 27acc23eee..0000000000
--- a/modules/tinymce/src/plugins/template/demo/html/development.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Header 1 |
- Header 2 |
-
-
- Cell 1 |
- Cell 2 |
-
-
-
diff --git a/modules/tinymce/src/plugins/template/demo/ts/demo/Demo.ts b/modules/tinymce/src/plugins/template/demo/ts/demo/Demo.ts
deleted file mode 100644
index c3649f1398..0000000000
--- a/modules/tinymce/src/plugins/template/demo/ts/demo/Demo.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { TinyMCE } from 'tinymce/core/api/PublicApi';
-
-declare let tinymce: TinyMCE;
-
-tinymce.init({
- selector: 'textarea.tinymce',
- plugins: 'template',
- toolbar: 'template',
- height: 600,
- template_preview_replace_values: {
- username: 'username here'
- },
- template_replace_values: {
- username: 'Jack',
- staffid: '991234'
- },
- templates: [
- { title: 'Some title 1', description: 'Some desc 1', content: 'My content {$username}' },
- { title: 'Some title 2', description: 'Some desc 2', content: 'My other content' },
- { title: 'Some remote file', description: 'Some desc 3', url: 'development.html' },
- { title: 'Nonexistent remote file', description: 'Some desc 4', url: 'invalid.html' }
- ]
-});
-
-export {};
diff --git a/modules/tinymce/src/plugins/template/main/ts/Main.ts b/modules/tinymce/src/plugins/template/main/ts/Main.ts
deleted file mode 100644
index 80d85c0581..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/Main.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import Plugin from './Plugin';
-
-Plugin();
-
-/** *****
- * DO NOT EXPORT ANYTHING
- *
- * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE
- *******/
diff --git a/modules/tinymce/src/plugins/template/main/ts/Plugin.ts b/modules/tinymce/src/plugins/template/main/ts/Plugin.ts
deleted file mode 100644
index 5d1d5357ee..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/Plugin.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import PluginManager from 'tinymce/core/api/PluginManager';
-
-import * as Commands from './api/Commands';
-import * as Options from './api/Options';
-import * as FilterContent from './core/FilterContent';
-import * as Buttons from './ui/Buttons';
-
-export default (): void => {
- PluginManager.add('template', (editor) => {
- Options.register(editor);
- Buttons.register(editor);
- Commands.register(editor);
- FilterContent.setup(editor);
- });
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/api/Commands.ts b/modules/tinymce/src/plugins/template/main/ts/api/Commands.ts
deleted file mode 100644
index 3a7591c614..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/api/Commands.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Fun } from '@ephox/katamari';
-
-import Editor from 'tinymce/core/api/Editor';
-
-import * as Templates from '../core/Templates';
-import { ExternalTemplate } from '../core/Types';
-import * as Dialog from '../ui/Dialog';
-
-const showDialog = (editor: Editor) => (templates: ExternalTemplate[]): void => {
- Dialog.open(editor, templates);
-};
-
-const register = (editor: Editor): void => {
- editor.addCommand('mceInsertTemplate', Fun.curry(Templates.insertTemplate, editor));
- editor.addCommand('mceTemplate', Templates.createTemplateList(editor, showDialog(editor)));
-};
-
-export {
- register
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/api/Options.ts b/modules/tinymce/src/plugins/template/main/ts/api/Options.ts
deleted file mode 100644
index 0e1af04583..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/api/Options.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { Type } from '@ephox/katamari';
-
-import Editor from 'tinymce/core/api/Editor';
-import { EditorOptions } from 'tinymce/core/api/OptionTypes';
-
-import { ExternalTemplate, TemplateValues } from '../core/Types';
-
-type TemplateCallback = (callback: (templates: ExternalTemplate[]) => void) => void;
-
-const option: {
- (name: K): (editor: Editor) => EditorOptions[K];
- (name: string): (editor: Editor) => T;
-} = (name: string) => (editor: Editor) =>
- editor.options.get(name);
-
-const register = (editor: Editor): void => {
- const registerOption = editor.options.register;
-
- registerOption('template_cdate_classes', {
- processor: 'string',
- default: 'cdate'
- });
-
- registerOption('template_mdate_classes', {
- processor: 'string',
- default: 'mdate'
- });
-
- registerOption('template_selected_content_classes', {
- processor: 'string',
- default: 'selcontent'
- });
-
- registerOption('template_preview_replace_values', {
- processor: 'object'
- });
-
- registerOption('template_replace_values', {
- processor: 'object'
- });
-
- registerOption('templates', {
- processor: (value) => Type.isString(value) || Type.isArrayOf(value, Type.isObject) || Type.isFunction(value),
- default: []
- });
-
- registerOption('template_cdate_format', {
- processor: 'string',
- default: editor.translate('%Y-%m-%d')
- });
-
- registerOption('template_mdate_format', {
- processor: 'string',
- default: editor.translate('%Y-%m-%d')
- });
-};
-
-const getCreationDateClasses = option('template_cdate_classes');
-const getModificationDateClasses = option('template_mdate_classes');
-const getSelectedContentClasses = option('template_selected_content_classes');
-const getPreviewReplaceValues = option('template_preview_replace_values');
-const getTemplateReplaceValues = option('template_replace_values');
-const getTemplates = option('templates');
-const getCdateFormat = option('template_cdate_format');
-const getMdateFormat = option('template_mdate_format');
-const getContentStyle = option('content_style');
-const shouldUseContentCssCors = option('content_css_cors');
-const getBodyClass = option('body_class');
-
-export {
- register,
- getCreationDateClasses,
- getModificationDateClasses,
- getSelectedContentClasses,
- getPreviewReplaceValues,
- getTemplateReplaceValues,
- getTemplates,
- getCdateFormat,
- getMdateFormat,
- getBodyClass,
- getContentStyle,
- shouldUseContentCssCors
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/core/DateTimeHelper.ts b/modules/tinymce/src/plugins/template/main/ts/core/DateTimeHelper.ts
deleted file mode 100644
index fae326ed6c..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/core/DateTimeHelper.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import Editor from 'tinymce/core/api/Editor';
-
-const addZeros = (value: string | number, len: number): string => {
- value = '' + value;
-
- if (value.length < len) {
- for (let i = 0; i < (len - value.length); i++) {
- value = '0' + value;
- }
- }
-
- return value;
-};
-
-const getDateTime = (editor: Editor, fmt: string, date: Date = new Date()): string => {
- 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(' ');
-
- 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 as any).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;
-};
-
-export {
- getDateTime
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/core/FilterContent.ts b/modules/tinymce/src/plugins/template/main/ts/core/FilterContent.ts
deleted file mode 100644
index 2b0bb75991..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/core/FilterContent.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import Editor from 'tinymce/core/api/Editor';
-import Tools from 'tinymce/core/api/util/Tools';
-
-import * as Options from '../api/Options';
-import * as DateTimeHelper from './DateTimeHelper';
-import * as Templates from './Templates';
-import { hasAnyClasses } from './Utils';
-
-const setup = (editor: Editor): void => {
- editor.on('PreProcess', (o) => {
- const dom = editor.dom, dateFormat = Options.getMdateFormat(editor);
-
- Tools.each(dom.select('div', o.node), (e) => {
- if (dom.hasClass(e, 'mceTmpl')) {
- Tools.each(dom.select('*', e), (e) => {
- if (hasAnyClasses(dom, e, Options.getModificationDateClasses(editor))) {
- e.innerHTML = DateTimeHelper.getDateTime(editor, dateFormat);
- }
- });
-
- Templates.replaceVals(editor, e);
- }
- });
- });
-};
-
-export {
- setup
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/core/Templates.ts b/modules/tinymce/src/plugins/template/main/ts/core/Templates.ts
deleted file mode 100644
index 029b4d30e7..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/core/Templates.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { Regex, Type } from '@ephox/katamari';
-
-import Editor from 'tinymce/core/api/Editor';
-import Tools from 'tinymce/core/api/util/Tools';
-
-import * as Options from '../api/Options';
-import * as DateTimeHelper from './DateTimeHelper';
-import { ExternalTemplate, TemplateValues } from './Types';
-import { hasAnyClasses, parseAndSerialize } from './Utils';
-
-const createTemplateList = (editor: Editor, callback: (templates: ExternalTemplate[]) => void) => {
- return (): void => {
- const templateList = Options.getTemplates(editor);
-
- if (Type.isFunction(templateList)) {
- templateList(callback);
- } else if (Type.isString(templateList)) {
- fetch(templateList)
- .then((res) => {
- if (res.ok) {
- res.json().then(callback);
- }
- });
- } else {
- callback(templateList);
- }
- };
-};
-
-const replaceTemplateValues = (html: string, templateValues: TemplateValues | undefined): string => {
- Tools.each(templateValues, (v, k) => {
- if (Type.isFunction(v)) {
- v = v(k);
- }
-
- html = html.replace(new RegExp('\\{\\$' + Regex.escape(k) + '\\}', 'g'), v);
- });
-
- return html;
-};
-
-const replaceVals = (editor: Editor, scope: HTMLElement): void => {
- const dom = editor.dom, vl = Options.getTemplateReplaceValues(editor);
-
- Tools.each(dom.select('*', scope), (e) => {
- Tools.each(vl, (v, k) => {
- if (dom.hasClass(e, k)) {
- if (Type.isFunction(v)) {
- // TODO: TINY-7792: Investigate as this appears to be a bug as "replaceTemplateValues" above uses
- // the same values here and it expects a string and return value so this is not compatible.
- v(e as any);
- }
- }
- });
- });
-};
-
-const insertTemplate = (editor: Editor, _ui: boolean, html: string): void => {
- // Note: ui is unused here but is required since this can be called by execCommand
- const dom = editor.dom;
- const sel = editor.selection.getContent();
-
- html = replaceTemplateValues(html, Options.getTemplateReplaceValues(editor));
- let el = dom.create('div', {}, parseAndSerialize(editor, html));
-
- // Find template element within div
- const n = dom.select('.mceTmpl', el);
- if (n && n.length > 0) {
- el = dom.create('div');
- el.appendChild(n[0].cloneNode(true));
- }
-
- Tools.each(dom.select('*', el), (n) => {
- // Replace cdate
- if (hasAnyClasses(dom, n, Options.getCreationDateClasses(editor))) {
- n.innerHTML = DateTimeHelper.getDateTime(editor, Options.getCdateFormat(editor));
- }
-
- // Replace mdate
- if (hasAnyClasses(dom, n, Options.getModificationDateClasses(editor))) {
- n.innerHTML = DateTimeHelper.getDateTime(editor, Options.getMdateFormat(editor));
- }
-
- // Replace selection
- if (hasAnyClasses(dom, n, Options.getSelectedContentClasses(editor))) {
- n.innerHTML = sel;
- }
- });
-
- replaceVals(editor, el);
-
- editor.execCommand('mceInsertContent', false, el.innerHTML);
- editor.addVisual();
-};
-
-export {
- createTemplateList,
- replaceTemplateValues,
- replaceVals,
- insertTemplate
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/core/Types.ts b/modules/tinymce/src/plugins/template/main/ts/core/Types.ts
deleted file mode 100644
index 8e6e3c8b53..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/core/Types.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Optional } from '@ephox/katamari';
-
-export interface UrlTemplate {
- readonly title: string;
- readonly description: string;
- readonly url: string;
-}
-
-export interface ContentTemplate {
- readonly title: string;
- readonly description: string;
- readonly content: string;
-}
-
-export type ExternalTemplate = UrlTemplate | ContentTemplate;
-
-export interface InternalTemplate {
- readonly selected: boolean;
- readonly text: string;
- readonly value: {
- readonly url: Optional;
- readonly content: Optional;
- readonly description: string;
- };
-}
-
-export interface DialogData {
- readonly template: string;
- readonly preview: string;
-}
-
-export type TemplateValues = Record string)>;
diff --git a/modules/tinymce/src/plugins/template/main/ts/core/Utils.ts b/modules/tinymce/src/plugins/template/main/ts/core/Utils.ts
deleted file mode 100644
index 67654f5403..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/core/Utils.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Arr, Obj } from '@ephox/katamari';
-
-import DOMUtils from 'tinymce/core/api/dom/DOMUtils';
-import Editor from 'tinymce/core/api/Editor';
-import HtmlSerializer from 'tinymce/core/api/html/Serializer';
-
-const entitiesAttr: Record = {
- '"': '"',
- '<': '<',
- '>': '>',
- '&': '&',
- '\'': '''
-};
-
-const htmlEscape = (html: string): string =>
- html.replace(/["'<>&]/g, (match) => Obj.get(entitiesAttr, match).getOr(match));
-
-const hasAnyClasses = (dom: DOMUtils, n: Element, classes: string): boolean =>
- Arr.exists(classes.split(/\s+/), (c) => dom.hasClass(n, c));
-
-const parseAndSerialize = (editor: Editor, html: string): string =>
- HtmlSerializer({ validate: true }, editor.schema).serialize(
- editor.parser.parse(html, { insert: true })
- );
-
-export {
- hasAnyClasses,
- htmlEscape,
- parseAndSerialize
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/ui/Buttons.ts b/modules/tinymce/src/plugins/template/main/ts/ui/Buttons.ts
deleted file mode 100644
index 4b575ab8cf..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/ui/Buttons.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import Editor from 'tinymce/core/api/Editor';
-import { Menu, Toolbar } from 'tinymce/core/api/ui/Ui';
-
-const onSetupEditable = (editor: Editor) => (api: Toolbar.ToolbarButtonInstanceApi | Menu.MenuItemInstanceApi): VoidFunction => {
- const nodeChanged = () => {
- api.setEnabled(editor.selection.isEditable());
- };
-
- editor.on('NodeChange', nodeChanged);
- nodeChanged();
-
- return () => {
- editor.off('NodeChange', nodeChanged);
- };
-};
-
-const register = (editor: Editor): void => {
- const onAction = () => editor.execCommand('mceTemplate');
-
- editor.ui.registry.addButton('template', {
- icon: 'template',
- tooltip: 'Insert template',
- onSetup: onSetupEditable(editor),
- onAction
- });
-
- editor.ui.registry.addMenuItem('template', {
- icon: 'template',
- text: 'Insert template...',
- onSetup: onSetupEditable(editor),
- onAction
- });
-};
-
-export {
- register
-};
diff --git a/modules/tinymce/src/plugins/template/main/ts/ui/Dialog.ts b/modules/tinymce/src/plugins/template/main/ts/ui/Dialog.ts
deleted file mode 100644
index 0fc9a5286c..0000000000
--- a/modules/tinymce/src/plugins/template/main/ts/ui/Dialog.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-import { Arr, Optional } from '@ephox/katamari';
-
-import Editor from 'tinymce/core/api/Editor';
-import Env from 'tinymce/core/api/Env';
-import { Dialog } from 'tinymce/core/api/ui/Ui';
-import Tools from 'tinymce/core/api/util/Tools';
-
-import * as Options from '../api/Options';
-import * as Templates from '../core/Templates';
-import { DialogData, ExternalTemplate, InternalTemplate, UrlTemplate } from '../core/Types';
-import * as Utils from '../core/Utils';
-
-type UpdateDialogCallback = (dialogApi: Dialog.DialogInstanceApi, template: InternalTemplate, previewHtml: string) => void;
-
-const getPreviewContent = (editor: Editor, html: string): string => {
- let previewHtml = Utils.parseAndSerialize(editor, html);
- if (html.indexOf('') === -1) {
- let contentCssEntries = '';
- const contentStyle = Options.getContentStyle(editor) ?? '';
-
- const cors = Options.shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : '';
-
- Tools.each(editor.contentCSS, (url) => {
- contentCssEntries += '';
- });
-
- if (contentStyle) {
- contentCssEntries += '';
- }
-
- const bodyClass = Options.getBodyClass(editor);
-
- const encode = editor.dom.encode;
-
- const isMetaKeyPressed = Env.os.isMacOS() || Env.os.isiOS() ? 'e.metaKey' : 'e.ctrlKey && !e.altKey';
-
- const preventClicksOnLinksScript = (
- ' '
- );
-
- const directionality = editor.getBody().dir;
- const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
-
- previewHtml = (
- '' +
- '' +
- '' +
- '' +
- contentCssEntries +
- preventClicksOnLinksScript +
- '' +
- '' +
- previewHtml +
- '' +
- ''
- );
- }
-
- return Templates.replaceTemplateValues(previewHtml, Options.getPreviewReplaceValues(editor));
-};
-
-const open = (editor: Editor, templateList: ExternalTemplate[]): void => {
- const createTemplates = (): Optional> => {
- 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(Tools.map(templateList, (template: ExternalTemplate, index) => {
- const isUrlTemplate = (t: ExternalTemplate): t is UrlTemplate => (t as UrlTemplate).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: InternalTemplate[]) => Arr.map(templates, (t) => ({
- text: t.text,
- value: t.text
- }));
-
- const findTemplate = (templates: InternalTemplate[], templateTitle: string) => Arr.find(templates, (t) => t.text === templateTitle);
-
- const loadFailedAlert = (api: Dialog.DialogInstanceApi) => {
- editor.windowManager.alert('Could not load the specified template.', () => api.focus('template'));
- };
-
- const getTemplateContent = (t: InternalTemplate): Promise =>
- t.value.url.fold(
- () => Promise.resolve(t.value.content.getOr('')),
- (url) => fetch(url).then((res) => res.ok ? res.text() : Promise.reject())
- );
-
- const onChange = (templates: InternalTemplate[], updateDialog: UpdateDialogCallback) =>
- (api: Dialog.DialogInstanceApi, change: { name: string }) => {
- 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: InternalTemplate[]) => (api: Dialog.DialogInstanceApi) => {
- 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: InternalTemplate[]) => {
- const selectBoxItems = createSelectBoxItems(templates);
-
- const buildDialogSpec = (bodyItems: Dialog.BodyComponentSpec[], initialData: DialogData): Dialog.DialogSpec => ({
- 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: Dialog.DialogInstanceApi, template: InternalTemplate, previewHtml: string) => {
- const content = getPreviewContent(editor, previewHtml);
- const bodyItems: Dialog.BodyComponentSpec[] = [
- {
- type: 'listbox',
- name: 'template',
- label: 'Templates',
- items: selectBoxItems
- },
- {
- type: 'htmlpanel',
- html: `${Utils.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: Optional = createTemplates();
- optTemplates.each(openDialog);
-};
-
-export {
- open,
- getPreviewContent
-};
diff --git a/modules/tinymce/src/plugins/template/test/html/test_template.html b/modules/tinymce/src/plugins/template/test/html/test_template.html
deleted file mode 100644
index 3112d8ec02..0000000000
--- a/modules/tinymce/src/plugins/template/test/html/test_template.html
+++ /dev/null
@@ -1 +0,0 @@
-this is external
\ No newline at end of file
diff --git a/modules/tinymce/src/plugins/template/test/ts/browser/DatesTest.ts b/modules/tinymce/src/plugins/template/test/ts/browser/DatesTest.ts
deleted file mode 100644
index ee53f5b226..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/browser/DatesTest.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-import { afterEach, describe, it } from '@ephox/bedrock-client';
-import { TinyAssertions, TinyHooks, TinySelections } from '@ephox/wrap-mcagar';
-
-import Editor from 'tinymce/core/api/Editor';
-import Plugin from 'tinymce/plugins/template/Plugin';
-
-import { pInsertTemplate } from '../module/InsertTemplate';
-import { Settings } from '../module/Settings';
-
-describe('browser.tinymce.plugins.template.DatesTest', () => {
- const hook = TinyHooks.bddSetupLight({
- plugins: 'template',
- toolbar: 'template',
- base_url: '/project/tinymce/js/tinymce'
- }, [ Plugin ]);
-
- const { addSettings, cleanupSettings } = Settings(hook);
-
- afterEach(() => {
- const editor = hook.editor();
- cleanupSettings();
- editor.setContent('');
- });
-
- it('TBA: Test cdate in snippet with default class', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', content: 'x
' }],
- template_cdate_format: 'fake date',
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, 'fake date
');
- });
-
- it('TBA: Test cdate in snippet with custom class', async () => {
- const editor = hook.editor();
- addSettings({
- template_cdate_classes: 'customCdateClass',
- templates: [{ title: 'a', description: 'b', content: 'x
' }],
- template_cdate_format: 'fake date'
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor,
- 'fake date
'
- );
- });
-
- it('TBA: Test mdate updates with each serialization', async () => {
- const editor = hook.editor();
- addSettings({
- template_mdate_format: 'fake modified date',
- template_cdate_format: 'fake created date',
- templates: [{ title: 'a', description: 'b', content: '' }]
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, [
- '',
- '
fake modified date
',
- '
fake created date
',
- '
'
- ].join('\n'));
- addSettings({ template_mdate_format: 'changed modified date' });
- TinyAssertions.assertContent(editor, [
- '',
- '
changed modified date
',
- '
fake created date
',
- '
'
- ].join('\n'));
- });
-
- it('TBA: Test mdate updates with each serialization with custom class', async () => {
- const editor = hook.editor();
- addSettings({
- template_mdate_classes: 'modified',
- template_mdate_format: 'fake modified date',
- template_cdate_format: 'fake created date',
- templates: [{ title: 'a', description: 'b', content: '' }]
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, [
- '',
- '
fake modified date
',
- '
fake created date
',
- '
'
- ].join('\n'));
- addSettings({ template_mdate_format: 'changed modified date' });
- TinyAssertions.assertContent(editor, [
- '',
- '
changed modified date
',
- '
fake created date
',
- '
'
- ].join('\n'));
- });
-
- it('TBA: Multiple replacement classes provided via options', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', content: '' }],
- template_cdate_classes: 'cdate1 cdate2',
- template_cdate_format: 'fake created date',
- template_mdate_classes: 'mdate1 mdate2',
- template_mdate_format: 'fake modified date',
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, [
- '',
- '
fake created date
',
- '
fake modified date
',
- '
'
- ].join('\n'));
- TinySelections.setCursor(editor, [ 0, 1, 0 ], 'fake modified date'.length);
- editor.insertContent('inserted modified date
');
- addSettings({ template_mdate_format: 'changed modified date' });
- TinyAssertions.assertContent(editor, [
- '',
- '
fake created date
',
- '
changed modified date
',
- '
changed modified date
',
- '
'
- ].join('\n'));
- });
-
- it('TINY-7433: replacement classes with regex like names', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', content: '' }],
- template_cdate_classes: 'custom+cdate',
- template_cdate_format: 'fake created date',
- template_mdate_classes: 'custom+mdate',
- template_mdate_format: 'fake modified date',
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, [
- '',
- '
fake created date
',
- '
fake modified date
',
- '
'
- ].join('\n'));
- });
-});
diff --git a/modules/tinymce/src/plugins/template/test/ts/browser/DialogGetPreviewContentTest.ts b/modules/tinymce/src/plugins/template/test/ts/browser/DialogGetPreviewContentTest.ts
deleted file mode 100644
index 32044da46d..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/browser/DialogGetPreviewContentTest.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { afterEach, describe, it } from '@ephox/bedrock-client';
-import { TinyHooks } from '@ephox/wrap-mcagar';
-import { assert } from 'chai';
-
-import Editor from 'tinymce/core/api/Editor';
-import Env from 'tinymce/core/api/Env';
-import Plugin from 'tinymce/plugins/template/Plugin';
-import { getPreviewContent } from 'tinymce/plugins/template/ui/Dialog';
-
-import { Settings } from '../module/Settings';
-
-const metaKey = Env.os.isMacOS() || Env.os.isiOS() ? 'e.metaKey' : 'e.ctrlKey && !e.altKey';
-const host = document.location.host;
-
-const noCorsNoStyle = '' +
- `` +
- `` +
- `` +
- ' ' +
- '';
-
-const corsNoStyle = '' +
- `` +
- `` +
- `` +
- ' ';
-
-const noCorsStyle = '' +
- `` +
- `` +
- `` +
- '' +
- ' ' +
- '';
-
-const corsStyle = '' +
- `` +
- `` +
- `` +
- '' +
- ' ' +
- '';
-
-const corsStyleAndContent = '' +
- `` +
- `` +
- `` +
- '' +
- ' ' +
- '' +
- 'Custom content which was provided
';
-
-// TODO TINY-10480: Investigate flaky tests
-describe.skip('browser.tinymce.plugins.template.Dialog.getPreviewContent', () => {
- const hook = TinyHooks.bddSetupLight({
- plugins: 'template',
- base_url: '/project/tinymce/js/tinymce'
- }, [ Plugin ]);
-
- const checkPreview = (expected: string, html: string = '') => {
- const editor = hook.editor();
- assert.equal(getPreviewContent(editor, html), expected);
- };
-
- const { addSettings, cleanupSettings } = Settings(hook);
-
- afterEach(() => {
- cleanupSettings();
- });
-
- it('TINY-6115: Dialog.getPreviewContent: No CORS or content style, no previous HTML', () => {
- checkPreview(noCorsNoStyle);
- });
-
- it('TINY-6115: Dialog.getPreviewContent: CORS but no content style, no previous HTML', () => {
- addSettings({ content_css_cors: true });
- checkPreview(corsNoStyle);
- });
-
- it('TINY-6115: Dialog.getPreviewcontent: No CORS but content style, no previous HTML', () => {
- addSettings({ content_style: 'This is the style inserted into the document' });
- checkPreview(noCorsStyle);
- });
-
- it('TINY-6115: Dialog.getPreviewContent: No CORS but content style, no previous HTML', () => {
- addSettings({
- content_css_cors: true,
- content_style: 'This is the style inserted into the document'
- });
- checkPreview(corsStyle);
- });
-
- it('TINY-6115: Dialog.getPreviewContent: with provided content', () => {
- addSettings({
- content_css_cors: true,
- content_style: 'This is the style inserted into the document'
- });
- checkPreview(corsStyleAndContent, 'Custom content which was provided');
- });
-
- it('TINY-6115: Dialog.getPreviewContent: with provided html', () => {
- addSettings({
- content_css_cors: true,
- content_style: 'This is the style inserted into the document'
- });
- // TINY-9867: Preview content is parsed to minimise visual discrepancy with inserted content
- checkPreview('Custom content here
', 'Custom content here');
- });
-});
diff --git a/modules/tinymce/src/plugins/template/test/ts/browser/InvalidUrlTest.ts b/modules/tinymce/src/plugins/template/test/ts/browser/InvalidUrlTest.ts
deleted file mode 100644
index 87bfd3eab2..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/browser/InvalidUrlTest.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { UiFinder, Waiter } from '@ephox/agar';
-import { describe, it } from '@ephox/bedrock-client';
-import { SugarBody } from '@ephox/sugar';
-import { TinyAssertions, TinyHooks, TinyUiActions } from '@ephox/wrap-mcagar';
-
-import Editor from 'tinymce/core/api/Editor';
-import Plugin from 'tinymce/plugins/template/Plugin';
-
-const dialogSelector = 'div.tox-dialog';
-const alertDialogSelector = 'div.tox-dialog.tox-alert-dialog';
-const toolbarButtonSelector = '[role="toolbar"] button[aria-label="Insert template"]';
-
-describe('browser.tinymce.plugins.template.InvalidUrlTest', () => {
- const hook = TinyHooks.bddSetupLight({
- plugins: 'template',
- toolbar: 'template',
- base_url: '/project/tinymce/js/tinymce'
- }, [ Plugin ]);
-
- it('TBA: Test loading in snippet from file that does not exist', async () => {
- const editor = hook.editor();
- editor.setContent('');
- editor.options.set('templates', [{ title: 'invalid', description: 'b', url: '/custom/404' }, { title: 'a', description: 'a', content: 'c' }]);
- TinyUiActions.clickOnToolbar(editor, toolbarButtonSelector);
- await TinyUiActions.pWaitForDialog(editor);
- await TinyUiActions.pWaitForPopup(editor, alertDialogSelector);
- // Click on Save button (should be disabled)
- TinyUiActions.clickOnUi(editor, 'button.tox-button:contains(OK)');
- await Waiter.pTryUntil('Alert dialog should close', () => UiFinder.notExists(SugarBody.body(), alertDialogSelector));
- TinyUiActions.submitDialog(editor);
- await Waiter.pTryUntil('Dialog should not close', () => UiFinder.exists(SugarBody.body(), dialogSelector));
- TinyUiActions.cancelDialog(editor);
- await Waiter.pTryUntil('Dialog should close', () => UiFinder.notExists(SugarBody.body(), dialogSelector));
- TinyAssertions.assertContent(editor, '');
- });
-});
diff --git a/modules/tinymce/src/plugins/template/test/ts/browser/NoneditableRootTest.ts b/modules/tinymce/src/plugins/template/test/ts/browser/NoneditableRootTest.ts
deleted file mode 100644
index ef32ab7e3d..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/browser/NoneditableRootTest.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Keys, UiFinder } from '@ephox/agar';
-import { describe, it } from '@ephox/bedrock-client';
-import { SugarBody } from '@ephox/sugar';
-import { TinyHooks, TinySelections, TinyState, TinyUiActions } from '@ephox/wrap-mcagar';
-
-import Editor from 'tinymce/core/api/Editor';
-import Plugin from 'tinymce/plugins/template/Plugin';
-
-describe('browser.tinymce.plugins.template.NoneditableRootTest', () => {
- const hook = TinyHooks.bddSetup({
- plugins: 'template',
- toolbar: 'template',
- base_url: '/project/tinymce/js/tinymce'
- }, [ Plugin ], true);
-
- it('TINY-9669: Disable template button on noneditable content', () => {
- TinyState.withNoneditableRootEditor(hook.editor(), (editor) => {
- editor.setContent('Noneditable content
Editable content
');
- TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 2);
- UiFinder.exists(SugarBody.body(), '[aria-label="Insert template"][aria-disabled="true"]');
- TinySelections.setSelection(editor, [ 1, 0 ], 0, [ 1, 0 ], 2);
- UiFinder.exists(SugarBody.body(), '[aria-label="Insert template"][aria-disabled="false"]');
- });
- });
-
- it('TINY-9669: Disable template menuitem on noneditable content', async () => {
- await TinyState.withNoneditableRootEditorAsync(hook.editor(), async (editor) => {
- editor.setContent('Noneditable content
Editable content
');
- TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 2);
- TinyUiActions.clickOnMenu(editor, 'button:contains("Insert")');
- await TinyUiActions.pWaitForUi(editor, '[role="menuitem"][aria-label="Insert template..."][aria-disabled="true"]');
- TinyUiActions.keystroke(editor, Keys.escape());
- TinySelections.setSelection(editor, [ 1, 0 ], 0, [ 1, 0 ], 2);
- TinyUiActions.clickOnMenu(editor, 'button:contains("Insert")');
- await TinyUiActions.pWaitForUi(editor, '[role="menuitem"][aria-label="Insert template..."][aria-disabled="false"]');
- TinyUiActions.keystroke(editor, Keys.escape());
- });
- });
-});
-
diff --git a/modules/tinymce/src/plugins/template/test/ts/browser/SelectedContentTest.ts b/modules/tinymce/src/plugins/template/test/ts/browser/SelectedContentTest.ts
deleted file mode 100644
index af1cec696c..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/browser/SelectedContentTest.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { afterEach, describe, it } from '@ephox/bedrock-client';
-import { TinyAssertions, TinyHooks, TinySelections } from '@ephox/wrap-mcagar';
-
-import Editor from 'tinymce/core/api/Editor';
-import Plugin from 'tinymce/plugins/template/Plugin';
-
-import { pInsertTemplate } from '../module/InsertTemplate';
-import { Settings } from '../module/Settings';
-
-describe('browser.tinymce.plugins.template.SelectedContentTest', () => {
- const hook = TinyHooks.bddSetupLight({
- plugins: 'template',
- toolbar: 'template',
- base_url: '/project/tinymce/js/tinymce'
- }, [ Plugin ]);
-
- const { addSettings, cleanupSettings } = Settings(hook);
-
- afterEach(() => {
- const editor = hook.editor();
- cleanupSettings();
- editor.setContent('');
- });
-
- it('TBA: Test selected content replacement with default class', async () => {
- const editor = hook.editor();
- editor.setContent('Text');
- TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 4);
- addSettings({
- templates: [{ title: 'a', description: 'b', content: 'This will be replaced
' }],
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, 'Text
');
- });
-
- it('TBA: Test selected content replacement with custom class', async () => {
- const editor = hook.editor();
- editor.setContent('Text');
- TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 4);
- addSettings({
- template_selected_content_classes: 'customSelected',
- templates: [{ title: 'a', description: 'b', content: 'This will be replaced/h1>' }],
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, 'Text
'
- );
- });
-});
diff --git a/modules/tinymce/src/plugins/template/test/ts/browser/TemplateSanityTest.ts b/modules/tinymce/src/plugins/template/test/ts/browser/TemplateSanityTest.ts
deleted file mode 100644
index b840723b94..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/browser/TemplateSanityTest.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import { UiFinder, Waiter } from '@ephox/agar';
-import { afterEach, beforeEach, context, describe, it } from '@ephox/bedrock-client';
-import { Cell } from '@ephox/katamari';
-import { SugarElement } from '@ephox/sugar';
-import { TinyAssertions, TinyHooks } from '@ephox/wrap-mcagar';
-import { assert } from 'chai';
-
-import Editor from 'tinymce/core/api/Editor';
-import Plugin from 'tinymce/plugins/template/Plugin';
-
-import { pInsertTemplate, pPreviewTemplate } from '../module/InsertTemplate';
-import { Settings } from '../module/Settings';
-
-describe('browser.tinymce.plugins.template.TemplateSanityTest', () => {
- const hook = TinyHooks.bddSetupLight({
- plugins: 'template',
- toolbar: 'template',
- base_url: '/project/tinymce/js/tinymce'
- }, [ Plugin ]);
-
- const { addSettings, cleanupSettings } = Settings(hook);
-
- beforeEach(() => {
- const editor = hook.editor();
- editor.setContent('');
- });
-
- afterEach(() => {
- cleanupSettings();
- });
-
- it('TBA: Test basic template insertion', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', content: 'c' }],
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, 'c
');
- });
-
- it('TBA: Test basic content replacement', async () => {
- const editor = hook.editor();
- addSettings({
- template_replace_values: { name: 'Tester', email: 'test@test.com' },
- templates: [{ title: 'a', description: 'b', content: '{$name} {$email}
' }]
- });
- await pInsertTemplate(editor);
- TinyAssertions.assertContent(editor, 'Tester test@test.com
');
- });
-
- it('TBA: Test loading in snippet from other file', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', url: '/project/tinymce/src/plugins/template/test/html/test_template.html' }]
- });
- await pInsertTemplate(editor, (dialogEl) => {
- UiFinder.exists(dialogEl, 'p:contains("b")');
- });
- TinyAssertions.assertContent(editor, 'this is external
');
- });
-
- it('TBA: Test command', () => {
- const editor = hook.editor();
- addSettings({
- template_replace_values: { name: 'Tester', email: 'test@test.com' },
- });
- editor.execCommand('mceInsertTemplate', false, '{$name}
');
- TinyAssertions.assertContent(editor, 'Tester
');
- });
-
- it('TINY-7433: Replace template values with regex like keys', () => {
- const editor = hook.editor();
- addSettings({
- template_replace_values: { 'first+name': 'Tester', 'email': 'test@test.com' },
- });
- editor.execCommand('mceInsertTemplate', false, '{$first+name}
');
- TinyAssertions.assertContent(editor, 'Tester
');
- });
-
- context('Previewing unparsed content', () => {
- const unparsedHtml = '
';
- const unparsedPreviewHtmlSelector = 'p > img[src="error"][onerror="throw new Error();"]';
- const parsedPreviewHtmlSelector = 'p > img[src="error"][data-mce-src="error"]';
-
- const pPreviewAndAssertNoUnparsedContent = async (editor: Editor): Promise => {
- const assertNoUnparsedContent = (dialogEl: SugarElement): void => {
- UiFinder.findIn(dialogEl, 'iframe').fold(
- () => assert.fail('Preview iframe not found'),
- (iframe) => {
- const iframeDoc = iframe.dom.contentDocument;
- const iframeBody = SugarElement.fromDom(iframeDoc?.body as Node);
- UiFinder.exists(iframeBody, parsedPreviewHtmlSelector);
- UiFinder.notExists(iframeBody, unparsedPreviewHtmlSelector);
- }
- );
- };
-
- try {
- await pPreviewTemplate(editor, assertNoUnparsedContent);
- } catch {
- assert.fail('Unparsed html read');
- }
- };
-
- it('TINY-9244: Parsed html should be shown when previewing template', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', content: unparsedHtml }],
- });
- await pPreviewAndAssertNoUnparsedContent(editor);
- });
-
- it('TINY-9867: Parsed html should be shown when previewing template containing tags', async () => {
- const editor = hook.editor();
- addSettings({
- templates: [{ title: 'a', description: 'b', content: `${unparsedHtml}` }],
- });
- await pPreviewAndAssertNoUnparsedContent(editor);
- });
- });
-
- context('Inserting unparsed content', () => {
- const unparsedHtml = '
';
- const assertFnDoesNotReadUnParsedHtmlInDom = async (editor: Editor, fn: (unparsedHtml: string) => void | Promise): Promise => {
- const isUnParsedHtmlRead = Cell(false);
- (editor.getDoc() as any).unparsedHtmlFn = () => {
- isUnParsedHtmlRead.set(true);
- };
- await fn(unparsedHtml);
- // wait for any unparsed html to be read and error to be thrown if it is
- await Waiter.pWait(1);
- assert.isFalse(isUnParsedHtmlRead.get(), 'Unparsed html read');
- (editor.getDoc() as any).unparsedHtmlFn = null;
- };
-
- it('TINY-9244: Unparsed html should not be read when inserting template via command', async () => {
- const editor = hook.editor();
- await assertFnDoesNotReadUnParsedHtmlInDom(editor, (unparsedHtml) => {
- editor.execCommand('mceInsertTemplate', false, unparsedHtml);
- });
- });
-
- it('TINY-9244: Unparsed html should not be read when inserting template via dialog', async () => {
- const editor = hook.editor();
- addSettings({ templates: [{ title: 'a', description: 'b', content: unparsedHtml }] });
- await assertFnDoesNotReadUnParsedHtmlInDom(editor, async () => {
- await pInsertTemplate(editor);
- });
- });
- });
-});
diff --git a/modules/tinymce/src/plugins/template/test/ts/module/InsertTemplate.ts b/modules/tinymce/src/plugins/template/test/ts/module/InsertTemplate.ts
deleted file mode 100644
index d4e2a8c4fc..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/module/InsertTemplate.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { UiFinder, Waiter } from '@ephox/agar';
-import { Type } from '@ephox/katamari';
-import { SugarBody, SugarElement } from '@ephox/sugar';
-import { TinyUiActions } from '@ephox/wrap-mcagar';
-
-import Editor from 'tinymce/core/api/Editor';
-
-const toolbarButtonSelector = '[role="toolbar"] button[aria-label="Insert template"]';
-const dialogSelector = 'div.tox-dialog';
-
-const waitUntilIframeLoaded = async (dialogEl: SugarElement): Promise => {
- await UiFinder.pWaitForState('iframe is loaded', dialogEl, 'iframe', (elm) => {
- // fallback for pre-IE 8 using contentWindow.document
- const iframeDoc = elm.dom.contentDocument || elm.dom.contentWindow?.document;
- return Type.isNonNullable(iframeDoc?.body.firstChild);
- });
-};
-
-const pUseTemplateDialog = async (editor: Editor, submit: boolean, assertFn?: (elm: SugarElement) => void): Promise => {
- TinyUiActions.clickOnToolbar(editor, toolbarButtonSelector);
- const dialogEl = await TinyUiActions.pWaitForDialog(editor);
- if (Type.isFunction(assertFn)) {
- await waitUntilIframeLoaded(dialogEl);
- assertFn(dialogEl);
- }
- if (submit) {
- TinyUiActions.submitDialog(editor);
- } else {
- TinyUiActions.closeDialog(editor);
- }
- await Waiter.pTryUntil('Dialog should close', () => UiFinder.notExists(SugarBody.body(), dialogSelector));
-};
-
-const pInsertTemplate = async (editor: Editor, assertFn?: (elm: SugarElement) => void): Promise => {
- await pUseTemplateDialog(editor, true, assertFn);
-};
-
-const pPreviewTemplate = async (editor: Editor, assertFn?: (elm: SugarElement) => void): Promise => {
- await pUseTemplateDialog(editor, false, assertFn);
-};
-
-export {
- pInsertTemplate,
- pPreviewTemplate
-};
diff --git a/modules/tinymce/src/plugins/template/test/ts/module/Settings.ts b/modules/tinymce/src/plugins/template/test/ts/module/Settings.ts
deleted file mode 100644
index 87c34aff9b..0000000000
--- a/modules/tinymce/src/plugins/template/test/ts/module/Settings.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { Obj } from '@ephox/katamari';
-import { TinyHooks } from '@ephox/wrap-mcagar';
-
-import Editor from 'tinymce/core/api/Editor';
-
-interface Settings {
- readonly addSettings: (config: Record) => void;
- readonly cleanupSettings: () => void;
-}
-
-const Settings = (hook: TinyHooks.Hook): Settings => {
- let settings = new Set();
-
- const addSettings = (config: Record) => {
- const editor = hook.editor();
- Obj.each(config, (val, key) => {
- editor.options.set(key, val);
- settings.add(key);
- });
- };
-
- const cleanupSettings = () => {
- const editor = hook.editor();
- settings.forEach((key) => editor.options.unset(key));
- settings = new Set();
- };
-
- return { addSettings, cleanupSettings };
-};
-
-export { Settings };
diff --git a/modules/tinymce/src/themes/silver/main/ts/ui/menus/menubar/Integration.ts b/modules/tinymce/src/themes/silver/main/ts/ui/menus/menubar/Integration.ts
index ac8789c3ee..d3f9863613 100644
--- a/modules/tinymce/src/themes/silver/main/ts/ui/menus/menubar/Integration.ts
+++ b/modules/tinymce/src/themes/silver/main/ts/ui/menus/menubar/Integration.ts
@@ -23,7 +23,7 @@ const defaultMenus: Record = {
file: { title: 'File', items: 'newdocument restoredraft | preview | export print | deleteallconversations' },
edit: { title: 'Edit', items: 'undo redo | cut copy paste pastetext | selectall | searchreplace' },
view: { title: 'View', items: 'code revisionhistory | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' },
- insert: { title: 'Insert', items: 'image link media addcomment pageembed template inserttemplate codesample inserttable accordion | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents footnotes | mergetags | insertdatetime' },
+ insert: { title: 'Insert', items: 'image link media addcomment pageembed inserttemplate codesample inserttable accordion | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents footnotes | mergetags | insertdatetime' },
format: { title: 'Format', items: 'bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat' },
tools: { title: 'Tools', items: 'aidialog aishortcuts | spellchecker spellcheckerlanguage | autocorrect capitalization | a11ycheck code typography wordcount addtemplate' },
table: { title: 'Table', items: 'inserttable | cell row column | advtablesort | tableprops deletetable' },
diff --git a/modules/tinymce/tsconfig.json b/modules/tinymce/tsconfig.json
index 3f1c4372cf..fdcf2a0e28 100644
--- a/modules/tinymce/tsconfig.json
+++ b/modules/tinymce/tsconfig.json
@@ -40,7 +40,6 @@
"tinymce/plugins/save/*": ["src/plugins/save/main/ts/*"],
"tinymce/plugins/searchreplace/*": ["src/plugins/searchreplace/main/ts/*"],
"tinymce/plugins/table/*": ["src/plugins/table/main/ts/*"],
- "tinymce/plugins/template/*": ["src/plugins/template/main/ts/*"],
"tinymce/plugins/visualblocks/*": ["src/plugins/visualblocks/main/ts/*"],
"tinymce/plugins/visualchars/*": ["src/plugins/visualchars/main/ts/*"],
"tinymce/plugins/wordcount/*": ["src/plugins/wordcount/main/ts/*"],
diff --git a/tsconfig.demo.json b/tsconfig.demo.json
index af790766d0..4f04b3339d 100644
--- a/tsconfig.demo.json
+++ b/tsconfig.demo.json
@@ -41,7 +41,6 @@
"tinymce/plugins/save/*": ["modules/tinymce/src/plugins/save/main/ts/*"],
"tinymce/plugins/searchreplace/*": ["modules/tinymce/src/plugins/searchreplace/main/ts/*"],
"tinymce/plugins/table/*": ["modules/tinymce/src/plugins/table/main/ts/*"],
- "tinymce/plugins/template/*": ["modules/tinymce/src/plugins/template/main/ts/*"],
"tinymce/plugins/visualblocks/*": ["modules/tinymce/src/plugins/visualblocks/main/ts/*"],
"tinymce/plugins/visualchars/*": ["modules/tinymce/src/plugins/visualchars/main/ts/*"],
"tinymce/plugins/wordcount/*": ["modules/tinymce/src/plugins/wordcount/main/ts/*"],
diff --git a/tsconfig.json b/tsconfig.json
index 5c3eccd558..6945e5d609 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -63,7 +63,6 @@
"tinymce/plugins/save/*": ["modules/tinymce/src/plugins/save/main/ts/*"],
"tinymce/plugins/searchreplace/*": ["modules/tinymce/src/plugins/searchreplace/main/ts/*"],
"tinymce/plugins/table/*": ["modules/tinymce/src/plugins/table/main/ts/*"],
- "tinymce/plugins/template/*": ["modules/tinymce/src/plugins/template/main/ts/*"],
"tinymce/plugins/visualblocks/*": ["modules/tinymce/src/plugins/visualblocks/main/ts/*"],
"tinymce/plugins/visualchars/*": ["modules/tinymce/src/plugins/visualchars/main/ts/*"],
"tinymce/plugins/wordcount/*": ["modules/tinymce/src/plugins/wordcount/main/ts/*"],