<template>
	<div id="tinymce" class="tinymce-box">
		<textarea :id="tinymceId" :ref="tinymceId" :value="value"></textarea>
		<slot></slot>
	</div>
</template>

<script>
/* eslint-disable no-unused-vars */
import tinymce from "pyy-editor";
import { editorCrawlerIgnore } from "@/config/editor";
export default {
	name: "BaseEditor",
	props: {
		// 编辑器内容绑定值
		modelValue: {
			type: String,
			default: "",
		},
		// 编辑器根路径
		baseUrl: {
			type: String,
			default: window.location.origin + "/" + process.env.VUE_APP_PREFIX + "/tinymce",
		},
		// 编辑器初始化完成前执行的操作
		setup: {
			type: Function,
			default: (editor) => {},
		},
		// 配置处理类实例
		configHandler: {
			type: Object,
			default: () => {
				return {};
			},
		},
		// 上传处理类实例
		uploadHandler: {
			type: Object,
			default: () => {
				return {};
			},
		},
		// 业务参数
		additionalParams: {
			type: Object,
			default: () => {
				return {};
			},
		},
		// url 白名单
		whiteList: {
			type: Array,
			default: () => editorCrawlerIgnore,
		},
		// 富文本编辑器高度
		height: {
			type: Number,
			default: 700,
		},
		// 自定义配置项, 该配置中配置编辑器高度优先级低于 prop: height
		customConfig: {
			type: Object,
			default: () => {
				return {};
			},
		},
	},
	emits: ["onchange", "fileUploadError", "progress"],
	data() {
		return {
			tinymceId: "tinymce" + new Date().getTime() + Math.floor(Math.random() * 899 + 100),
			// value: "",
			finishStatus: true,
			downFile: [],
			editor: null,
			isEdit: false,
			bookmark: null,
			imageCrawler: {},
		};
	},
	computed: {
		value: {
			get() {
				if (this.editor && !this.isEdit) this.setContent(this.content, this.editor);
				return this.modelValue;
			},
			set(val) {
				if (val !== this.value) {
					this.$emit("update:modelValue", val);
					const text = this.getContentText();
					this.$emit("onchange", val, text);
				}
			},
		},
	},
	created() {},
	mounted() {
		tinymce.baseURL = this.baseUrl;
		this.initTinymce();
		window.addEventListener("focusout", this.onIntercept, true);
	},
	beforeUnmount() {
		this.destroyTinymceEditor();
		this.editor = null;
		window.removeEventListener("focusout", this.onIntercept);
	},
	methods: {
		// 阻止点击目标输入框之外的其他聚焦事件
		onIntercept(e) {
			e.stopImmediatePropagation();
		},
		// 富文本内容保存处理
		htmlSaveHandle(val) {
			let html = "";
			if (val) {
				html = val + "";
			} else {
				html = this.value + "";
			}
			if (this.downFile.length > 0) {
				this.downFile.forEach((item) => {
					html = html.replace(
						new RegExp('href="' + item.url + '" target', "g"),
						'href="' + item.url + '" download="' + item.name + '" target'
					);
				});
			}
			let imgList = this.getContentSrc();
			if (Object.values(this.imageCrawler).filter((item) => item !== 0).length === imgList.length) {
				imgList.forEach((oldUrl) => {
					if (this.imageCrawler[oldUrl]) {
						html = html.replaceAll(oldUrl, this.imageCrawler[oldUrl]);
					}
				});
			}
			return html;
		},
		//获取node的属性
		getAttrFromString(str, node, attr) {
      let regex = new RegExp("<" + node + ".*?" + attr + '="(.*?)"', "gi"),
				result,
				res = [];
			while ((result = regex.exec(str))) {
				res.push(result[1]);
			}
			return res;
		},

		// 编辑器初始化操作
		initTinymce() {
			const functionConfig = this.configHandler.functionConfig;
			for (const key in functionConfig) {
				if (!functionConfig[key].custom) {
					this.configHandler[key](this[key]);
				} else if (functionConfig[key].custom && functionConfig[key].hasAdditionalParams) {
					this.configHandler[key](this.additionalParams);
				} else {
					this.configHandler[key]();
				}
			}

			// console.log('tinymceId', this.tinymceId)
			const tinymceInit = Object.assign(
				{},
				this.configHandler.config,
				{
					selector: `#${this.tinymceId}`,
					setup: (editor) => {
						this.editor = editor;
						this.setup(editor);
						editor.on("init", () => {
							editor.on("Blur", (e) => {
								this.isEdit = false;
							});
							editor.on("keyup input", (e) => {
								console.log(e);
								this.isEdit = true;
							});
							editor.on("input keyup Change Undo Redo ExecCommand NodeChange", (e) => {
								this.onChanged(e, editor);
							});
						});
					},
				},
				{ ...this.customConfig },
				{ height: this.height }
			);
			// console.log("tinymceInit", tinymceInit);
			tinymce.init(tinymceInit);
		},
		setContent(val, editor) {
			if (!editor) editor = this.editor;
			editor.setContent(val);
      if (this.bookmark) editor.selection.moveToBookmark(this.bookmark);
		},
		onChanged(e, editor) {
			if (!editor) editor = this.editor;
			if (e.type === "change") this.bookmark = e.level.bookmark;
			this.value = editor.getContent();
		},
		destroyTinymceEditor() {
			// console.log("tinymce destroy");
			let tinymceInstance = window.tinymce.get(this.tinymceId);
			if (tinymceInstance) {
				tinymceInstance.destroy();
			}
		},

		//获取内容中的文字
		getContentText() {
			return this.editor.getContent({ format: "text" });
		},

		//获取内容中的HTML
		getContent() {
			return this.editor.getContent();
		},

		//获取内容中的图片src
		getContentSrc() {
			let contentHtml = this.editor.getContent();
			let images = this.getAttrFromString(contentHtml, "img", "src");
			return images;
		},

		//获取node中的attr
		getContentAttrByNode(node, nodeAttr) {
			let contentHtml = this.editor.getContent();
			let res = this.getAttrFromString(contentHtml, node, nodeAttr);
			return res;
		},

		/** 图片地址替换完成状态 */
		getStatus(val) {
			let that = this;
			// 获取富文本框所有src
			let images = this.getAttrFromString(val, "img", "src");
			images = Array.from(new Set(images));

			// console.log("getStatus-images", images);
			//没有图片，完成状态为true
			if (images.length === 0) {
				return;
			}
			if (!that.whiteList.length) {
				console.warn("白名单为空!");
				return;
			}
			//遍历所有src是否在白名单中，
			images = images.filter(function (url) {
				// console.log("getStatus-url", url);

				for (const item of that.whiteList) {
					if (url.indexOf(item) > -1) return false;
				}
				return true;
			});
			this.finishStatus = images.length === 0;
			// console.log("list-imagse-status", images, this.finishStatus);
		},

		assignUrl(url) {
			const urlLimit = this.whiteList;
			if (!this.whiteList.length) {
				console.warn("白名单为空!");
				return true;
			}
			try {
				for (const item of urlLimit) {
					if (url.indexOf(item) > -1) {
						return true;
					}
				}
			} catch (e) {
				return false;
			}
			return false;
		},
		/* 编辑器默认方法-Start */
		// 文件上传回调
		file_picker_callback(callback, value, meta) {
			// console.log('file_picker_callback');
			//  上传文件
			let input = document.createElement("input");
			input.setAttribute("type", "file");
			let filetype =
				this.uploadHandler.config.fileSupportType ||
				".png,.jpg,.jpeg,.gif,.flv,.swf,.mkv,.avi,.rm,.rmvb,.mpeg,.mpg,.ogg,.ogv,.mov,.wmv,.mp4,.webm,.mp3,.wav,.mid,.bmp,.rar,.zip,.tar,.gz,.7z,.bz2,.cab,.iso,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.md,.xml,.csv";
			let fileTypeText = "文件";
			//文件分类
			switch (meta.filetype) {
				case "image":
					filetype = this.uploadHandler.config.imageSupportType;
					fileTypeText = "图片类型";
					break;
				case "media":
					filetype = this.uploadHandler.config.mediaSupportType;
					fileTypeText = "视频类型";
					break;
				case "file":
					filetype = this.uploadHandler.config.fileSupportType;
					fileTypeText = "格式正确";
					break;
				default:
					break;
			}
			input.setAttribute("accept", filetype); //如果不想过滤文件上传的后缀，可以禁用
			let that = this;
			input.onchange = function (e) {
				let file = this.files[0];
				// console.log('file', file,filetype);
				//格式验证
				if (!that.uploadHandler.fileLimit(file, filetype)) {
					that.editor.windowManager.alert("请上传" + fileTypeText + "的文件!");
					that.$emit("fileUploadError", "请上传" + fileTypeText + "的文件!");
					return false;
				}

				that.uploadHandler.upload(
					file,
					that.additionalParams,
					(data) => {
						callback(data.url, { title: data.name, text: file.name });
					},
					(err) => {
						throw Error("file_picker_callback-err" + err);
					},
					(progress) => {
						// console.log('file_picker_callback-progress', progress);
						that.$emit("progress", progress);
					}
				);
			};
			input.click();
		},
		// 自定义图片上传函数代替TinyMCE默认逻辑
		images_upload_handler(blobInfo, success, failure, progress) {
			// console.log('images_upload_handler');
			const filename = (blobInfo.file && blobInfo.file.name) || blobInfo.filename();
			if (!this.uploadHandler.fileLimit(blobInfo.blob(), this.uploadHandler.config.imageSupportType)) {
				this.$emit("fileUploadError", "请上传图片类型的文件!");
				failure(filename + "不是图片类型的文件!");
				return false;
			}
			if (this.uploadHandler.fileSizeJudgment(blobInfo.blob().size)) {
				failure(filename + "图片太大, 请上传5M以内的图片");
				return false;
			}

			this.uploadHandler.upload(
				blobInfo.blob(),
				this.additionalParams,
				(data) => {
					success(data.url);
				},
				(err) => {
					failure(err);
					throw Error("images_upload_handler-err: " + err);
				},
				(progress) => {
					// console.log('images_upload_handler-progress', progress);
					this.$emit("progress", progress);
				}
			);
		},
		// 自定义的URL转换逻辑处理文档中的URL
		urlconverter_callback(url, node, on_save, name) {
			// console.log("urlconverter_callback", url, node, on_save, name, typeof url);
			if (node) {
				if (node === "img" || JSON.stringify(node).indexOf("<img") !== -1) {
					// 未进行过替换的图片地址进行替换
					if (
						!Object.keys(this.imageCrawler).includes(url) &&
						!Object.values(this.imageCrawler).includes(url) &&
						!this.assignUrl(url)
					) {
						this.imageCrawler[url] = 0;
						let additionalParams = { ...this.additionalParams };
						setTimeout(() => {
							this.uploadHandler.uploadRemotePic(
								url,
								additionalParams,
								(data) => {
									this.imageCrawler[url] = data.url;
								},
								(err) => {
									throw Error("urlconverter_callback-err" + err);
								}
							);
						}, 200);
					}
				}
			}
			return url;
		},
		// upfile 插件文件上传回调
		file_callback(file, successFunc) {
			// console.log('file_callback')
			//格式验证
			if (!this.uploadHandler.fileLimit(file)) {
				this.editor.windowManager.alert("请上传格式正确的文件!");
				this.$emit("fileUploadError", "文件格式验证不通过");
				return false;
			}

			this.uploadHandler.upload(
				file,
				this.additionalParams,
				(data) => {
					this.downFile.push({ url: data.url, name: file.name });
					successFunc(data.url, { title: data.name, text: file.name });
				},
				(err) => {
					throw Error("file_callback-err" + err);
				},
				(progress) => {
					// console.log('file_callback-progress', progress);
					this.$emit("progress", progress);
				}
			);
		},
		// 自定义media的Url处理逻辑并将生成的html代码发送到编辑内容区
		media_url_resolver(data, resolve) {
			// console.log('media_url_resolver',data)
			let videoUrl = encodeURI(data.url);
			if (data.url.indexOf(videoUrl) !== -1) {
				let embedHtml = `<p style="text-align: center">
    <video src=${data.url} width="100%" height="auto"  ${
					data.poster ? "poster=" + data.poster : ""
				} controls="controls" controlslist="nodownload"></video>
</p>
<p style="text-align:left;"></p>`;
				resolve({ html: embedHtml });
			} else {
				resolve({ html: "" });
			}
		},
		/* 编辑器默认方法-End */
	},
};
</script>

<style lang="scss" scoped>
.tinymce-box {
	width: 100%;
	display: block;
	min-width: 500px;
	min-height: 400px;
}
</style>
