<template>
	<view class="fui-parse__wrap">
		<block v-for="(item,index) in nodesData" :key="index">
			<!-- 判断是否为标签节点 -->
			<block v-if="item.node == 'element'">
				<!-- button类型 -->
				<block v-if="item.tag == 'button'">
					<button type="default" size="mini">
						<!-- 如果还有子节点，递归遍历自身 -->
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse :nodes="child"></fui-parse>
						</block>
					</button>
				</block>

				<!-- code类型 -->
				<block v-else-if="item && item.tag == 'code'">
					<view class="mb10" :class="item.classStr" :style="item.styleStr">
						<firstui-code :codeText="item.content" :language="item.attr && item.attr.lang"></firstui-code>
					</view>
				</block>

				<!-- ol类型 -->
				<block v-else-if="item.tag == 'ol'">
					<view class="fuiParse-ol" :class="[item.classStr]" :style="item.styleStr">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<view class="fuiParse-ol-inner">
								<view class="fuiParse-ol-number">{{idx + 1}}. </view>
								<view class="flex-full overflow-hide">
									<fui-parse :nodes="child"></fui-parse>
								</view>
							</view>
						</block>
					</view>
				</block>

				<!-- ul类型 -->
				<block v-else-if="item.tag == 'ul'">
					<view class="fuiParse-ul" :class="[item.classStr]" :style="item.style && item.style.Str">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<view class="fuiParse-ul-inner">
								<view class="fuiParse-li-circle"></view>
								<view class="flex-full overflow-hide">
									<fui-parse :nodes="child"></fui-parse>
								</view>
							</view>
						</block>
					</view>
				</block>

				<!-- li类型 -->
				<block v-else-if="item.tag == 'li'">
					<view class="fuiParse-li" :class="[item.classStr]" :style="item.styleStr">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse :nodes="child"></fui-parse>
						</block>
					</view>
				</block>

				<!-- video类型 -->
				<block v-else-if="item.tag == 'video'">
					<!--增加video标签支持，并循环添加-->
					<view :class="[item.classStr,`fuiParse-${item.tag}`]" :style="item.styleStr">
						<video :class="[item.classStr,`fuiParse-${item.tag}-video`]"
							:src="item.attr && item.attr.src"></video>
					</view>
				</block>

				<!-- img类型 -->
				<block v-else-if="item.tag == 'img'">
					<view class="fuiParse-img-inner" v-if="item.attr && item.attr.src">
						<image :class="[item.classStr,`fuiParse-${item.tag}`,item.loaded ? 'fuiParse-img-fadein' : '']"
							:data-from="item.from" :data-src="item.attr.src" :data-idx="item.imgIndex" :lazy-load="true"
							:src="item.loaded ? item.attr.src : ''" @tap="fuiParseImgTap" :mode="mode"
							:style="'width:'+(item.attr.width || width)+'px;height:'+(item.attr.height || height)+'px;'+item.styleStr" />
						<image class="fuiParse-img__loading" :class="{'fuiParse-img__hidden':item.loaded}"
							src="data:image/png;base64, " />
						<image style="display: none;" :mode="mode" :data-from="item.from" :data-index="index"
							:src="item.attr.src" @load="fuiParseImgLoad" />
					</view>
				</block>

				<!-- a类型 -->
				<block v-else-if="item.tag == 'a'">
					<view @tap="fuiParseTagATap" :class="[item.classStr,`fuiParse-${item.tag}`]" class="fuiParse-inline"
						:data-title="item.attr && item.attr.title" :data-src="item.attr && item.attr.href"
						:style="item.styleStr">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse :nodes="child"></fui-parse>
						</block>
					</view>
				</block>

				<!-- table类型 -->
				<block v-else-if="item.tag == 'table'">
					<view :class="[item.classStr,`fuiParse-${item.tag}`]">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse :nodes="child"></fui-parse>
						</block>
					</view>
				</block>

				<!-- tr 类型 -->
				<block v-else-if="item.tag == 'tr'">
					<view :class="[item.classStr,`fuiParse-${item.tag}`]">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse
								:class="[child.classStr,`fuiParse-${child.tag}`,`fuiParse-${child.tag}-container`,child.tag=='th' && thBgcolor?'fuiParse-th__bg':'']"
								:style="child.styleStr" :nodes="child"></fui-parse>
						</block>
					</view>
				</block>

				<!-- td 类型 -->
				<block v-else-if="item.tag == 'td'">
					<view :class="[item.classStr,`fuiParse-${item.tag}`]">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse
								:class="[child.classStr,`fuiParse-${child.tag}`,`fuiParse-${child.tag}-container`]"
								:style="child.styleStr" :nodes="child"></fui-parse>
						</block>
					</view>
				</block>

				<!-- audio类型 -->
				<block v-else-if="item.tag == 'audio'">
					<view class="fuiParse-audio">
						<firstui-audio class="fuiParse-audio-inner" :src="item.attr && item.attr.src"
							:title="item.attr && item.attr.title" :desc="item.attr && item.attr.desc"
							:class="[item.classStr]" :style="item.styleStr"></firstui-audio>
					</view>
				</block>

				<!-- br类型 -->
				<block v-else-if="item.tag == 'br'">
					<text>\n</text>
				</block>

				<!-- 其它块级标签 -->
				<block v-else-if="item.tagType == 'block'">
					<view :class="[item.classStr,`fuiParse-${item.tag}`]" :style="item.styleStr">
						<block v-for="(child,idx) in item.nodes" :key="idx">
							<fui-parse :nodes="child"></fui-parse>
						</block>
					</view>
				</block>

				<!-- 其它内联标签 -->
				<view v-else :class="[item.classStr,`fuiParse-${item.tag}`,`fuiParse-${item.tagType}`]"
					:style="item.styleStr">
					<block v-for="(child,idx) in item.nodes" :key="idx">
						<fui-parse :nodes="child"></fui-parse>
					</block>
				</view>
			</block>

			<!-- 判断是否为文本节点 -->
			<block v-else-if="item.node == 'text'">
				<view class="fuiEmojiView fuiParse-inline" :style="item.styleStr">
					<block v-for="(textItem,idx) in item.textArray" :key="idx">
						<block :class="[textItem.text == '\\n' ? 'fuiParse-hide':'']" v-if="textItem.node == 'text'">
							<text :selectable="true">{{textItem.text}}</text>
						</block>
						<block v-else-if="textItem.node == 'element'">
							<image class="fuiEmoji" :src="textItem.baseSrc+textItem.text" />
						</block>
					</block>
				</view>
			</block>
		</block>
	</view>
