提交 39d629a0 作者: Vben

refactor(tinymce): changed to npm introduction,fix #435,fix 434

上级 37f6660c
......@@ -8,10 +8,12 @@
### ✨ Refactor
- 移除 useFullScreen 函数
- tinymce 由 Cdn 改为 npm(打包体积偏大)
### 🐛 Bug Fixes
- 确保面包屑正确的显示图标
- 修复 tinymce 上传按钮全屏模式下消失问题
## 2.1.1 (2021-03-26)
......
......@@ -46,6 +46,7 @@
"print-js": "^1.6.0",
"qrcode": "^1.4.4",
"sortablejs": "^1.13.0",
"tinymce": "^5.7.1",
"vditor": "^3.8.4",
"vue": "3.0.7",
"vue-i18n": "^9.0.0",
......@@ -84,7 +85,7 @@
"dotenv": "^8.2.0",
"eslint": "^7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-define-config": "^1.0.4",
"eslint-define-config": "^1.0.5",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.8.0",
"esno": "^0.5.0",
......
/**
* 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/
*/
body {
margin: 1rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.4;
}
table {
border-collapse: collapse;
}
table th,
table td {
padding: 0.4rem;
border: 1px solid #ccc;
}
figure {
display: table;
margin: 1rem auto;
}
figure figcaption {
display: block;
margin-top: 0.25rem;
color: #999;
text-align: center;
}
hr {
border-color: #ccc;
border-style: solid;
border-width: 1px 0 0 0;
}
code {
padding: 0.1rem 0.2rem;
background-color: #e8e8e8;
border-radius: 3px;
}
.mce-content-body:not([dir=rtl]) blockquote {
padding-left: 1rem;
margin-left: 1.5rem;
border-left: 2px solid #ccc;
}
.mce-content-body[dir=rtl] blockquote {
padding-right: 1rem;
margin-right: 1.5rem;
border-right: 2px solid #ccc;
}
\ No newline at end of file
/**
* 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/
*/
body{margin: 1rem;font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height: 1.4;}
table{border-collapse: collapse;}
table td,table th{padding: .4rem;border: 1px solid #ccc;}
figure{display: table;margin: 1rem auto;}
figure figcaption{display: block;margin-top: .25rem;color: #999;text-align: center;}
hr{border-color: #ccc;border-style: solid;border-width: 1px 0 0 0;}
code{padding: .1rem .2rem;background-color: #e8e8e8;border-radius: 3px;}
.mce-content-body:not([dir=rtl]) blockquote{padding-left: 1rem;margin-left: 1.5rem;border-left: 2px solid #ccc;}
.mce-content-body[dir=rtl] blockquote{padding-right: 1rem;margin-right: 1.5rem;border-right: 2px solid #ccc;}
/**
* 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/
*/
@media screen {
html {
background: #f4f4f4;
}
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
@media screen {
body {
max-width: 820px;
min-height: calc(100vh - 1rem);
padding: 4rem 6rem 6rem 6rem;
margin: 1rem auto 0;
background-color: #fff;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.15);
box-sizing: border-box;
}
}
table {
border-collapse: collapse;
}
table th,
table td {
padding: 0.4rem;
border: 1px solid #ccc;
}
figure figcaption {
margin-top: 0.25rem;
color: #999;
text-align: center;
}
hr {
border-color: #ccc;
border-style: solid;
border-width: 1px 0 0 0;
}
.mce-content-body:not([dir=rtl]) blockquote {
padding-left: 1rem;
margin-left: 1.5rem;
border-left: 2px solid #ccc;
}
.mce-content-body[dir=rtl] blockquote {
padding-right: 1rem;
margin-right: 1.5rem;
border-right: 2px solid #ccc;
}
\ No newline at end of file
/**
* 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/
*/
@media screen{html{background: #f4f4f4;}}
body{font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;}@media screen{body{max-width: 820px;min-height: calc(100vh - 1rem);padding: 4rem 6rem 6rem 6rem;margin: 1rem auto 0;background-color: #fff;box-shadow: 0 0 4px rgba(0,0,0,.15);box-sizing: border-box;}}
table{border-collapse: collapse;}
table td,table th{padding: .4rem;border: 1px solid #ccc;}
figure figcaption{margin-top: .25rem;color: #999;text-align: center;}
hr{border-color: #ccc;border-style: solid;border-width: 1px 0 0 0;}
.mce-content-body:not([dir=rtl]) blockquote{padding-left: 1rem;margin-left: 1.5rem;border-left: 2px solid #ccc;}
.mce-content-body[dir=rtl] blockquote{padding-right: 1rem;margin-right: 1.5rem;border-right: 2px solid #ccc;}
/**
* 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/
*/
body {
max-width: 900px;
margin: 1rem auto;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.4;
}
table {
border-collapse: collapse;
}
table th,
table td {
padding: 0.4rem;
border: 1px solid #ccc;
}
figure {
display: table;
margin: 1rem auto;
}
figure figcaption {
display: block;
margin-top: 0.25rem;
color: #999;
text-align: center;
}
hr {
border-color: #ccc;
border-style: solid;
border-width: 1px 0 0 0;
}
code {
padding: 0.1rem 0.2rem;
background-color: #e8e8e8;
border-radius: 3px;
}
.mce-content-body:not([dir=rtl]) blockquote {
padding-left: 1rem;
margin-left: 1.5rem;
border-left: 2px solid #ccc;
}
.mce-content-body[dir=rtl] blockquote {
padding-right: 1rem;
margin-right: 1.5rem;
border-right: 2px solid #ccc;
}
\ No newline at end of file
/**
* 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/
*/
body{max-width: 900px;margin: 1rem auto;font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height: 1.4;}
table{border-collapse: collapse;}
table td,table th{padding: .4rem;border: 1px solid #ccc;}
figure{display: table;margin: 1rem auto;}
figure figcaption{display: block;margin-top: .25rem;color: #999;text-align: center;}
hr{border-color: #ccc;border-style: solid;border-width: 1px 0 0 0;}
code{padding: .1rem .2rem;background-color: #e8e8e8;border-radius: 3px;}
.mce-content-body:not([dir=rtl]) blockquote{padding-left: 1rem;margin-left: 1.5rem;border-left: 2px solid #ccc;}
.mce-content-body[dir=rtl] blockquote{padding-right: 1rem;margin-right: 1.5rem;border-right: 2px solid #ccc;}
/**
* 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/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection {
position: absolute;
display: inline-block;
/* Note: this file is used inside the content, so isn't part of theming */
background-color: green;
opacity: 0.5;
}
body {
-webkit-text-size-adjust: none;
}
body img {
/* this is related to the content margin */
max-width: 96vw;
}
body table img {
max-width: 95%;
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}
\ No newline at end of file
/**
* 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/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{position: absolute;display: inline-block;background-color: green;opacity: .5;}
body{-webkit-text-size-adjust: none;}
body img{max-width: 96vw;}
body table img{max-width: 95%;}
body{font-family: sans-serif;}
table{border-collapse: collapse;}
/**
* 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/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection {
position: absolute;
display: inline-block;
/* Note: this file is used inside the content, so isn't part of theming */
background-color: green;
opacity: 0.5;
}
body {
-webkit-text-size-adjust: none;
}
body img {
/* this is related to the content margin */
max-width: 96vw;
}
body table img {
max-width: 95%;
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}
\ No newline at end of file
/**
* 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/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{position: absolute;display: inline-block;background-color: green;opacity: .5;}
body{-webkit-text-size-adjust: none;}
body img{max-width: 96vw;}
body table img{max-width: 95%;}
body{font-family: sans-serif;}
table{border-collapse: collapse;}
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
export const Tinymce = createAsyncComponent(() => import('./src/Editor.vue'));
import Tinymce from './src/Editor.vue';
export { Tinymce };
<template>
<div :class="prefixCls" :style="{ width: containerWidth }">
<ImgUpload
:fullscreen="fullscreen"
@uploading="handleImageUploading"
@done="handleDone"
v-if="showImageUpload"
......@@ -21,31 +22,103 @@
onUnmounted,
onDeactivated,
} from 'vue';
import { basicProps } from './props';
import tinymce from 'tinymce/tinymce';
import 'tinymce/skins/ui/oxide/skin.min.css';
import 'tinymce/themes/silver';
import toolbar from './toolbar';
import plugins from './plugins';
import { getTinymce } from './getTinymce';
import { useScript } from '/@/hooks/web/useScript';
import { buildShortUUID } from '/@/utils/uuid';
import { bindHandlers } from './helper';
import lineHeight from './lineHeight';
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
import ImgUpload from './ImgUpload.vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { isNumber } from '/@/utils/is';
const CDN_URL = 'https://cdn.bootcdn.net/ajax/libs/tinymce/5.5.1';
import 'tinymce/icons/default/icons';
import 'tinymce/themes/mobile';
import 'tinymce/plugins/emoticons';
import 'tinymce/plugins/emoticons/js/emojis';
import 'tinymce/plugins/advlist';
import 'tinymce/plugins/anchor';
import 'tinymce/plugins/autolink';
import 'tinymce/plugins/autosave';
import 'tinymce/plugins/code';
import 'tinymce/plugins/codesample';
import 'tinymce/plugins/directionality';
import 'tinymce/plugins/fullscreen';
import 'tinymce/plugins/hr';
import 'tinymce/plugins/image';
import 'tinymce/plugins/imagetools';
import 'tinymce/plugins/insertdatetime';
import 'tinymce/plugins/link';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/media';
import 'tinymce/plugins/nonbreaking';
import 'tinymce/plugins/noneditable';
import 'tinymce/plugins/pagebreak';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/preview';
import 'tinymce/plugins/print';
import 'tinymce/plugins/save';
import 'tinymce/plugins/searchreplace';
import 'tinymce/plugins/spellchecker';
import 'tinymce/plugins/tabfocus';
import 'tinymce/plugins/table';
import 'tinymce/plugins/template';
import 'tinymce/plugins/textpattern';
import 'tinymce/plugins/visualblocks';
import 'tinymce/plugins/visualchars';
import 'tinymce/plugins/wordcount';
const tinymceScriptSrc = `${CDN_URL}/tinymce.min.js`;
const tinymceProps = {
options: {
type: Object as PropType<any>,
default: {},
},
value: {
type: String,
},
toolbar: {
type: Array as PropType<string[]>,
default: toolbar,
},
plugins: {
type: Array as PropType<string[]>,
default: plugins,
},
modelValue: {
type: String,
},
height: {
type: [Number, String] as PropType<string | number>,
required: false,
default: 400,
},
width: {
type: [Number, String] as PropType<string | number>,
required: false,
default: 'auto',
},
showImageUpload: {
type: Boolean,
default: true,
},
};
export default defineComponent({
name: 'Tinymce',
components: { ImgUpload },
inheritAttrs: false,
props: basicProps,
props: tinymceProps,
emits: ['change', 'update:modelValue'],
setup(props, { emit, attrs }) {
const editorRef = ref<any>(null);
const fullscreen = ref(false);
const tinymceId = ref<string>(buildShortUUID('tiny-vue'));
const elRef = ref<Nullable<HTMLElement>>(null);
......@@ -64,26 +137,24 @@
});
const initOptions = computed(() => {
const { height, options } = props;
const { height, options, toolbar, plugins } = props;
return {
selector: `#${unref(tinymceId)}`,
base_url: CDN_URL,
suffix: '.min',
height: height,
toolbar: toolbar,
height,
toolbar,
menubar: 'file edit insert view format table',
plugins: plugins,
// 语言包
language_url: 'resource/tinymce/langs/zh_CN.js',
// 中文
plugins,
language_url: '/resource/tinymce/langs/zh_CN.js',
language: 'zh_CN',
branding: false,
default_link_target: '_blank',
link_title: false,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
object_resizing: false,
fontsize_formats: '10px 11px 12px 14px 16px 18px 20px 24px 36px 48px',
lineheight_formats: '1 1.5 1.75 2.0 3.0 4.0 5.0',
skin: 'oxide',
skin_url: 'resource/tinymce/skins/ui/oxide',
content_css: 'resource/tinymce/skins/content/default/content.css',
...options,
setup: (editor: any) => {
editorRef.value = editor;
......@@ -92,10 +163,6 @@
};
});
const { toPromise } = useScript({
src: tinymceScriptSrc,
});
watch(
() => attrs.disabled,
() => {
......@@ -104,10 +171,13 @@
editor.setMode(attrs.disabled ? 'readonly' : 'design');
}
);
onMountedOrActivated(() => {
tinymceId.value = buildShortUUID('tiny-vue');
nextTick(() => {
init();
setTimeout(() => {
initEditor();
}, 30);
});
});
......@@ -120,26 +190,17 @@
});
function destory() {
if (getTinymce() !== null) {
getTinymce()?.remove?.(unref(editorRef));
if (tinymce !== null) {
tinymce?.remove?.(unref(editorRef));
}
}
function init() {
toPromise().then(() => {
setTimeout(() => {
initEditor();
}, 0);
});
}
function initEditor() {
getTinymce().PluginManager.add('lineHeight', lineHeight(getTinymce()));
const el = unref(elRef);
if (el) {
el.style.visibility = '';
}
getTinymce().init(unref(initOptions));
tinymce.init(unref(initOptions));
}
function initSetup(e: Event) {
......@@ -189,6 +250,10 @@
emit('update:modelValue', content);
emit('change', content);
});
editor.on('FullscreenStateChanged', (e) => {
fullscreen.value = e.state;
});
}
function handleImageUploading(name: string) {
......@@ -216,12 +281,12 @@
containerWidth,
initOptions,
tinymceContent,
tinymceScriptSrc,
elRef,
tinymceId,
handleImageUploading,
handleDone,
editorRef,
fullscreen,
};
},
});
......
<template>
<div :class="prefixCls">
<div :class="[prefixCls, { fullscreen }]">
<Upload
name="file"
multiple
......@@ -25,6 +25,11 @@
export default defineComponent({
name: 'TinymceImageUpload',
components: { Upload },
props: {
fullscreen: {
type: Boolean,
},
},
emits: ['uploading', 'done', 'error'],
setup(_, { emit }) {
let uploading = false;
......@@ -69,5 +74,10 @@
top: 4px;
right: 10px;
z-index: 20;
&.fullscreen {
position: fixed;
z-index: 10000;
}
}
</style>
const getGlobal = (): any => (typeof window !== 'undefined' ? window : global);
export const getTinymce = () => {
const global = getGlobal();
return global && global.tinymce ? global.tinymce : null;
};
const lineHeight = function (tinymce: any) {
tinymce.PluginManager.add('lineheight', function (t: any) {
t.on('init', function () {
t.formatter.register({
lineheight: {
inline: 'span',
styles: {
'line-height': '%value',
},
},
});
});
t.ui.registry.addMenuButton('lineheight', {
icon: 'lineheight',
tooltip: 'Line Height',
// fetch: function (callback: Fn) {
// var dom = t.dom;
// var blocks = t.selection.getSelectedBlocks();
// var lhv = 0;
// global$1.each(blocks, function (block: any) {
// if (lhv == 0) {
// lhv = dom.getStyle(block, 'line-height') ? dom.getStyle(block, 'line-height') : 0;
// }
// });
// var items = lineheight_val.split(' ').map(function (item) {
// var text = item;
// var value = item;
// return {
// type: 'togglemenuitem',
// text: text,
// active: lhv == value ? true : false,
// onAction: function () {
// doAct(value);
// },
// };
// });
// callback(items);
// },
});
});
tinymce.PluginManager.requireLangPack('lineheight', 'de');
};
export default lineHeight;
......@@ -4,7 +4,7 @@
// colorpicker/contextmenu/textcolor plugin is now built in to the core editor, please remove it from your editor configuration
const plugins = [
'lineheight advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount',
'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount',
];
export default plugins;
import { PropType } from 'vue';
import { propTypes } from '/@/utils/propTypes';
export const basicProps = {
options: {
type: Object as PropType<any>,
default: {},
},
value: propTypes.string,
modelValue: propTypes.string,
// 高度
height: {
type: [Number, String] as PropType<string | number>,
required: false,
default: 400,
},
// 宽度
width: {
type: [Number, String] as PropType<string | number>,
required: false,
default: 'auto',
},
showImageUpload: propTypes.bool.def(true),
};
......@@ -50,4 +50,8 @@ import 'vite-plugin-svg-icons/register';
await router.isReady();
app.mount('#app', true);
if (import.meta.env.DEV) {
window.__APP__ = app;
}
})();
......@@ -7,10 +7,10 @@ import type {
} from 'vue';
declare global {
// declare interface Window {
declare interface Window {
// Global vue app instance
// __APP__: App<Element>;
// }
__APP__: App<Element>;
}
// vue
declare type PropType<T> = VuePropType<T>;
......
......@@ -4328,10 +4328,10 @@ eslint-config-prettier@^8.1.0:
resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz#4ef1eaf97afe5176e6a75ddfb57c335121abc5a6"
integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==
eslint-define-config@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/eslint-define-config/-/eslint-define-config-1.0.4.tgz#e3b3a177600155f1ffe9e38f90332da956f7959c"
integrity sha512-vGnX8CfockGwXP4NuORbnHd7PWy8gr41ARLH4HuWJoHk4U4ni5KjDG6Kg1/GNIE0B9BwXfyDgW7I3mSx2zuT0A==
eslint-define-config@^1.0.5:
version "1.0.5"
resolved "https://registry.npmjs.org/eslint-define-config/-/eslint-define-config-1.0.5.tgz#e4799d27a75f51ab1ce151f00b6802f03948b1fc"
integrity sha512-kwBMdZ7UKpzTkymYnBZrTSOGbawoCnPOKVUjSbOype9dj7YRczT1nDKk0tPRawtcm7y7zfoGf5nBUrcYO60Avg==
eslint-plugin-jest@^24.1.5:
version "24.3.2"
......@@ -10331,6 +10331,11 @@ tinycolor2@^1.4.2:
resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
tinymce@^5.7.1:
version "5.7.1"
resolved "https://registry.npmjs.org/tinymce/-/tinymce-5.7.1.tgz#658a6fb4c7d53a8496cc00f8da33f4b8290da06d"
integrity sha512-1gY8RClc734srSlkYwY0MQzmkS1j73PuPC+nYtNtrrQVPY9VNcZ4bOiRwzTbdjPPD8GOtv6BAk8Ww/H2RiqKpA==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论