feat: 更新 MarkdownEditor 组件及其 editor.md 源码
This commit is contained in:
parent
a43f75db00
commit
c66d5c88ec
@ -436,7 +436,39 @@
|
||||
var _this = this;
|
||||
var classPrefix = this.classPrefix = editormd.classPrefix;
|
||||
var settings = this.settings = $.extend(true, editormd.defaults, options);
|
||||
|
||||
|
||||
// 支持新增自定义 toolbar(要求 settings.toolbarIcons 非自定义模式)
|
||||
if (settings.appendToolbar && typeof settings.toolbarIcons === "string" && settings.toolbarIcons in editormd.toolbarModes) {
|
||||
editormd.toolbarModes[settings.toolbarIcons].push("|");
|
||||
settings.appendToolbar.forEach(toolbar => {
|
||||
// 如果没有 name 字段,则忽略该 toolbar
|
||||
if (!('name' in toolbar)) {
|
||||
return;
|
||||
}
|
||||
|
||||
editormd.toolbarModes[settings.toolbarIcons].push(toolbar.name);
|
||||
if ('icon' in toolbar) {
|
||||
settings.toolbarIconsClass[toolbar.name] = toolbar.icon;
|
||||
}
|
||||
if ('title' in toolbar) {
|
||||
settings.lang.toolbar[toolbar.name] = toolbar.title;
|
||||
}
|
||||
if ('handler' in toolbar) {
|
||||
settings.toolbarHandlers[toolbar.name] = toolbar.handler;
|
||||
if ('shortcut' in toolbar) {
|
||||
// 给新增的工具栏图标绑定快捷键
|
||||
toolbar.shortcut.forEach(key => editormd.keyMaps[key] = toolbar.handler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.shortcutFunction) {
|
||||
for (const key in settings.shortcutFunction) {
|
||||
editormd.keyMaps[key] = settings.shortcutFunction[key];
|
||||
}
|
||||
}
|
||||
|
||||
id = (typeof id === "object") ? settings.id : id;
|
||||
|
||||
var editor = this.editor = $("#" + id);
|
||||
@ -1339,6 +1371,8 @@
|
||||
if (typeof settings.toolbarHandlers[name] !== "undefined")
|
||||
{
|
||||
$.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection);
|
||||
} else {
|
||||
alert("This feature is not yet implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -3901,8 +3935,8 @@
|
||||
|
||||
if (typeof attrs !== "undefined")
|
||||
{
|
||||
// 将 html 标签的 attr value 中存在的 <> 进行转义
|
||||
// 示例 <a name="<p>code</p>"></a> 替换为 <a name="<p>code</p>"></a>
|
||||
// 将 html 标签的 attr value 中可能存在的 <> 尖括号进行转义,避免后面的正则替换发生错误
|
||||
// 示例 <a name="<p>code</p>"></a> 转化为 <a name="<p>code</p>"></a>
|
||||
html = html.replace(/(\w+)="([^"]*)"/g, (match, key, value) => {
|
||||
const escapedValue = value.replace(/</g, '<').replace(/>/g, '>');
|
||||
return `${key}="${escapedValue}"`;
|
||||
|
||||
6
public/static/editor.md/editormd.amd.min.js
vendored
6
public/static/editor.md/editormd.amd.min.js
vendored
File diff suppressed because one or more lines are too long
@ -366,7 +366,39 @@
|
||||
var _this = this;
|
||||
var classPrefix = this.classPrefix = editormd.classPrefix;
|
||||
var settings = this.settings = $.extend(true, {}, editormd.defaults, options);
|
||||
|
||||
|
||||
// 支持新增自定义 toolbar(要求 settings.toolbarIcons 非自定义模式)
|
||||
if (settings.appendToolbar && typeof settings.toolbarIcons === "string" && settings.toolbarIcons in editormd.toolbarModes) {
|
||||
editormd.toolbarModes[settings.toolbarIcons].push("|");
|
||||
settings.appendToolbar.forEach(toolbar => {
|
||||
// 如果没有 name 字段,则忽略该 toolbar
|
||||
if (!('name' in toolbar)) {
|
||||
return;
|
||||
}
|
||||
|
||||
editormd.toolbarModes[settings.toolbarIcons].push(toolbar.name);
|
||||
if ('icon' in toolbar) {
|
||||
settings.toolbarIconsClass[toolbar.name] = toolbar.icon;
|
||||
}
|
||||
if ('title' in toolbar) {
|
||||
settings.lang.toolbar[toolbar.name] = toolbar.title;
|
||||
}
|
||||
if ('handler' in toolbar) {
|
||||
settings.toolbarHandlers[toolbar.name] = toolbar.handler;
|
||||
if ('shortcut' in toolbar) {
|
||||
// 给新增的工具栏图标绑定快捷键
|
||||
toolbar.shortcut.forEach(key => editormd.keyMaps[key] = toolbar.handler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.shortcutFunction) {
|
||||
for (const key in settings.shortcutFunction) {
|
||||
editormd.keyMaps[key] = settings.shortcutFunction[key];
|
||||
}
|
||||
}
|
||||
|
||||
id = (typeof id === "object") ? settings.id : id;
|
||||
|
||||
var editor = this.editor = $("#" + id);
|
||||
@ -1269,6 +1301,8 @@
|
||||
if (typeof settings.toolbarHandlers[name] !== "undefined")
|
||||
{
|
||||
$.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection);
|
||||
} else {
|
||||
alert("This feature is not yet implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -3832,8 +3866,8 @@
|
||||
|
||||
if (typeof attrs !== "undefined")
|
||||
{
|
||||
// 将 html 标签的 attr value 中存在的 <> 进行转义
|
||||
// 示例 <a name="<p>code</p>"></a> 替换为 <a name="<p>code</p>"></a>
|
||||
// 将 html 标签的 attr value 中可能存在的 <> 尖括号进行转义,避免后面的正则替换发生错误
|
||||
// 示例 <a name="<p>code</p>"></a> 转化为 <a name="<p>code</p>"></a>
|
||||
html = html.replace(/(\w+)="([^"]*)"/g, (match, key, value) => {
|
||||
const escapedValue = value.replace(/</g, '<').replace(/>/g, '>');
|
||||
return `${key}="${escapedValue}"`;
|
||||
|
||||
5
public/static/editor.md/editormd.min.js
vendored
5
public/static/editor.md/editormd.min.js
vendored
File diff suppressed because one or more lines are too long
@ -46,7 +46,6 @@
|
||||
action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid;
|
||||
}
|
||||
|
||||
var imageFileName = classPrefix + "image-file";
|
||||
// 将 action 置为 # 号。后面使用 ajax 重写图片上传请求
|
||||
var dialogContent = ( (settings.imageUpload) ? "<form action=\"#\" target=\"" + iframeName + "\" method=\"post\" enctype=\"multipart/form-data\" class=\"" + classPrefix + "form\">" : "<div class=\"" + classPrefix + "form\">" ) +
|
||||
( (settings.imageUpload) ? "<iframe name=\"" + iframeName + "\" id=\"" + iframeName + "\" guid=\"" + guid + "\"></iframe>" : "" ) +
|
||||
@ -61,8 +60,8 @@
|
||||
"<label>" + imageLang.url + "</label>" +
|
||||
"<input type=\"text\" data-url />" + (function(){
|
||||
return (settings.imageUpload) ? "<div class=\"" + classPrefix + "file-input\">" +
|
||||
// 这里增加 id = {imageFileName},方便后面拿到文件数据
|
||||
"<input type=\"file\" name=\"" + imageFileName + "\" id=\"" + imageFileName + "\" accept=\"image/*\" />" +
|
||||
// 这里增加 id 属性,方便后面拿到文件数据
|
||||
"<input type=\"file\" id=\"" + classPrefix + "image-file\" name=\"" + classPrefix + "image-file\" accept=\"image/*\" />" +
|
||||
"<input type=\"submit\" value=\"" + imageLang.uploadButton + "\" />" +
|
||||
"</div>" : "";
|
||||
})() +
|
||||
@ -145,15 +144,17 @@
|
||||
// 给按钮绑定事件,支持手动更新 settings.imageUploadURL
|
||||
$('#lock-or-unlock').on('click', function() {
|
||||
let uploadURLInput = $('#upload-url-input')
|
||||
if (uploadURLInput.attr('disabled') == undefined) {
|
||||
if (uploadURLInput.attr('disabled') === undefined) {
|
||||
// 如果输入框未被禁用,则禁用按钮
|
||||
$(this).text('Unlock');
|
||||
uploadURLInput.attr('disabled', 'disabled');
|
||||
// 用输入框内容更新 imageUploadURL
|
||||
if (uploadURLInput.val().trim().length > 0) {
|
||||
settings.imageUploadURL = uploadURLInput.val().trim()
|
||||
// 触发回调事件,支持向上暴露
|
||||
settings.imageUploadURLChange(settings.imageUploadURL)
|
||||
// 更新 imageUploadURL 触发回调事件
|
||||
if (typeof settings.imageUploadURLChange === 'function') {
|
||||
settings.imageUploadURLChange(settings.imageUploadURL)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果输入框为禁用状态,则解锁输入框
|
||||
@ -163,7 +164,7 @@
|
||||
}
|
||||
})
|
||||
|
||||
var fileInput = dialog.find("[name=\"" + imageFileName + "\"]");
|
||||
var fileInput = dialog.find("[name=\"" + classPrefix + "image-file\"]");
|
||||
|
||||
fileInput.bind("change", function() {
|
||||
var fileName = fileInput.val();
|
||||
@ -193,7 +194,7 @@
|
||||
|
||||
loading(false);
|
||||
|
||||
// 注释掉官方写法,这里存在 iframe 跨域问题
|
||||
// 注释掉原来的写法,这里存在 iframe 跨域问题
|
||||
// var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
|
||||
// var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);
|
||||
|
||||
@ -211,10 +212,13 @@
|
||||
// }
|
||||
// }
|
||||
|
||||
// 重写图片上传方法
|
||||
var formData = new FormData();
|
||||
formData.append(imageFileName, $("#" + imageFileName)[0].files[0]);
|
||||
// 重写图片上传方法,支持 token 鉴权
|
||||
var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid;
|
||||
var formData = new FormData();
|
||||
formData.append(classPrefix + "image-file", $("#" + classPrefix + "image-file")[0].files[0]);
|
||||
if (settings.imageUploadToken !== undefined && settings.imageUploadToken.length > 0) {
|
||||
formData.append("token", settings.imageUploadToken);
|
||||
}
|
||||
$.ajax({
|
||||
url: action,
|
||||
type: "POST",
|
||||
|
||||
@ -354,7 +354,39 @@
|
||||
var _this = this;
|
||||
var classPrefix = this.classPrefix = editormd.classPrefix;
|
||||
var settings = this.settings = $.extend(true, editormd.defaults, options);
|
||||
|
||||
|
||||
// 支持新增自定义 toolbar(要求 settings.toolbarIcons 非自定义模式)
|
||||
if (settings.appendToolbar && typeof settings.toolbarIcons === "string" && settings.toolbarIcons in editormd.toolbarModes) {
|
||||
editormd.toolbarModes[settings.toolbarIcons].push("|");
|
||||
settings.appendToolbar.forEach(toolbar => {
|
||||
// 如果没有 name 字段,则忽略该 toolbar
|
||||
if (!('name' in toolbar)) {
|
||||
return;
|
||||
}
|
||||
|
||||
editormd.toolbarModes[settings.toolbarIcons].push(toolbar.name);
|
||||
if ('icon' in toolbar) {
|
||||
settings.toolbarIconsClass[toolbar.name] = toolbar.icon;
|
||||
}
|
||||
if ('title' in toolbar) {
|
||||
settings.lang.toolbar[toolbar.name] = toolbar.title;
|
||||
}
|
||||
if ('handler' in toolbar) {
|
||||
settings.toolbarHandlers[toolbar.name] = toolbar.handler;
|
||||
if ('shortcut' in toolbar) {
|
||||
// 给新增的工具栏图标绑定快捷键
|
||||
toolbar.shortcut.forEach(key => editormd.keyMaps[key] = toolbar.handler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.shortcutFunction) {
|
||||
for (const key in settings.shortcutFunction) {
|
||||
editormd.keyMaps[key] = settings.shortcutFunction[key];
|
||||
}
|
||||
}
|
||||
|
||||
id = (typeof id === "object") ? settings.id : id;
|
||||
|
||||
var editor = this.editor = $("#" + id);
|
||||
@ -1257,6 +1289,8 @@
|
||||
if (typeof settings.toolbarHandlers[name] !== "undefined")
|
||||
{
|
||||
$.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection);
|
||||
} else {
|
||||
alert("This feature is not yet implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -3822,8 +3856,8 @@
|
||||
|
||||
if (typeof attrs !== "undefined")
|
||||
{
|
||||
// 将 html 标签的 attr value 中存在的 <> 进行转义
|
||||
// 示例 <a name="<p>code</p>"></a> 替换为 <a name="<p>code</p>"></a>
|
||||
// 将 html 标签的 attr value 中可能存在的 <> 尖括号进行转义,避免后面的正则替换发生错误
|
||||
// 示例 <a name="<p>code</p>"></a> 转化为 <a name="<p>code</p>"></a>
|
||||
html = html.replace(/(\w+)="([^"]*)"/g, (match, key, value) => {
|
||||
const escapedValue = value.replace(/</g, '<').replace(/>/g, '>');
|
||||
return `${key}="${escapedValue}"`;
|
||||
|
||||
@ -40,7 +40,7 @@ export default {
|
||||
required: false,
|
||||
default: '720px'
|
||||
},
|
||||
// 默认不开启本地上传
|
||||
// 是否支持图片本地上传
|
||||
imageUpload: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
@ -52,6 +52,12 @@ export default {
|
||||
required: false,
|
||||
default: ''
|
||||
},
|
||||
// 图片上传时携带的 token
|
||||
imageUploadToken: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ''
|
||||
},
|
||||
// 当 image-dialog 插件更新 imageUploadURL 时触发
|
||||
imageUploadURLChange: {
|
||||
type: Function,
|
||||
@ -60,6 +66,18 @@ export default {
|
||||
console.log("new imageUploadURL: " + newURL)
|
||||
}
|
||||
},
|
||||
// 新增工具栏。需要定义 name、icon 和 handler,其他的 title 和 shortcut 可选。
|
||||
appendToolbar: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: [],
|
||||
},
|
||||
// 编辑器内绑定快捷键事件,会覆盖原有快捷键事件
|
||||
shortcutFunction: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {},
|
||||
},
|
||||
// 编辑器加载完成后,执行该函数
|
||||
onload: {
|
||||
type: Function,
|
||||
@ -67,13 +85,13 @@ export default {
|
||||
default: () => { }
|
||||
},
|
||||
// 全屏编辑器时,执行该函数
|
||||
onfullscreen: {
|
||||
onFullScreen: {
|
||||
type: Function,
|
||||
required: false,
|
||||
default: () => { }
|
||||
},
|
||||
// 退出全屏时,执行该函数
|
||||
onfullscreenExit: {
|
||||
onFullScreenExit: {
|
||||
type: Function,
|
||||
required: false,
|
||||
default: () => { }
|
||||
@ -87,16 +105,13 @@ export default {
|
||||
mounted() {
|
||||
if (this.autoInit) {
|
||||
this.initEditor()
|
||||
// 设置延迟初始化 markdown 编辑器。因为只会初始化一次,需要等待数据加载完成之后再初始化
|
||||
// setTimeout(() => {
|
||||
// this.initEditor()
|
||||
// }, 300)
|
||||
}
|
||||
// 设置延迟初始化markdown编辑器,因为只会初始化一次,需要等待数据加载完成之后再初始化
|
||||
// setTimeout(() => {
|
||||
// this.initEditor()
|
||||
// }, 300)
|
||||
},
|
||||
methods: {
|
||||
isEditorLoadingCompleted() {
|
||||
return editorClient != defaultEditorValue && this.loadingCompleted
|
||||
},
|
||||
fetchScript(url) {
|
||||
return new Promise((resolve) => {
|
||||
scriptjs(url, () => {
|
||||
@ -106,7 +121,7 @@ export default {
|
||||
},
|
||||
initEditor() {
|
||||
(async () => {
|
||||
await this.fetchScript('/static/jQuery/jquery.min.js')
|
||||
await this.fetchScript('/static/jquery/jquery.min.js')
|
||||
await this.fetchScript('/static/editor.md/editormd.js')
|
||||
// await this.fetchScript('/static/editor.md/editorrmd.amd.js')
|
||||
// 加载完成以上 JS 资源之后,再加载编辑器
|
||||
@ -132,27 +147,31 @@ export default {
|
||||
taskList: true,
|
||||
|
||||
// 定义图片本地上传的功能
|
||||
imageUpload: vm.imageUpload, // 支持图片本地上传。若不提供 imageUploadURL 则需要用户自行设定
|
||||
imageUpload: vm.imageUpload, // 是否支持图片本地上传。若不提供 imageUploadURL 则需要用户自行设定
|
||||
imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "ico"],
|
||||
imageUploadURL: vm.imageUploadURL, // 可用于上传图片的服务端接口
|
||||
imageUploadURLChange: function (newURL) {
|
||||
// 当 image-dialog 插件更新 imageUploadURL 时触发
|
||||
vm.imageUploadURLChange(newURL)
|
||||
},
|
||||
imageUploadToken: vm.imageUploadToken,
|
||||
imageUploadURLChange: vm.imageUploadURLChange,
|
||||
|
||||
// 可分区域定制样式主题
|
||||
// theme: (localStorage.theme) ? localStorage.theme : "dark",
|
||||
// editorTheme: (localStorage.editorTheme) ? localStorage.editorThheme : "3024-night",
|
||||
// previewTheme: (localStorage.previewTheme) ? localStorage.previewTheme : "default",
|
||||
|
||||
// 给工具栏补充工具事件
|
||||
appendToolbar: vm.appendToolbar,
|
||||
|
||||
// 绑定快捷键。如果冲突,会覆盖其他相同快捷键事件
|
||||
shortcutFunction: vm.shortcutFunction,
|
||||
|
||||
// 全屏
|
||||
onfullscreen: function () {
|
||||
vm.onfullscreen()
|
||||
vm.onFullScreen()
|
||||
},
|
||||
|
||||
// 退出全屏
|
||||
onfullscreenExit: function () {
|
||||
vm.onfullscreenExit()
|
||||
vm.onFullScreenExit()
|
||||
},
|
||||
|
||||
// 监听更新,更新父组件值
|
||||
@ -181,6 +200,9 @@ export default {
|
||||
})
|
||||
})()
|
||||
},
|
||||
isEditorLoadingCompleted() {
|
||||
return editorClient != defaultEditorValue && this.loadingCompleted
|
||||
},
|
||||
|
||||
// 以下是 editor.md 对外暴露的 API
|
||||
resetHeight(height) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user