</template>

<script>
	import firstuiAudio from './firstui-audio.vue'
	import HtmlToJson from './utils/html2json.js';
	import util from './utils/util.js';
	const BIND_NAME = 'fuiParse'
	export default {
		name: "fui-parse",
		inject: {
			parsegroup: {
				value: "parsegroup",
				default: null
			}
		},
		components: {
			firstuiAudio
		},
		props: {
			// 可选：html | markdown (md)
			language: {
				type: String,
				default: 'html'
			},
			nodes: {
				type: [String, Object, Array],
				default: ''
			}
		},
		watch: {
			nodes: {
				handler(val) {
					if (!val) return;
					// 采用markdown解析
					if (this.language === 'markdown' || this.language === 'md') {
						// const parseNodes = marked(val);
						// setTimeout(() => {
						// 	this._parseNodes(parseNodes)
						// }, 0);
					} else {
						// 默认采用html解析
						setTimeout(() => {
							this._parseNodes(val)
						}, 0)
					}
				},
				immediate: true
			}
		},
		// #ifndef VUE3
		beforeDestroy() {
			// 组件销毁，清除绑定实例
			util.cacheInstance.remove(this.pageNodeKey)
		},
		// #endif
		// #ifdef VUE3
		beforeUnmount() {
			// 组件销毁，清除绑定实例
			util.cacheInstance.remove(this.pageNodeKey)
		},
		// #endif
		data() {
			return {
				pageNodeKey: '',
				nodesData: [],
				bindData: {},
				width: 0,
				height: 0,
				thBgcolor: true,
				mode: ''
			};
		},
		created() {
			this.$nextTick(() => {
				setTimeout(() => {
					if (this.parsegroup) {
						this.thBgcolor = this.parsegroup.thBgcolor
					}
					this.mode = 'widthFix'
				}, 50)
			})
		},
		methods: {
			_parseNodes(nodes) {
				// 设置页面唯一键值标识符
				this.pageNodeKey = this.parsegroup ? this.parsegroup.pageNodeKey : BIND_NAME;
				if (typeof nodes === 'string') { // 初始为html富文本字符串
					this._parseHtml(nodes)
				} else if (Array.isArray(nodes)) { // html 富文本解析成节点数组
					this.nodesData = nodes;
				} else { // 其余为单个节点对象
					this.nodesData = [nodes];
				}
			},

			_parseHtml(html) {
				//存放html节点转化后的json数据
				const transData = HtmlToJson.html2json(html, this.pageNodeKey)
				transData.view = {}
				transData.view.imagePadding = 0
				this.nodesData = transData.nodes;
				this.bindData = {
					[this.pageNodeKey]: transData
				}
				util.cacheInstance.set(this.pageNodeKey, transData)
			},

			/**
			 * 图片视觉宽高计算函数区
			 * @param {*} e
			 */
			fuiParseImgLoad(e) {
				// 获取当前的image node节点
				const {
					from: tagFrom,
					index
				} = (e.target.dataset || e.currentTarget.dataset || {})
				if (typeof tagFrom !== 'undefined' && tagFrom.length > 0) {
					const {
						width,
						height
					} = e.detail

					//因为无法获取view宽度 需要自定义padding进行计算，稍后处理
					const recal = this._fuiAutoImageCal(width, height)
					this.width = recal.imageWidth;
					this.height = recal.imageHeight;
					const nodesData = this.nodesData;
					nodesData[index].loaded = true;
					this.nodesData = nodesData;
				}
			},

			/**
			 * 预览图片
			 * @param {*} e
			 */
			fuiParseImgTap(e) {
				const {
					src
				} = (e.target.dataset || e.currentTarget.dataset)

				let {
					imageUrls = []
				} = util.cacheInstance.get(this.pageNodeKey)
				if (imageUrls.length == 0) {
					imageUrls = [src]
				}

				if (this.parsegroup) {
					if (this.parsegroup.imgPreview) {
						uni.previewImage({
							current: src,
							urls: imageUrls
						})
					}
					this.parsegroup.previewImage(src, imageUrls)
				} else {
					uni.previewImage({
						current: src,
						urls: imageUrls
					})
				}
			},

			/**
			 * 计算视觉优先的图片宽高
			 * @param {*} originalWidth
			 * @param {*} originalHeight
			 */
			_fuiAutoImageCal(originalWidth, originalHeight) {
				let autoWidth = 0,
					autoHeight = 0;
				const results = {}
				const [windowWidth, windowHeight] = util.getSystemInfo()

				// 判断按照哪种方式进行缩放
				if (originalWidth > windowWidth) { //在图片width大于手机屏幕width时候
					autoWidth = windowWidth
					autoHeight = (autoWidth * originalHeight) / originalWidth
					results.imageWidth = autoWidth
					results.imageHeight = autoHeight
				} else { // 否则展示原来数据
					results.imageWidth = originalWidth
					results.imageHeight = originalHeight
				}
				return results
			},

			/**
			 * 增加a标签跳转
			 * @param {*} e
			 */
			fuiParseTagATap(e) {
				const {
					src = ''
				} = e.currentTarget.dataset

				if (this.parsegroup) {
					this.parsegroup.onATap(src)
					return
				}
				// 判断是否内部链接跳转
				const isInnerPage = src.indexOf('http') === -1
				if (isInnerPage) {
					uni.navigateTo({
						url: src
					})
				}
			}
		}
	}
