This commit is contained in:
2025-10-22 15:39:40 +08:00
commit b0b510fac1
2720 changed files with 415933 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Plugin: code Demo Page</title>
</head>
<body>
<h2>Plugin: visualblocks Demo Page</h2>
<div id="ephox-ui">
<textarea name="" id="" cols="30" rows="10" class="tinymce">
&lt;h1&gt;Header 1&lt;/h1&gt;
&lt;h2&gt;Header 2&lt;/h2&gt;
&lt;h3&gt;Header 3&lt;/h3&gt;
&lt;h4&gt;Header 4&lt;/h4&gt;
&lt;h5&gt;Header 5&lt;/h5&gt;
&lt;h6&gt;Header 6&lt;/h6&gt;
&lt;p&gt;Paragraph&lt;/p&gt;
&lt;div&gt;Div&lt;/div&gt;
&lt;pre&gt;Pre&lt;/pre&gt;
&lt;address&gt;Address&lt;/address&gt;
&lt;section&gt;Section&lt;p&gt;Paragraph&lt;/p&gt;&lt;/section&gt;
&lt;article&gt;Article&lt;p&gt;Paragraph&lt;/p&gt;&lt;/article&gt;
&lt;blockquote&gt;Blockquote&lt;p&gt;Paragraph&lt;/p&gt;&lt;/blockquote&gt;
&lt;hgroup&gt;&lt;h1&gt;Header 1&lt;/h1&gt;&lt;/hgroup&gt;
&lt;aside&gt;Section&lt;p&gt;Paragraph&lt;/p&gt;&lt;/aside&gt;
&lt;figure&gt;Figure&lt;figcaption&gt;Figcaption&lt;/figcaption&gt;&lt;/figure&gt;
</textarea>
</div>
<script src="../../../../../js/tinymce/tinymce.js"></script>
<script src="../../../../../scratch/demos/plugins/visualblocks/demo.js"></script>
</body>
</html>

View File

@@ -0,0 +1,41 @@
/**
* Demo.js
*
* Released under LGPL License.
* Copyright (c) 1999-2016 Ephox Corp. All rights reserved
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*/
declare let tinymce: any;
tinymce.init({
selector: 'textarea.tinymce',
plugins: 'visualblocks code',
toolbar: 'visualblocks code',
visualblocks_default_state: true,
skin_url: '../../../../../js/tinymce/skins/lightgray',
// end_container_on_empty_block: true,
// Style formats
style_formats: [
{ title: 'h1', block: 'h1' },
{ title: 'h2', block: 'h2' },
{ title: 'h3', block: 'h3' },
{ title: 'h4', block: 'h4' },
{ title: 'h5', block: 'h5' },
{ title: 'h6', block: 'h6' },
{ title: 'p', block: 'p' },
{ title: 'div', block: 'div' },
{ title: 'pre', block: 'pre' },
{ title: 'section', block: 'section', wrapper: true, merge_siblings: false },
{ title: 'article', block: 'article', wrapper: true, merge_siblings: false },
{ title: 'blockquote', block: 'blockquote', wrapper: true },
{ title: 'hgroup', block: 'hgroup', wrapper: true },
{ title: 'aside', block: 'aside', wrapper: true },
{ title: 'figure', block: 'figure', wrapper: true }
],
height: 600
});
export {};

View File