</script>

<style scoped>
	.fui-parse__wrap {
		display: inline;
		max-width: 100%;
		font-weight: normal;
	}

	.fuiParse {
		margin: 0 5px;
		font-family: Helvetica, sans-serif;
		font-size: 28rpx;
		color: #666;
		line-height: 1.8;
	}

	.fuiParse-inline {
		display: inline;
		margin: 0;
		padding: 0;
		line-height: 1.75;
	}

	.mb10 {
		margin-bottom: 0.63em;
	}

	/*//标题 */
	.fuiParse-div {
		/* margin: 0; */
		padding: 0;
	}

	.fuiParse-h1 {
		font-size: 2em;
		margin: .67em 0
	}

	.fuiParse-h2 {
		font-size: 1.5em;
		margin: .75em 0
	}

	.fuiParse-h3 {
		font-size: 1.17em;
		margin: .83em 0
	}

	.fuiParse-h4 {
		margin: 1.12em 0
	}

	.fuiParse-h5 {
		font-size: .83em;
		margin: 1.5em 0
	}

	.fuiParse-h6 {
		font-size: .75em;
		margin: 1.67em 0
	}

	.fuiParse-h1 {
		font-size: 18px;
		font-weight: 500;
		margin-bottom: .9em;
	}

	.fuiParse-h2 {
		font-size: 16px;
		font-weight: 500;
		margin-bottom: .34em;
	}

	.fuiParse-h3 {
		font-weight: 500;
		font-size: 15px;
		margin-bottom: .34em;
	}

	.fuiParse-h4 {
		font-weight: 500;
		font-size: 14px;
		margin-bottom: .24em;
	}

	.fuiParse-h5 {
		font-weight: 500;
		font-size: 13px;
		margin-bottom: .14em;
	}

	.fuiParse-h6 {
		font-weight: 500;
		font-size: 12px;
		margin-bottom: .04em;
	}

	.fuiParse-h1,
	.fuiParse-h1 text,
	.fuiParse-h2,
	.fuiParse-h2 text,
	.fuiParse-h3,
	.fuiParse-h3 text,
	.fuiParse-h4,
	.fuiParse-h4 text,
	.fuiParse-h5,
	.fuiParse-h5 text,
	.fuiParse-h6,
	.fuiParse-h6 text,
	.fuiParse-b,
	.fuiParse-b text,
	.fuiParse-strong,
	.fuiParse-strong text {
		font-weight: bold;
	}

	.fuiParse-i,
	.fuiParse-i text,
	.fuiParse-cite,
	.fuiParse-em,
	.fuiParse-em text,
	.fuiParse-var,
	.fuiParse-address,
	.fuiParse-address text {
		font-style: italic
	}

	.fuiParse-pre,
	.fuiParse-tt,
	.fuiParse-code,
	.fuiParse-kbd,
	.fuiParse-samp {
		font-family: monospace
	}

	.fuiParse-pre {
		white-space: pre;
		overflow-x: scroll;
		background: #f5f5f5;

	}

	.fuiParse-p {
		max-width: 100%;
		word-break: break-all;
		white-space: pre-wrap;
		box-sizing: border-box;
	}

	.fuiParse-section {
		max-width: 100%;
		overflow: hidden;
		white-space: pre-wrap;
		box-sizing: border-box;
	}

	.fuiParse-big {
		font-size: 1.17em
	}

	.fuiParse-small,
	.fuiParse-sub,
	.fuiParse-sup {
		font-size: .83em
	}

	.fuiParse-sub {
		vertical-align: sub
	}

	.fuiParse-sup {
		vertical-align: super
	}

	.fuiParse-s,
	.fuiParse-strike,
	.fuiParse-del {
		text-decoration: line-through
	}

	/*fuiParse-自定义个性化的css样式*/
	/*增加video的css样式*/
	.fuiParse-strong,
	.fuiParse-s {
		display: inline
	}

	.fuiParse-a {
		word-break: break-all;
		overflow: auto;
		color: var(--fui-color-link, #465CFF);

	}

	/* #ifdef H5 */
	.fuiParse-a text {
		cursor: pointer;
	}

	/* #endif */

	.fuiParse-video {
		max-width: 100% !important;
		text-align: center;
		margin: 10px 0;
	}

	.fuiParse-video-video {
		width: 100%;
	}

	.fuiParse-blockquote {
		padding: 10px 0 10px 5px;
		font-family: Courier, Calibri, "宋体";
		background: #f5f5f5;
		border-left: 3px solid #dbdbdb;
	}

	.fuiParse-code,
	.fuiParse-code-style {
		background: #f5f5f5;
		line-height: 1.75;
	}

	.fuiParse-li,
	.fuiParse-li-inner {
		align-items: baseline;
		margin: 10rpx 0;
	}

	.fuiParse-li-text {
		flex-direction: row;
		align-items: center;
		line-height: 20px;
	}

	.fuiParse-li-circle,
	.fuiParse-ol-number {
		margin: 10rpx 10rpx 10rpx 0;
	}

	.fuiParse-li-circle {
		display: inline-flex;
		width: 5px;
		height: 5px;
		margin-top: 34rpx !important;
		background-color: #333;
		border-radius: 50%;
	}

	.fuiParse-li-square {
		display: inline-flex;
		width: 10rpx;
		height: 10rpx;
		background-color: #333;
		margin-right: 5px;
	}

	.fuiParse-li-ring {
		display: inline-flex;
		width: 10rpx;
		height: 10rpx;
		border: 2rpx solid #333;
		border-radius: 50%;
		background-color: #fff;
		margin-right: 5px;
	}

	.fuiParse-u {
		text-decoration: underline;
	}

	.fuiParse-hide {
		display: none;
	}

	.fuiEmojiView {
		align-items: center;
	}

	.fuiEmoji {
		width: 16px;
		height: 16px;
	}

	.fuiParse-table {
		border-bottom: 1px solid #e0e0e0;
		font-size: 0;
		overflow-x: scroll;
	}

	.fuiParse-tr {
		display: flex;
		flex-direction: row;
		border-right: 1px solid #e0e0e0;
	}

	.fuiParse-th,
	.fuiParse-td {
		flex: 1;
		padding: 5px;
		font-size: 28rpx;
		word-break: break-all;
		text-align: center;
	}

	.fuiParse-th image,
	.fuiParse-td image,
	.fuiParse-td .fuiParse-img {
		width: 100% !important;
	}

	.fuiParse-th-container,
	.fuiParse-td-container {
		border-left: 1px solid #e0e0e0;
		border-top: 1px solid #e0e0e0
	}

	.fuiParse-td:last {
		border-top: 1px solid #e0e0e0;
	}

	.fuiParse-th__bg {
		background: #f0f0f0;
	}

	.fuiParse-del {
		/* #ifndef APP-NVUE */
		display: inline;
		/* #endif */
	}

	.fuiParse-figure {
		overflow: hidden;
	}

	.fuiParse-ol-inner,
	.fuiParse-ul-inner {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		align-items: flex-start;
		flex-direction: row;
		line-height: 28px;
	}

	.fuiParse-img-inner {
		position: relative;
		min-height: 100rpx;
	}

	.fuiParse-img {
		background-color: #efefef;
		overflow: hidden;
		max-width: 100%;
		width: 100%;
		display: block;
	}

	/* #ifndef APP-NVUE */
	.fuiParse-img-fadein {
		animation: fade-in 1s linear;
	}

	/* #endif */

	.fuiParse-img-inner .fuiParse-img__loading {
		display: block;
		position: absolute;
		top: 50%;
		left: 50%;
		margin-top: -30rpx;
		margin-left: -30rpx;
		/* #ifndef APP-NVUE */
		animation: loading 1s linear 0s infinite;
		/* #endif */
		width: 60rpx !important;
		height: 60rpx !important;
	}

	/* audio */
	.fuiParse-audio-inner {
		width: 100%;
		height: 200rpx;
	}

	/* common */
	.mr5 {
		margin-right: 5px;
	}

	.flex-full {
		flex: 1;
	}

	.overflow-hide {
		overflow: hidden;
	}

	/* #ifndef APP-NVUE */
	@keyframes loading {
		0% {
			transform: rotate(0deg);
		}

		100% {
			transform: rotate(360deg);
		}
	}

	@keyframes fade-in {
		0% {
			opacity: 0;
		}

		100% {
			opacity: 1;
		}
	}

	/* #endif */

	.fuiParse-img__hidden {
		opacity: 0;
		visibility: hidden;
		pointer-events: none;
	}
</style>