@@ -0,0 +1,154 @@
.mce-visualblocks p {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
background-repeat: no-repeat;
}
.mce-visualblocks h1 {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks h2 {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks h3 {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
background-repeat: no-repeat;
}
.mce-visualblocks h4 {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks h5 {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks h6 {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks div:not([data-mce-bogus]) {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
background-repeat: no-repeat;
}
.mce-visualblocks section {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
background-repeat: no-repeat;
}
.mce-visualblocks article {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
background-repeat: no-repeat;
}
.mce-visualblocks blockquote {
padding-top: 10px;
border: 1px dashed #BBB;
background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
background-repeat: no-repeat;
}
.mce-visualblocks address {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
background-repeat: no-repeat;
}
.mce-visualblocks pre {
padding-top: 10px;
border: 1px dashed #BBB;
margin-left: 3px;
background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks figure {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
background-repeat: no-repeat;
}
.mce-visualblocks hgroup {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
background-repeat: no-repeat;
}
.mce-visualblocks aside {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
background-repeat: no-repeat;
}
.mce-visualblocks figcaption {
border: 1px dashed #BBB;
}
.mce-visualblocks ul {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks ol {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
background-repeat: no-repeat;
}
.mce-visualblocks dl {
padding-top: 10px;
border: 1px dashed #BBB;
margin: 0 0 1em 3px;
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
background-repeat: no-repeat;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
import { Cell } from '@ephox/katamari';
import PluginManager from 'tinymce/core/api/PluginManager';
import Commands from './api/Commands';
import Bindings from './core/Bindings';
import Buttons from './ui/Buttons';
PluginManager.add('visualblocks', function (editor, pluginUrl) {
const enabledState = Cell(false);
Commands.register(editor, pluginUrl, enabledState);
Buttons.register(editor, enabledState);
Bindings.setup(editor, pluginUrl, enabledState);
});
export default function () { }

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
import VisualBlocks from '../core/VisualBlocks';
const register = function (editor, pluginUrl, enabledState) {
editor.addCommand('mceVisualBlocks', function () {
VisualBlocks.toggleVisualBlocks(editor, pluginUrl, enabledState);
});
};
export default {
register
};

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
const fireVisualBlocks = function (editor, state) {
editor.fire('VisualBlocks', { state });
};
export default {
fireVisualBlocks
};

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
const isEnabledByDefault = function (editor) {
return editor.getParam('visualblocks_default_state', false);
};
const getContentCss = function (editor) {
return editor.settings.visualblocks_content_css;
};
export default {
isEnabledByDefault,
getContentCss
};

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
import Settings from '../api/Settings';
import VisualBlocks from './VisualBlocks';
const setup = function (editor, pluginUrl, enabledState) {
// Prevents the visualblocks from being presented in the preview of formats when that is computed
editor.on('PreviewFormats AfterPreviewFormats', function (e) {
if (enabledState.get()) {
editor.dom.toggleClass(editor.getBody(), 'mce-visualblocks', e.type === 'afterpreviewformats');
}
});
editor.on('init', function () {
if (Settings.isEnabledByDefault(editor)) {
VisualBlocks.toggleVisualBlocks(editor, pluginUrl, enabledState);
}
});
editor.on('remove', function () {
editor.dom.removeClass(editor.getBody(), 'mce-visualblocks');
});
};
export default {
setup
};

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
import DOMUtils from 'tinymce/core/api/dom/DOMUtils';
import Tools from 'tinymce/core/api/util/Tools';
const cssId = DOMUtils.DOM.uniqueId();
const load = function (doc, url) {
const linkElements = Tools.toArray(doc.getElementsByTagName('link'));
const matchingLinkElms = Tools.grep(linkElements, function (head) {
return head.id === cssId;
});
if (matchingLinkElms.length === 0) {
const linkElm = DOMUtils.DOM.create('link', {
id: cssId,
rel: 'stylesheet',
href: url
});
doc.getElementsByTagName('head')[0].appendChild(linkElm);
}
};
export default {
load
};

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
import Events from '../api/Events';
import Settings from '../api/Settings';
import LoadCss from './LoadCss';
const toggleVisualBlocks = function (editor, pluginUrl, enabledState) {
const dom = editor.dom;
const contentCss = Settings.getContentCss(editor);
LoadCss.load(editor.getDoc(), contentCss ? contentCss : pluginUrl + '/css/visualblocks.css');
dom.toggleClass(editor.getBody(), 'mce-visualblocks');
enabledState.set(!enabledState.get());
Events.fireVisualBlocks(editor, enabledState.get());
};
export default {
toggleVisualBlocks
};

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
const toggleActiveState = function (editor, enabledState) {
return function (e) {
const ctrl = e.control;
ctrl.active(enabledState.get());
editor.on('VisualBlocks', function (e) {
ctrl.active(e.state);
});
};
};
const register = function (editor, enabledState) {
editor.addButton('visualblocks', {
active: false,
title: 'Show blocks',
cmd: 'mceVisualBlocks',
onPostRender: toggleActiveState(editor, enabledState)
});
editor.addMenuItem('visualblocks', {
text: 'Show blocks',
cmd: 'mceVisualBlocks',
onPostRender: toggleActiveState(editor, enabledState),
selectable: true,
context: 'view',
prependToContext: true
});
};
export default {
register
};

View File

@@ -0,0 +1,49 @@
import { Assertions, GeneralSteps, Logger, Pipeline, Step, Waiter } from '@ephox/agar';
import { UnitTest } from '@ephox/bedrock';
import { TinyApis, TinyLoader } from '@ephox/mcagar';
import { Class, Css, Element } from '@ephox/sugar';
import VisualBlocksPlugin from 'tinymce/plugins/visualblocks/Plugin';
import ModernTheme from 'tinymce/themes/modern/Theme';
UnitTest.asynctest('browser.tinymce.plugins.visualblocks.PreviewFormatsTest', function () {
const success = arguments[arguments.length - 2];
const failure = arguments[arguments.length - 1];
ModernTheme();
VisualBlocksPlugin();
const sWaitForVisualBlocks = function (editor) {
return Waiter.sTryUntil('Wait background css to be applied to first element', Step.sync(function () {
const p = Element.fromDom(editor.getBody().firstChild);
const background = Css.get(p, 'background-image');
Assertions.assertEq('Paragraph should have a url background', true, background.indexOf('url(') === 0);
}), 10, 10000);
};
TinyLoader.setup(function (editor, onSuccess, onFailure) {
const tinyApis = TinyApis(editor);
Pipeline.async({}, [
Logger.t('Toggle on/off visualblocks and compute previews', GeneralSteps.sequence([
tinyApis.sExecCommand('mceVisualBlocks'),
sWaitForVisualBlocks(editor),
Step.sync(function () {
Assertions.assertEq('Visual blocks class should exist', true, Class.has(Element.fromDom(editor.getBody()), 'mce-visualblocks'));
Assertions.assertEq('Should not have a border property', true, editor.formatter.getCssText('h1').indexOf('border:1px dashed') === -1);
}),
tinyApis.sExecCommand('mceVisualBlocks'),
Step.sync(function () {
Assertions.assertEq('Visual blocks class should not exist', false, Class.has(Element.fromDom(editor.getBody()), 'mce-visualblocks'));
Assertions.assertEq('Should not have a border property', true, editor.formatter.getCssText('h1').indexOf('border:1px dashed') === -1);
Assertions.assertEq('Visual blocks class should still not exist', false, Class.has(Element.fromDom(editor.getBody()), 'mce-visualblocks'));
})
]))
], onSuccess, onFailure);
}, {
plugins: 'visualblocks',
toolbar: 'visualblocks',
visualblocks_content_css: '/project/js/tinymce/plugins/visualblocks/css/visualblocks.css',
skin_url: '/project/js/tinymce/skins/lightgray'
}, success, failure);
});

View File

@@ -0,0 +1,51 @@
import { ApproxStructure, Pipeline } from '@ephox/agar';
import { UnitTest } from '@ephox/bedrock';
import { TinyApis, TinyLoader, TinyUi } from '@ephox/mcagar';
import VisualBlocksPlugin from 'tinymce/plugins/visualblocks/Plugin';
import ModernTheme from 'tinymce/themes/modern/Theme';
UnitTest.asynctest(
'browser.tinymce.plugins.visualblocks.VisualBlocksSanityTest',
function () {
const success = arguments[arguments.length - 2];
const failure = arguments[arguments.length - 1];
ModernTheme();
VisualBlocksPlugin();
TinyLoader.setup(function (editor, onSuccess, onFailure) {
const tinyUi = TinyUi(editor);
const tinyApis = TinyApis(editor);
Pipeline.async({}, [
tinyApis.sAssertContentStructure(ApproxStructure.build(function (s, str, arr) {
return s.element('body', {
classes: [
arr.not('mce-visualblocks')
]
});
})),
tinyUi.sClickOnToolbar('click visualblocks button', 'div[aria-label="Show blocks"] > button'),
tinyApis.sAssertContentStructure(ApproxStructure.build(function (s, str, arr) {
return s.element('body', {
classes: [
arr.has('mce-visualblocks')
]
});
})),
tinyUi.sClickOnToolbar('click visualblocks button', 'div[aria-label="Show blocks"] > button'),
tinyApis.sAssertContentStructure(ApproxStructure.build(function (s, str, arr) {
return s.element('body', {
classes: [
arr.not('mce-visualblocks')
]
});
}))
], onSuccess, onFailure);
}, {
plugins: 'visualblocks',
toolbar: 'visualblocks',
skin_url: '/project/js/tinymce/skins/lightgray'
}, success, failure);
}
);