tiyan
This commit is contained in:
parent
3cab778234
commit
996a18043a
|
@ -45,6 +45,9 @@
|
||||||
icon="el-icon-refresh-left"
|
icon="el-icon-refresh-left"
|
||||||
@click="resetFilter"
|
@click="resetFilter"
|
||||||
>刷新重置</el-button>
|
>刷新重置</el-button>
|
||||||
|
<el-checkbox v-model="showCreate" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">
|
||||||
|
创建时间
|
||||||
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top:10px">
|
<div style="margin-top:10px">
|
||||||
<el-button type="primary" @click="handleAddUser" icon="el-icon-plus">新增</el-button>
|
<el-button type="primary" @click="handleAddUser" icon="el-icon-plus">新增</el-button>
|
||||||
|
@ -115,7 +118,7 @@
|
||||||
<el-tag v-if="scope.row.workscope_name">{{ scope.row.workscope_name }}</el-tag>
|
<el-tag v-if="scope.row.workscope_name">{{ scope.row.workscope_name }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="创建日期" sortable='custom' prop="create_time">
|
<el-table-column label="创建日期" sortable='custom' prop="create_time" v-if="showCreate">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ scope.row.create_time }}</span>
|
<span>{{ scope.row.create_time }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -246,6 +249,8 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
tableKey: 0,
|
||||||
|
showCreate: false,
|
||||||
uploadUrl: uploadUrl(),
|
uploadUrl: uploadUrl(),
|
||||||
popovervisible: false,
|
popovervisible: false,
|
||||||
consumer: defaultConsumer,
|
consumer: defaultConsumer,
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default {
|
||||||
{ required: true, message: "请输入", trigger: "blur" }
|
{ required: true, message: "请输入", trigger: "blur" }
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
is_show: false
|
is_show: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
audio 扩展包
|
||||||
|
github:https://github.com/jin-yufeng/Parser
|
||||||
|
docs:https://jin-yufeng.github.io/Parser
|
||||||
|
author:JinYufeng
|
||||||
|
*/
|
||||||
|
Component({
|
||||||
|
data: {
|
||||||
|
time: '00:00'
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
author: String,
|
||||||
|
autoplay: Boolean,
|
||||||
|
controls: Boolean,
|
||||||
|
loop: Boolean,
|
||||||
|
name: String,
|
||||||
|
poster: String,
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
observer(src) {
|
||||||
|
this.setSrc(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this._ctx = wx.createInnerAudioContext();
|
||||||
|
this._ctx.onError((err) => {
|
||||||
|
this.setData({
|
||||||
|
error: true
|
||||||
|
})
|
||||||
|
this.triggerEvent('error', err);
|
||||||
|
})
|
||||||
|
this._ctx.onTimeUpdate(() => {
|
||||||
|
var time = this._ctx.currentTime,
|
||||||
|
min = parseInt(time / 60),
|
||||||
|
sec = Math.ceil(time % 60),
|
||||||
|
data = {};
|
||||||
|
data.time = (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec);
|
||||||
|
if (!this.lastTime) data.value = time / this._ctx.duration * 100; // 不在拖动状态下
|
||||||
|
this.setData(data);
|
||||||
|
})
|
||||||
|
this._ctx.onEnded(() => {
|
||||||
|
this.setData({
|
||||||
|
playing: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
detached() {
|
||||||
|
this._ctx.destroy();
|
||||||
|
},
|
||||||
|
pageLifetimes: {
|
||||||
|
show() {
|
||||||
|
if (this.data.playing && this._ctx.paused)
|
||||||
|
this._ctx.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 设置源
|
||||||
|
setSrc(src) {
|
||||||
|
this._ctx.autoplay = this.data.autoplay;
|
||||||
|
this._ctx.loop = this.data.loop;
|
||||||
|
this._ctx.src = src;
|
||||||
|
},
|
||||||
|
// 播放
|
||||||
|
play() {
|
||||||
|
this._ctx.play();
|
||||||
|
this.setData({
|
||||||
|
playing: true
|
||||||
|
})
|
||||||
|
this.triggerEvent('play');
|
||||||
|
},
|
||||||
|
// 暂停
|
||||||
|
pause() {
|
||||||
|
this._ctx.pause();
|
||||||
|
this.setData({
|
||||||
|
playing: false
|
||||||
|
})
|
||||||
|
this.triggerEvent('pause');
|
||||||
|
},
|
||||||
|
// 移动进度条
|
||||||
|
seek(sec) {
|
||||||
|
this._ctx.seek(sec);
|
||||||
|
},
|
||||||
|
// 内部方法
|
||||||
|
_seeking(e) {
|
||||||
|
if (e.timeStamp - this.lastTime < 200) return;
|
||||||
|
var time = Math.round(e.detail.value / 100 * this._ctx.duration),
|
||||||
|
min = parseInt(time / 60),
|
||||||
|
sec = time % 60;
|
||||||
|
this.setData({
|
||||||
|
time: (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec)
|
||||||
|
})
|
||||||
|
this.lastTime = e.timeStamp;
|
||||||
|
},
|
||||||
|
_seeked(e) {
|
||||||
|
this.seek(e.detail.value / 100 * this._ctx.duration);
|
||||||
|
this.lastTime = void 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"component": true
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<view wx:if="{{controls}}" class="contain">
|
||||||
|
<slider class="slider" activeColor="#585959" block-size="12" disabled="{{error}}" value="{{value}}" bindchanging="_seeking" bindchange="_seeked" />
|
||||||
|
<view class="poster" style="background-image:url('{{poster}}')">
|
||||||
|
<view class="button" bindtap="{{playing?'pause':'play'}}">
|
||||||
|
<view class="{{playing?'pause':'play'}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="title">
|
||||||
|
<view class="name">{{name||'未知音频'}}</view>
|
||||||
|
<view class="author">{{author||'未知作者'}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="time">{{time}}</view>
|
||||||
|
</view>
|
|
@ -0,0 +1,75 @@
|
||||||
|
:host {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.author {
|
||||||
|
color: #888;
|
||||||
|
font-size: 28rpx;
|
||||||
|
width: 140rpx;
|
||||||
|
}
|
||||||
|
.author, .name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgb(0, 0, 0, 0.2);
|
||||||
|
border: 3.5rpx solid white;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
height: 47rpx;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0.9;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 47rpx;
|
||||||
|
}
|
||||||
|
.contain {
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 2px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
width: 650rpx;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-size: 33rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
width: 320rpx;
|
||||||
|
}
|
||||||
|
.pause {
|
||||||
|
width: 16.5rpx;
|
||||||
|
height: 16.5rpx;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.play {
|
||||||
|
border-bottom: 10rpx solid transparent;
|
||||||
|
border-left: 18rpx solid white;
|
||||||
|
border-top: 10rpx solid transparent;
|
||||||
|
margin-left: 5rpx;
|
||||||
|
}
|
||||||
|
.poster {
|
||||||
|
align-items: center;
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
background-size: contain;
|
||||||
|
display: flex;
|
||||||
|
height: 152.35rpx;
|
||||||
|
justify-content: center;
|
||||||
|
width: 152.35rpx;
|
||||||
|
}
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 18.75rpx;
|
||||||
|
margin: 0;
|
||||||
|
right: 35.15rpx;
|
||||||
|
width: 316.4rpx;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
flex: 1;
|
||||||
|
margin: 10rpx 0 0 35.15rpx;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
color: #888;
|
||||||
|
font-size: 28rpx;
|
||||||
|
margin: 16.4rpx 35.15rpx 0 0;
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
解析和匹配 Css 的选择器
|
||||||
|
github:https://github.com/jin-yufeng/Parser
|
||||||
|
docs:https://jin-yufeng.github.io/Parser
|
||||||
|
author:JinYufeng
|
||||||
|
update:2020/03/15
|
||||||
|
*/
|
||||||
|
var cfg = require('./config.js');
|
||||||
|
class CssHandler {
|
||||||
|
constructor(tagStyle) {
|
||||||
|
var styles = Object.assign({}, cfg.userAgentStyles);
|
||||||
|
for (var item in tagStyle)
|
||||||
|
styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
|
||||||
|
this.styles = styles;
|
||||||
|
}
|
||||||
|
getStyle = data => this.styles = new CssParser(data, this.styles).parse();
|
||||||
|
match(name, attrs) {
|
||||||
|
var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
|
||||||
|
if (attrs.class) {
|
||||||
|
var items = attrs.class.split(' ');
|
||||||
|
for (var i = 0, item; item = items[i]; i++)
|
||||||
|
if (tmp = this.styles['.' + item])
|
||||||
|
matched += tmp + ';';
|
||||||
|
}
|
||||||
|
if (tmp = this.styles['#' + attrs.id])
|
||||||
|
matched += tmp + ';';
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = CssHandler;
|
||||||
|
class CssParser {
|
||||||
|
constructor(data, init) {
|
||||||
|
this.data = data;
|
||||||
|
this.floor = 0;
|
||||||
|
this.i = 0;
|
||||||
|
this.list = [];
|
||||||
|
this.res = init;
|
||||||
|
this.state = this.Space;
|
||||||
|
}
|
||||||
|
parse() {
|
||||||
|
for (var c; c = this.data[this.i]; this.i++)
|
||||||
|
this.state(c);
|
||||||
|
return this.res;
|
||||||
|
}
|
||||||
|
section = () => this.data.substring(this.start, this.i);
|
||||||
|
isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
|
// 状态机
|
||||||
|
Space(c) {
|
||||||
|
if (c == '.' || c == '#' || this.isLetter(c)) {
|
||||||
|
this.start = this.i;
|
||||||
|
this.state = this.Name;
|
||||||
|
} else if (c == '/' && this.data[this.i + 1] == '*')
|
||||||
|
this.Comment();
|
||||||
|
else if (!cfg.blankChar[c] && c != ';')
|
||||||
|
this.state = this.Ignore;
|
||||||
|
}
|
||||||
|
Comment() {
|
||||||
|
this.i = this.data.indexOf('*/', this.i) + 1;
|
||||||
|
if (!this.i) this.i = this.data.length;
|
||||||
|
this.state = this.Space;
|
||||||
|
}
|
||||||
|
Ignore(c) {
|
||||||
|
if (c == '{') this.floor++;
|
||||||
|
else if (c == '}' && !--this.floor) this.state = this.Space;
|
||||||
|
}
|
||||||
|
Name(c) {
|
||||||
|
if (cfg.blankChar[c]) {
|
||||||
|
this.list.push(this.section());
|
||||||
|
this.state = this.NameSpace;
|
||||||
|
} else if (c == '{') {
|
||||||
|
this.list.push(this.section());
|
||||||
|
this.Content();
|
||||||
|
} else if (c == ',') {
|
||||||
|
this.list.push(this.section());
|
||||||
|
this.Comma();
|
||||||
|
} else if (!this.isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
|
||||||
|
this.state = this.Ignore;
|
||||||
|
}
|
||||||
|
NameSpace(c) {
|
||||||
|
if (c == '{') this.Content();
|
||||||
|
else if (c == ',') this.Comma();
|
||||||
|
else if (!cfg.blankChar[c]) this.state = this.Ignore;
|
||||||
|
}
|
||||||
|
Comma() {
|
||||||
|
while (cfg.blankChar[this.data[++this.i]]);
|
||||||
|
if (this.data[this.i] == '{') this.Content();
|
||||||
|
else {
|
||||||
|
this.start = this.i--;
|
||||||
|
this.state = this.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Content() {
|
||||||
|
this.start = ++this.i;
|
||||||
|
if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
|
||||||
|
var content = this.section();
|
||||||
|
for (var i = 0, item; item = this.list[i++];)
|
||||||
|
if (this.res[item]) this.res[item] += ';' + content;
|
||||||
|
else this.res[item] = content;
|
||||||
|
this.list = [];
|
||||||
|
this.state = this.Space;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,528 @@
|
||||||
|
/*
|
||||||
|
将 html 解析为适用于小程序 rich-text 的 DOM 结构
|
||||||
|
github:https://github.com/jin-yufeng/Parser
|
||||||
|
docs:https://jin-yufeng.github.io/Parser
|
||||||
|
author:JinYufeng
|
||||||
|
update:2020/04/26
|
||||||
|
*/
|
||||||
|
var cfg = require('./config.js'),
|
||||||
|
blankChar = cfg.blankChar,
|
||||||
|
CssHandler = require('./CssHandler.js'),
|
||||||
|
screenWidth = wx.getSystemInfoSync().screenWidth;
|
||||||
|
try {
|
||||||
|
var emoji = require('./emoji.js');
|
||||||
|
} catch (e) {}
|
||||||
|
class MpHtmlParser {
|
||||||
|
constructor(data, options = {}) {
|
||||||
|
this.attrs = {};
|
||||||
|
this.compress = options.compress;
|
||||||
|
this.CssHandler = new CssHandler(options.tagStyle, screenWidth);
|
||||||
|
this.data = data;
|
||||||
|
this.domain = options.domain;
|
||||||
|
this.DOM = [];
|
||||||
|
this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
|
||||||
|
this.protocol = this.domain && this.domain.includes('://') ? this.domain.split('://')[0] : 'http';
|
||||||
|
this.state = this.Text;
|
||||||
|
this.STACK = [];
|
||||||
|
this.useAnchor = options.useAnchor;
|
||||||
|
this.xml = options.xml;
|
||||||
|
}
|
||||||
|
parse() {
|
||||||
|
if (emoji) this.data = emoji.parseEmoji(this.data);
|
||||||
|
for (var c; c = this.data[this.i]; this.i++)
|
||||||
|
this.state(c);
|
||||||
|
if (this.state == this.Text) this.setText();
|
||||||
|
while (this.STACK.length) this.popNode(this.STACK.pop());
|
||||||
|
if (this.DOM.length) {
|
||||||
|
this.DOM[0].PoweredBy = 'Parser';
|
||||||
|
if (this.title) this.DOM[0].title = this.title;
|
||||||
|
}
|
||||||
|
return this.DOM;
|
||||||
|
}
|
||||||
|
// 设置属性
|
||||||
|
setAttr() {
|
||||||
|
var name = this.getName(this.attrName);
|
||||||
|
if (cfg.trustAttrs[name]) {
|
||||||
|
var val = this.attrVal;
|
||||||
|
if (val) {
|
||||||
|
if (name == 'src') this.attrs[name] = this.getUrl(this.decode(val, 'amp'));
|
||||||
|
else if (name == 'href' || name == 'style') this.attrs[name] = this.decode(val, 'amp');
|
||||||
|
else this.attrs[name] = val;
|
||||||
|
} else if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
|
||||||
|
}
|
||||||
|
this.attrVal = '';
|
||||||
|
while (blankChar[this.data[this.i]]) this.i++;
|
||||||
|
if (this.isClose()) this.setNode();
|
||||||
|
else {
|
||||||
|
this.start = this.i;
|
||||||
|
this.state = this.AttrName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置文本节点
|
||||||
|
setText() {
|
||||||
|
var back, text = this.section();
|
||||||
|
if (!text) return;
|
||||||
|
text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
|
||||||
|
if (back) {
|
||||||
|
this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
|
||||||
|
let j = this.start + text.length;
|
||||||
|
for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.pre) {
|
||||||
|
// 合并空白符
|
||||||
|
var tmp = [];
|
||||||
|
for (let i = text.length, c; c = text[--i];)
|
||||||
|
if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c);
|
||||||
|
text = tmp.join('');
|
||||||
|
if (text == ' ') return;
|
||||||
|
}
|
||||||
|
this.siblings().push({
|
||||||
|
type: 'text',
|
||||||
|
text: this.decode(text)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 设置元素节点
|
||||||
|
setNode() {
|
||||||
|
var node = {
|
||||||
|
name: this.getName(this.tagName),
|
||||||
|
attrs: this.attrs
|
||||||
|
},
|
||||||
|
close = cfg.selfClosingTags[node.name] || (this.xml && this.data[this.i] == '/');
|
||||||
|
this.attrs = {};
|
||||||
|
if (!cfg.ignoreTags[node.name]) {
|
||||||
|
this.matchAttr(node);
|
||||||
|
if (!close) {
|
||||||
|
node.children = [];
|
||||||
|
if (node.name == 'pre' && cfg.highlight) {
|
||||||
|
this.remove(node);
|
||||||
|
this.pre = node.pre = true;
|
||||||
|
}
|
||||||
|
this.siblings().push(node);
|
||||||
|
this.STACK.push(node);
|
||||||
|
} else if (!cfg.filter || cfg.filter(node, this) != false)
|
||||||
|
this.siblings().push(node);
|
||||||
|
} else {
|
||||||
|
if (!close) this.remove(node);
|
||||||
|
else if (node.name == 'source') {
|
||||||
|
var parent = this.parent(),
|
||||||
|
attrs = node.attrs;
|
||||||
|
if (parent && attrs.src)
|
||||||
|
if (parent.name == 'video' || parent.name == 'audio')
|
||||||
|
parent.attrs.source.push(attrs.src);
|
||||||
|
else {
|
||||||
|
var i, media = attrs.media;
|
||||||
|
if (parent.name == 'picture' && !parent.attrs.src && (!media || (media.includes('px') &&
|
||||||
|
(((i = media.indexOf('min-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth > parseInt(media.substr(i + 1))) ||
|
||||||
|
((i = media.indexOf('max-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth < parseInt(media.substr(i + 1)))))))
|
||||||
|
parent.attrs.src = attrs.src;
|
||||||
|
}
|
||||||
|
} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
|
||||||
|
}
|
||||||
|
if (this.data[this.i] == '/') this.i++;
|
||||||
|
this.start = this.i + 1;
|
||||||
|
this.state = this.Text;
|
||||||
|
}
|
||||||
|
// 移除标签
|
||||||
|
remove(node) {
|
||||||
|
var name = node.name,
|
||||||
|
j = this.i;
|
||||||
|
while (1) {
|
||||||
|
if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
|
||||||
|
if (name == 'pre' || name == 'svg') this.i = j;
|
||||||
|
else this.i = this.data.length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.start = (this.i += 2);
|
||||||
|
while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
|
||||||
|
if (this.getName(this.section()) == name) {
|
||||||
|
// 代码块高亮
|
||||||
|
if (name == 'pre') {
|
||||||
|
this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) + this.data.substr(this.i - 5);
|
||||||
|
return this.i = j;
|
||||||
|
} else if (name == 'style')
|
||||||
|
this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
|
||||||
|
else if (name == 'title')
|
||||||
|
this.title = this.data.substring(j + 1, this.i - 7);
|
||||||
|
if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
|
||||||
|
// 处理 svg
|
||||||
|
if (name == 'svg') {
|
||||||
|
var src = this.data.substring(j, this.i + 1);
|
||||||
|
if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src;
|
||||||
|
var i = j;
|
||||||
|
while (this.data[j] != '<') j--;
|
||||||
|
src = this.data.substring(j, i) + src;
|
||||||
|
var parent = this.parent();
|
||||||
|
if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
|
||||||
|
parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
|
||||||
|
this.siblings().push({
|
||||||
|
name: 'img',
|
||||||
|
attrs: {
|
||||||
|
src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
|
||||||
|
ignore: 'T'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 处理属性
|
||||||
|
matchAttr(node) {
|
||||||
|
var attrs = node.attrs,
|
||||||
|
style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
|
||||||
|
styleObj = {};
|
||||||
|
if (attrs.id) {
|
||||||
|
if (this.compress & 1) attrs.id = void 0;
|
||||||
|
else if (this.useAnchor) this.bubble();
|
||||||
|
}
|
||||||
|
if ((this.compress & 2) && attrs.class) attrs.class = void 0;
|
||||||
|
switch (node.name) {
|
||||||
|
case 'a':
|
||||||
|
case 'ad':
|
||||||
|
this.bubble();
|
||||||
|
break;
|
||||||
|
case 'font':
|
||||||
|
if (attrs.color) {
|
||||||
|
styleObj['color'] = attrs.color;
|
||||||
|
attrs.color = void 0;
|
||||||
|
}
|
||||||
|
if (attrs.face) {
|
||||||
|
styleObj['font-family'] = attrs.face;
|
||||||
|
attrs.face = void 0;
|
||||||
|
}
|
||||||
|
if (attrs.size) {
|
||||||
|
var size = parseInt(attrs.size);
|
||||||
|
if (size < 1) size = 1;
|
||||||
|
else if (size > 7) size = 7;
|
||||||
|
var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
|
||||||
|
styleObj['font-size'] = map[size - 1];
|
||||||
|
attrs.size = void 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'video':
|
||||||
|
case 'audio':
|
||||||
|
if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
|
||||||
|
else this[`${node.name}Num`]++;
|
||||||
|
if (node.name == 'video') {
|
||||||
|
if (this.videoNum > 3)
|
||||||
|
node.lazyLoad = 1;
|
||||||
|
if (attrs.width) {
|
||||||
|
styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px');
|
||||||
|
attrs.width = void 0;
|
||||||
|
}
|
||||||
|
if (attrs.height) {
|
||||||
|
styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px');
|
||||||
|
attrs.height = void 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs.source = [];
|
||||||
|
if (attrs.src) attrs.source.push(attrs.src);
|
||||||
|
if (!attrs.controls && !attrs.autoplay)
|
||||||
|
console.warn(`存在没有 controls 属性的 ${node.name} 标签,可能导致无法播放`, node);
|
||||||
|
this.bubble();
|
||||||
|
break;
|
||||||
|
case 'td':
|
||||||
|
case 'th':
|
||||||
|
if (attrs.colspan || attrs.rowspan)
|
||||||
|
for (var k = this.STACK.length, item; item = this.STACK[--k];)
|
||||||
|
if (item.name == 'table') {
|
||||||
|
item.c = void 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attrs.align) {
|
||||||
|
styleObj['text-align'] = attrs.align;
|
||||||
|
attrs.align = void 0;
|
||||||
|
}
|
||||||
|
// 压缩 style
|
||||||
|
var styles = style.split(';');
|
||||||
|
style = '';
|
||||||
|
for (var i = 0, len = styles.length; i < len; i++) {
|
||||||
|
var info = styles[i].split(':');
|
||||||
|
if (info.length < 2) continue;
|
||||||
|
let key = info[0].trim().toLowerCase(),
|
||||||
|
value = info.slice(1).join(':').trim();
|
||||||
|
if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value.includes('safe'))
|
||||||
|
style += `;${key}:${value}`;
|
||||||
|
else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
|
||||||
|
styleObj[key] = value;
|
||||||
|
}
|
||||||
|
if (node.name == 'img' || node.name == 'picture') {
|
||||||
|
if (attrs['data-src']) {
|
||||||
|
attrs.src = attrs.src || attrs['data-src'];
|
||||||
|
attrs['data-src'] = void 0;
|
||||||
|
}
|
||||||
|
if ((attrs.src || node.name == 'picture') && !attrs.ignore) {
|
||||||
|
if (this.bubble())
|
||||||
|
attrs.i = (this.imgNum++).toString();
|
||||||
|
else attrs.ignore = 'T';
|
||||||
|
}
|
||||||
|
if (attrs.ignore) styleObj['max-width'] = '100%';
|
||||||
|
var width;
|
||||||
|
if(styleObj.width) width = styleObj.width;
|
||||||
|
else if(attrs.width) width = attrs.width.includes('%') ? attrs.width : attrs.width + 'px';
|
||||||
|
if (width) {
|
||||||
|
styleObj.width = width;
|
||||||
|
attrs.width = '100%';
|
||||||
|
if (parseInt(width) > screenWidth) {
|
||||||
|
styleObj.height = '';
|
||||||
|
if (attrs.height) attrs.height = void 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (styleObj.height) {
|
||||||
|
attrs.height = styleObj.height;
|
||||||
|
styleObj.height = '';
|
||||||
|
} else if (attrs.height && !attrs.height.includes('%'))
|
||||||
|
attrs.height += 'px';
|
||||||
|
}
|
||||||
|
for (var key in styleObj) {
|
||||||
|
var value = styleObj[key];
|
||||||
|
if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
|
||||||
|
// 填充链接
|
||||||
|
if (value.includes('url')) {
|
||||||
|
var j = value.indexOf('(');
|
||||||
|
if (j++ != -1) {
|
||||||
|
while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
|
||||||
|
value = value.substr(0, j) + this.getUrl(value.substr(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 转换 rpx
|
||||||
|
else if (value.includes('rpx'))
|
||||||
|
value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * screenWidth / 750 + 'px');
|
||||||
|
else if (key == 'white-space' && value.includes('pre'))
|
||||||
|
this.pre = node.pre = true;
|
||||||
|
style += `;${key}:${value}`;
|
||||||
|
}
|
||||||
|
style = style.substr(1);
|
||||||
|
if (style) attrs.style = style;
|
||||||
|
}
|
||||||
|
// 节点出栈处理
|
||||||
|
popNode(node) {
|
||||||
|
// 空白符处理
|
||||||
|
if (node.pre) {
|
||||||
|
node.pre = this.pre = void 0;
|
||||||
|
for (let i = this.STACK.length; i--;)
|
||||||
|
if (this.STACK[i].pre)
|
||||||
|
this.pre = true;
|
||||||
|
}
|
||||||
|
if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
|
||||||
|
return this.siblings().pop();
|
||||||
|
var attrs = node.attrs;
|
||||||
|
// 替换一些标签名
|
||||||
|
if (node.name == 'picture') {
|
||||||
|
node.name = 'img';
|
||||||
|
if (!attrs.src && (node.children[0] || '').name == 'img')
|
||||||
|
attrs.src = node.children[0].attrs.src;
|
||||||
|
return node.children = void 0;
|
||||||
|
}
|
||||||
|
if (cfg.blockTags[node.name]) node.name = 'div';
|
||||||
|
else if (!cfg.trustTags[node.name]) node.name = 'span';
|
||||||
|
// 处理列表
|
||||||
|
if (node.c && (node.name == 'ul' || node.name == 'ol')) {
|
||||||
|
if ((node.attrs.style || '').includes('list-style:none')) {
|
||||||
|
for (let i = 0, child; child = node.children[i++];)
|
||||||
|
if (child.name == 'li')
|
||||||
|
child.name = 'div';
|
||||||
|
} else if (node.name == 'ul') {
|
||||||
|
var floor = 1;
|
||||||
|
for (let i = this.STACK.length; i--;)
|
||||||
|
if (this.STACK[i].name == 'ul') floor++;
|
||||||
|
if (floor != 1)
|
||||||
|
for (let i = node.children.length; i--;)
|
||||||
|
node.children[i].floor = floor;
|
||||||
|
} else {
|
||||||
|
for (let i = 0, num = 1, child; child = node.children[i++];)
|
||||||
|
if (child.name == 'li') {
|
||||||
|
child.type = 'ol';
|
||||||
|
child.num = ((num, type) => {
|
||||||
|
if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
|
||||||
|
if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
|
||||||
|
if (type == 'i' || type == 'I') {
|
||||||
|
num = (num - 1) % 99 + 1;
|
||||||
|
var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
|
||||||
|
ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
|
||||||
|
res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
|
||||||
|
if (type == 'i') return res.toLowerCase();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
})(num++, attrs.type) + '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 处理表格的边框
|
||||||
|
if (node.name == 'table') {
|
||||||
|
var padding = attrs.cellpadding,
|
||||||
|
spacing = attrs.cellspacing,
|
||||||
|
border = attrs.border;
|
||||||
|
if (node.c) {
|
||||||
|
this.bubble();
|
||||||
|
attrs.style = (attrs.style || '') + ';display:table';
|
||||||
|
if (!padding) padding = 2;
|
||||||
|
if (!spacing) spacing = 2;
|
||||||
|
}
|
||||||
|
if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
|
||||||
|
if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
|
||||||
|
if (border || padding || node.c)
|
||||||
|
(function f(ns) {
|
||||||
|
for (var i = 0, n; n = ns[i]; i++) {
|
||||||
|
if(n.type == 'text') continue;
|
||||||
|
var style = n.attrs.style || '';
|
||||||
|
if (node.c && n.name[0] == 't') {
|
||||||
|
n.c = 1;
|
||||||
|
style += ';display:table-' + (n.name == 'th' || n.name == 'td' ? 'cell' : (n.name == 'tr' ? 'row' : 'row-group'));
|
||||||
|
}
|
||||||
|
if (n.name == 'th' || n.name == 'td') {
|
||||||
|
if (border) style = `border:${border}px solid gray;${style}`;
|
||||||
|
if (padding) style = `padding:${padding}px;${style}`;
|
||||||
|
} else f(n.children || []);
|
||||||
|
if (style) n.attrs.style = style;
|
||||||
|
}
|
||||||
|
})(node.children)
|
||||||
|
}
|
||||||
|
this.CssHandler.pop && this.CssHandler.pop(node);
|
||||||
|
// 自动压缩
|
||||||
|
if (node.name == 'div' && !Object.keys(attrs).length) {
|
||||||
|
var siblings = this.siblings();
|
||||||
|
if (node.children.length == 1 && node.children[0].name == 'div')
|
||||||
|
siblings[siblings.length - 1] = node.children[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 工具函数
|
||||||
|
bubble() {
|
||||||
|
for (var i = this.STACK.length, item; item = this.STACK[--i];) {
|
||||||
|
if (cfg.richOnlyTags[item.name]) {
|
||||||
|
if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
item.c = 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
decode(val, amp) {
|
||||||
|
var i = -1,
|
||||||
|
j, en;
|
||||||
|
while (1) {
|
||||||
|
if ((i = val.indexOf('&', i + 1)) == -1) break;
|
||||||
|
if ((j = val.indexOf(';', i + 2)) == -1) break;
|
||||||
|
if (val[i + 1] == '#') {
|
||||||
|
en = parseInt((val[i + 2] == 'x' ? '0' : '') + val.substring(i + 2, j));
|
||||||
|
if (!isNaN(en)) val = val.substr(0, i) + String.fromCharCode(en) + val.substr(j + 1);
|
||||||
|
} else {
|
||||||
|
en = val.substring(i + 1, j);
|
||||||
|
if (cfg.entities[en] || en == amp)
|
||||||
|
val = val.substr(0, i) + (cfg.entities[en] || '&') + val.substr(j + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
getUrl(url) {
|
||||||
|
if (url[0] == '/') {
|
||||||
|
if (url[1] == '/') url = this.protocol + ':' + url;
|
||||||
|
else if (this.domain) url = this.domain + url;
|
||||||
|
} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
|
||||||
|
url = this.domain + '/' + url;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
getName = val => this.xml ? val : val.toLowerCase();
|
||||||
|
isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
|
||||||
|
section = () => this.data.substring(this.start, this.i);
|
||||||
|
parent = () => this.STACK[this.STACK.length - 1];
|
||||||
|
siblings = () => this.STACK.length ? this.parent().children : this.DOM;
|
||||||
|
// 状态机
|
||||||
|
Text(c) {
|
||||||
|
if (c == '<') {
|
||||||
|
var next = this.data[this.i + 1],
|
||||||
|
isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
|
if (isLetter(next)) {
|
||||||
|
this.setText();
|
||||||
|
this.start = this.i + 1;
|
||||||
|
this.state = this.TagName;
|
||||||
|
} else if (next == '/') {
|
||||||
|
this.setText();
|
||||||
|
if (isLetter(this.data[++this.i + 1])) {
|
||||||
|
this.start = this.i + 1;
|
||||||
|
this.state = this.EndTag;
|
||||||
|
} else this.Comment();
|
||||||
|
} else if (next == '!') {
|
||||||
|
this.setText();
|
||||||
|
this.Comment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Comment() {
|
||||||
|
var key;
|
||||||
|
if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
|
||||||
|
else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
|
||||||
|
else key = '>';
|
||||||
|
if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
|
||||||
|
else this.i += key.length - 1;
|
||||||
|
this.start = this.i + 1;
|
||||||
|
this.state = this.Text;
|
||||||
|
}
|
||||||
|
TagName(c) {
|
||||||
|
if (blankChar[c]) {
|
||||||
|
this.tagName = this.section();
|
||||||
|
while (blankChar[this.data[this.i]]) this.i++;
|
||||||
|
if (this.isClose()) this.setNode();
|
||||||
|
else {
|
||||||
|
this.start = this.i;
|
||||||
|
this.state = this.AttrName;
|
||||||
|
}
|
||||||
|
} else if (this.isClose()) {
|
||||||
|
this.tagName = this.section();
|
||||||
|
this.setNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AttrName(c) {
|
||||||
|
var blank = blankChar[c];
|
||||||
|
if (blank) {
|
||||||
|
this.attrName = this.section();
|
||||||
|
c = this.data[this.i];
|
||||||
|
}
|
||||||
|
if (c == '=') {
|
||||||
|
if (!blank) this.attrName = this.section();
|
||||||
|
while (blankChar[this.data[++this.i]]);
|
||||||
|
this.start = this.i--;
|
||||||
|
this.state = this.AttrValue;
|
||||||
|
} else if (blank) this.setAttr();
|
||||||
|
else if (this.isClose()) {
|
||||||
|
this.attrName = this.section();
|
||||||
|
this.setAttr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AttrValue(c) {
|
||||||
|
if (c == '"' || c == "'") {
|
||||||
|
this.start++;
|
||||||
|
if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
|
||||||
|
this.attrVal = this.section();
|
||||||
|
this.i++;
|
||||||
|
} else {
|
||||||
|
for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
|
||||||
|
this.attrVal = this.section();
|
||||||
|
}
|
||||||
|
this.setAttr();
|
||||||
|
}
|
||||||
|
EndTag(c) {
|
||||||
|
if (blankChar[c] || c == '>' || c == '/') {
|
||||||
|
var name = this.getName(this.section());
|
||||||
|
for (var i = this.STACK.length; i--;)
|
||||||
|
if (this.STACK[i].name == name) break;
|
||||||
|
if (i != -1) {
|
||||||
|
var node;
|
||||||
|
while ((node = this.STACK.pop()).name != name);
|
||||||
|
this.popNode(node);
|
||||||
|
} else if (name == 'p' || name == 'br')
|
||||||
|
this.siblings().push({
|
||||||
|
name,
|
||||||
|
attrs: {}
|
||||||
|
});
|
||||||
|
this.i = this.data.indexOf('>', this.i);
|
||||||
|
this.start = this.i + 1;
|
||||||
|
if (this.i == -1) this.i = this.data.length;
|
||||||
|
else this.state = this.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = MpHtmlParser;
|
|
@ -0,0 +1,102 @@
|
||||||
|
/* 配置文件 */
|
||||||
|
const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容
|
||||||
|
const Prism = require('./prism.js');
|
||||||
|
module.exports = {
|
||||||
|
// 过滤器函数
|
||||||
|
filter(node, cxt) {
|
||||||
|
if (node.name == 'pre')
|
||||||
|
cxt.bubble(); // 使得 pre 不被 rich-text 包含(为实现长按复制)
|
||||||
|
},
|
||||||
|
// 代码高亮函数
|
||||||
|
highlight(content, attrs) {
|
||||||
|
var info = content.match(/<code.*?language-([a-z-]+).*?>([\s\S]+)<\/code.*?>/m);
|
||||||
|
if (!info) return content;
|
||||||
|
var lan = info[1];
|
||||||
|
content = info[2].replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
||||||
|
attrs['data-content'] = content; // 记录原始内容,长按复制时使用
|
||||||
|
switch (lan) {
|
||||||
|
case 'js':
|
||||||
|
case 'javascript':
|
||||||
|
content = Prism.highlight(content, Prism.languages.javascript, 'javascript');
|
||||||
|
break;
|
||||||
|
case 'html':
|
||||||
|
case 'html-editor':
|
||||||
|
case 'wxml':
|
||||||
|
case 'vue':
|
||||||
|
content = Prism.highlight(content, Prism.languages.html, 'html');
|
||||||
|
break;
|
||||||
|
case 'json':
|
||||||
|
content = Prism.highlight(content, Prism.languages.json, 'json');
|
||||||
|
break;
|
||||||
|
case 'md':
|
||||||
|
case 'md-editor':
|
||||||
|
case 'markdown':
|
||||||
|
content = Prism.highlight(content, Prism.languages.markdown, 'markdown');
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
case 'cpp':
|
||||||
|
content = Prism.highlight(content, Prism.languages.clike, 'clike');
|
||||||
|
}
|
||||||
|
// 增加语言显示
|
||||||
|
if (!lan.includes('editor'))
|
||||||
|
content = `<span style="position:absolute;top:3px;right:8px;font-size:.6rem;color:#808080;font-weight:bold">${lan}</span><div style='overflow:auto;max-width:100%;padding-bottom:1em'>${content}</div>`;
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
// 文本处理函数
|
||||||
|
onText: null,
|
||||||
|
// 实体编码列表
|
||||||
|
entities: {
|
||||||
|
quot: '"',
|
||||||
|
apos: "'",
|
||||||
|
semi: ';',
|
||||||
|
nbsp: '\xA0',
|
||||||
|
ndash: '–',
|
||||||
|
mdash: '—',
|
||||||
|
middot: '·',
|
||||||
|
lsquo: '‘',
|
||||||
|
rsquo: '’',
|
||||||
|
ldquo: '“',
|
||||||
|
rdquo: '”',
|
||||||
|
bull: '•',
|
||||||
|
hellip: '…'
|
||||||
|
},
|
||||||
|
blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
|
||||||
|
inlineTags: makeMap('abbr,b,big,code,del,em,i,ins,label,q,small,span,strong'),
|
||||||
|
// 块级标签,将被转为 div
|
||||||
|
blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + (canIUse ? '' : ',pre')),
|
||||||
|
// 将被移除的标签
|
||||||
|
ignoreTags: makeMap('area,base,basefont,canvas,command,embed,frame,iframe,input,isindex,keygen,link,map,meta,param,script,source,style,svg,textarea,title,track,use,wbr' + (canIUse ? ',rp' : '')),
|
||||||
|
// 只能被 rich-text 显示的标签
|
||||||
|
richOnlyTags: makeMap('a,colgroup,fieldset,legend,picture,table' + (canIUse ? ',bdi,bdo,rt,ruby' : '')),
|
||||||
|
// 自闭合的标签
|
||||||
|
selfClosingTags: makeMap('area,base,basefont,br,col,circle,ellipse,embed,frame,hr,img,input,isindex,keygen,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
|
||||||
|
// 信任的属性
|
||||||
|
trustAttrs: makeMap('align,alt,app-id,author,autoplay,border,cellpadding,cellspacing,class,color,colspan,controls,data-src,dir,face,height,href,id,ignore,loop,media,muted,name,path,poster,rowspan,size,span,src,start,style,type,unit-id,width,xmlns'),
|
||||||
|
// bool 型的属性
|
||||||
|
boolAttrs: makeMap('autoplay,controls,ignore,loop,muted'),
|
||||||
|
// 信任的标签
|
||||||
|
trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video' + (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '')),
|
||||||
|
// 默认的标签样式
|
||||||
|
userAgentStyles: {
|
||||||
|
address: 'font-style:italic',
|
||||||
|
big: 'display:inline;font-size:1.2em',
|
||||||
|
blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
|
||||||
|
caption: 'display:table-caption;text-align:center',
|
||||||
|
center: 'text-align:center',
|
||||||
|
cite: 'font-style:italic',
|
||||||
|
dd: 'margin-left:40px',
|
||||||
|
mark: 'background-color:yellow',
|
||||||
|
pre: 'font-family:monospace;white-space:pre;overflow:scroll',
|
||||||
|
s: 'text-decoration:line-through',
|
||||||
|
small: 'display:inline;font-size:0.8em',
|
||||||
|
u: 'text-decoration:underline'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeMap(str) {
|
||||||
|
var map = {},
|
||||||
|
list = str.split(',');
|
||||||
|
for (var i = list.length; i--;)
|
||||||
|
map[list[i]] = true;
|
||||||
|
return map;
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
emoji 扩展包
|
||||||
|
github:https://github.com/jin-yufeng/Parser
|
||||||
|
docs:https://jin-yufeng.github.io/Parser
|
||||||
|
author:JinYufeng
|
||||||
|
*/
|
||||||
|
const reg = /\[(\S+?)\]/g;
|
||||||
|
const data = {
|
||||||
|
'笑脸': '😄',
|
||||||
|
'生病': '😷',
|
||||||
|
'破涕为笑': '😂',
|
||||||
|
'吐舌': '😝',
|
||||||
|
'脸红': '😳',
|
||||||
|
'恐惧': '😱',
|
||||||
|
'失望': '😔',
|
||||||
|
'无语': '😒',
|
||||||
|
'眨眼': '😉',
|
||||||
|
'酷': '😎',
|
||||||
|
'哭': '😭',
|
||||||
|
'痴迷': '😍',
|
||||||
|
'吻': '😘',
|
||||||
|
'思考': '🤔',
|
||||||
|
'困惑': '😕',
|
||||||
|
'颠倒': '🙃',
|
||||||
|
'钱': '🤑',
|
||||||
|
'惊讶': '😲',
|
||||||
|
'白眼': '🙄',
|
||||||
|
'叹气': '😤',
|
||||||
|
'睡觉': '😴',
|
||||||
|
'书呆子': '🤓',
|
||||||
|
'愤怒': '😡',
|
||||||
|
'面无表情': '😑',
|
||||||
|
'张嘴': '😮',
|
||||||
|
'量体温': '🤒',
|
||||||
|
'呕吐': '🤮',
|
||||||
|
'光环': '😇',
|
||||||
|
'幽灵': '👻',
|
||||||
|
'外星人': '👽',
|
||||||
|
'机器人': '🤖',
|
||||||
|
'捂眼镜': '🙈',
|
||||||
|
'捂耳朵': '🙉',
|
||||||
|
'捂嘴': '🙊',
|
||||||
|
'婴儿': '👶',
|
||||||
|
'男孩': '👦',
|
||||||
|
'女孩': '👧',
|
||||||
|
'男人': '👨',
|
||||||
|
'女人': '👩',
|
||||||
|
'老人': '👴',
|
||||||
|
'老妇人': '👵',
|
||||||
|
'警察': '👮',
|
||||||
|
'王子': '🤴',
|
||||||
|
'公主': '🤴',
|
||||||
|
'举手': '🙋',
|
||||||
|
'跑步': '🏃',
|
||||||
|
'家庭': '👪',
|
||||||
|
'眼睛': '👀',
|
||||||
|
'鼻子': '👃',
|
||||||
|
'耳朵': '👂',
|
||||||
|
'舌头': '👅',
|
||||||
|
'嘴': '👄',
|
||||||
|
'心': '❤️',
|
||||||
|
'心碎': '💔',
|
||||||
|
'雪人': '☃️',
|
||||||
|
'情书': '💌',
|
||||||
|
'大便': '💩',
|
||||||
|
'闹钟': '⏰',
|
||||||
|
'眼镜': '👓',
|
||||||
|
'雨伞': '☂️',
|
||||||
|
'音乐': '🎵',
|
||||||
|
'话筒': '🎤',
|
||||||
|
'游戏机': '🎮',
|
||||||
|
'喇叭': '📢',
|
||||||
|
'耳机': '🎧',
|
||||||
|
'礼物': '🎁',
|
||||||
|
'电话': '📞',
|
||||||
|
'电脑': '💻',
|
||||||
|
'打印机': '🖨️',
|
||||||
|
'手电筒': '🔦',
|
||||||
|
'灯泡': '💡',
|
||||||
|
'书本': '📖',
|
||||||
|
'信封': '✉️',
|
||||||
|
'药丸': '💊',
|
||||||
|
'口红': '💄',
|
||||||
|
'手机': '📱',
|
||||||
|
'相机': '📷',
|
||||||
|
'电视': '📺',
|
||||||
|
'中': '🀄',
|
||||||
|
'垃圾桶': '🚮',
|
||||||
|
'厕所': '🚾',
|
||||||
|
'感叹号': '❗',
|
||||||
|
'禁': '🈲',
|
||||||
|
'可': '🉑',
|
||||||
|
'彩虹': '🌈',
|
||||||
|
'旋风': '🌀',
|
||||||
|
'雷电': '⚡',
|
||||||
|
'雪花': '❄️',
|
||||||
|
'星星': '⭐',
|
||||||
|
'水滴': '💧',
|
||||||
|
'玫瑰': '🌹',
|
||||||
|
'加油': '💪',
|
||||||
|
'左': '👈',
|
||||||
|
'右': '👉',
|
||||||
|
'上': '👆',
|
||||||
|
'下': '👇',
|
||||||
|
'手掌': '🖐️',
|
||||||
|
'好的': '👌',
|
||||||
|
'好': '👍',
|
||||||
|
'差': '👎',
|
||||||
|
'胜利': '✌',
|
||||||
|
'拳头': '👊',
|
||||||
|
'挥手': '👋',
|
||||||
|
'鼓掌': '👏',
|
||||||
|
'猴子': '🐒',
|
||||||
|
'狗': '🐶',
|
||||||
|
'狼': '🐺',
|
||||||
|
'猫': '🐱',
|
||||||
|
'老虎': '🐯',
|
||||||
|
'马': '🐎',
|
||||||
|
'独角兽': '🦄',
|
||||||
|
'斑马': '🦓',
|
||||||
|
'鹿': '🦌',
|
||||||
|
'牛': '🐮',
|
||||||
|
'猪': '🐷',
|
||||||
|
'羊': '🐏',
|
||||||
|
'长颈鹿': '🦒',
|
||||||
|
'大象': '🐘',
|
||||||
|
'老鼠': '🐭',
|
||||||
|
'蝙蝠': '🦇',
|
||||||
|
'刺猬': '🦔',
|
||||||
|
'熊猫': '🐼',
|
||||||
|
'鸽子': '🕊️',
|
||||||
|
'鸭子': '🦆',
|
||||||
|
'兔子': '🐇',
|
||||||
|
'老鹰': '🦅',
|
||||||
|
'青蛙': '🐸',
|
||||||
|
'蛇': '🐍',
|
||||||
|
'龙': '🐉',
|
||||||
|
'鲸鱼': '🐳',
|
||||||
|
'海豚': '🐬',
|
||||||
|
'足球': '⚽',
|
||||||
|
'棒球': '⚾',
|
||||||
|
'篮球': '🏀',
|
||||||
|
'排球': '🏐',
|
||||||
|
'橄榄球': '🏉',
|
||||||
|
'网球': '🎾',
|
||||||
|
'骰子': '🎲',
|
||||||
|
'鸡腿': '🍗',
|
||||||
|
'蛋糕': '🎂',
|
||||||
|
'啤酒': '🍺',
|
||||||
|
'饺子': '🥟',
|
||||||
|
'汉堡': '🍔',
|
||||||
|
'薯条': '🍟',
|
||||||
|
'意大利面': '🍝',
|
||||||
|
'干杯': '🥂',
|
||||||
|
'筷子': '🥢',
|
||||||
|
'糖果': '🍬',
|
||||||
|
'奶瓶': '🍼',
|
||||||
|
'爆米花': '🍿',
|
||||||
|
'邮局': '🏤',
|
||||||
|
'医院': '🏥',
|
||||||
|
'银行': '🏦',
|
||||||
|
'酒店': '🏨',
|
||||||
|
'学校': '🏫',
|
||||||
|
'城堡': '🏰',
|
||||||
|
'火车': '🚂',
|
||||||
|
'高铁': '🚄',
|
||||||
|
'地铁': '🚇',
|
||||||
|
'公交': '🚌',
|
||||||
|
'救护车': '🚑',
|
||||||
|
'消防车': '🚒',
|
||||||
|
'警车': '🚓',
|
||||||
|
'出租车': '🚕',
|
||||||
|
'汽车': '🚗',
|
||||||
|
'货车': '🚛',
|
||||||
|
'自行车': '🚲',
|
||||||
|
'摩托': '🛵',
|
||||||
|
'红绿灯': '🚥',
|
||||||
|
'帆船': '⛵',
|
||||||
|
'游轮': '🛳️',
|
||||||
|
'轮船': '⛴️',
|
||||||
|
'飞机': '✈️',
|
||||||
|
'直升机': '🚁',
|
||||||
|
'缆车': '🚠',
|
||||||
|
'警告': '⚠️',
|
||||||
|
'禁止': '⛔'
|
||||||
|
}
|
||||||
|
module.exports = {
|
||||||
|
parseEmoji: (text) => text.replace(reg, ($, $1) => {
|
||||||
|
if (data[$1]) {
|
||||||
|
if (data[$1].includes('http'))
|
||||||
|
return `<img src="${data[$1]}" style="width:16px;height:16px;display:inline-block" ignore>`;
|
||||||
|
else return data[$1];
|
||||||
|
} else return $;
|
||||||
|
}),
|
||||||
|
getEmoji: (key) => data[key],
|
||||||
|
setEmoji: (key, emoji) => data[key] = emoji,
|
||||||
|
removeEmoji: (key) => data[key] = void 0
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,81 @@
|
||||||
|
/* PrismJS 1.19.0
|
||||||
|
https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript */
|
||||||
|
/**
|
||||||
|
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
|
||||||
|
* Based on https://github.com/chriskempson/tomorrow-theme
|
||||||
|
* @author Rose Pritchard
|
||||||
|
*/
|
||||||
|
|
||||||
|
.token.comment,
|
||||||
|
.token.block-comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.tag,
|
||||||
|
.token.attr-name,
|
||||||
|
.token.namespace,
|
||||||
|
.token.deleted {
|
||||||
|
color: #e2777a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.function-name {
|
||||||
|
color: #6196cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.boolean,
|
||||||
|
.token.number,
|
||||||
|
.token.function {
|
||||||
|
color: #f08d49;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.class-name,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol {
|
||||||
|
color: #f8c555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.important,
|
||||||
|
.token.atrule,
|
||||||
|
.token.keyword,
|
||||||
|
.token.builtin {
|
||||||
|
color: #cc99cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.string,
|
||||||
|
.token.char,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.regex,
|
||||||
|
.token.variable {
|
||||||
|
color: #7ec699;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.token.url {
|
||||||
|
color: #67cdcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important,
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.inserted {
|
||||||
|
color: green;
|
||||||
|
}
|
|
@ -0,0 +1,312 @@
|
||||||
|
/*
|
||||||
|
parser 主组件
|
||||||
|
github:https://github.com/jin-yufeng/Parser
|
||||||
|
docs:https://jin-yufeng.github.io/Parser
|
||||||
|
author:JinYufeng
|
||||||
|
update:2020/04/25
|
||||||
|
*/
|
||||||
|
var cache = {},
|
||||||
|
Parser = require('./libs/MpHtmlParser.js'),
|
||||||
|
fs = wx.getFileSystemManager && wx.getFileSystemManager();
|
||||||
|
try {
|
||||||
|
var dom = require('./libs/document.js');
|
||||||
|
} catch (e) {}
|
||||||
|
// 计算 cache 的 key
|
||||||
|
function hash(str) {
|
||||||
|
for (var i = str.length, val = 5381; i--;)
|
||||||
|
val += (val << 5) + str.charCodeAt(i);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
Component({
|
||||||
|
options: {
|
||||||
|
pureDataPattern: /^[acdgtux]|W/
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
'html': {
|
||||||
|
type: null,
|
||||||
|
observer(html) {
|
||||||
|
if (this._refresh) this._refresh = false;
|
||||||
|
else this.setContent(html, false, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'autosetTitle': {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
'autopause': {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
'compress': Number,
|
||||||
|
'domain': String,
|
||||||
|
'gestureZoom': Boolean,
|
||||||
|
'lazyLoad': Boolean,
|
||||||
|
'selectable': Boolean,
|
||||||
|
'tagStyle': Object,
|
||||||
|
'showWithAnimation': Boolean,
|
||||||
|
'useAnchor': Boolean,
|
||||||
|
'useCache': Boolean,
|
||||||
|
'xml': Boolean
|
||||||
|
},
|
||||||
|
relations: {
|
||||||
|
'../parser-group/parser-group': {
|
||||||
|
type: 'ancestor'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 图片数组
|
||||||
|
this.imgList = [];
|
||||||
|
this.imgList.setItem = function (i, src) {
|
||||||
|
if (!i || !src) return;
|
||||||
|
// 去重
|
||||||
|
if (src.indexOf('http') == 0 && this.includes(src)) {
|
||||||
|
var newSrc = '';
|
||||||
|
for (var j = 0, c; c = src[j]; j++) {
|
||||||
|
if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
|
||||||
|
newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
|
||||||
|
}
|
||||||
|
newSrc += src.substr(j);
|
||||||
|
return this[i] = newSrc;
|
||||||
|
}
|
||||||
|
this[i] = src;
|
||||||
|
// 暂存 data src
|
||||||
|
if (src.includes('data:image')) {
|
||||||
|
var info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
|
||||||
|
if (!info) return;
|
||||||
|
var filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
|
||||||
|
fs && fs.writeFile({
|
||||||
|
filePath,
|
||||||
|
data: info[3],
|
||||||
|
encoding: info[2],
|
||||||
|
success: () => this[i] = filePath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.imgList.each = function (f) {
|
||||||
|
for (var i = 0, len = this.length; i < len; i++)
|
||||||
|
this.setItem(i, f(this[i], i, this));
|
||||||
|
}
|
||||||
|
if (dom) this.document = new dom(this);
|
||||||
|
},
|
||||||
|
detached() {
|
||||||
|
// 删除暂存
|
||||||
|
this.imgList.each(src => {
|
||||||
|
if (src && src.includes(wx.env.USER_DATA_PATH) && fs)
|
||||||
|
fs.unlink({
|
||||||
|
filePath: src
|
||||||
|
})
|
||||||
|
})
|
||||||
|
clearInterval(this._timer);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 锚点跳转
|
||||||
|
navigateTo(obj) {
|
||||||
|
if (!this.data.useAnchor)
|
||||||
|
return obj.fail && obj.fail({
|
||||||
|
errMsg: 'Anchor is disabled'
|
||||||
|
})
|
||||||
|
this.createSelectorQuery()
|
||||||
|
.select('.top' + (obj.id ? '>>>#' + obj.id : '')).boundingClientRect()
|
||||||
|
.selectViewport().scrollOffset().exec(res => {
|
||||||
|
if (!res[0])
|
||||||
|
return this.group ? this.group.navigateTo(this.i, obj) :
|
||||||
|
obj.fail && obj.fail({
|
||||||
|
errMsg: 'Label not found'
|
||||||
|
});
|
||||||
|
obj.scrollTop = res[1].scrollTop + res[0].top + (obj.offset || 0);
|
||||||
|
wx.pageScrollTo(obj);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取文本
|
||||||
|
getText(ns = this.data.html) {
|
||||||
|
var txt = '';
|
||||||
|
for (var i = 0, n; n = ns[i++];) {
|
||||||
|
if (n.type == 'text') txt += n.text.replace(/ /g, '\u00A0').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
||||||
|
else if (n.type == 'br') txt += '\n';
|
||||||
|
else {
|
||||||
|
// 块级标签前后加换行
|
||||||
|
var br = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] > '0' && n.name[1] < '7');
|
||||||
|
if (br && txt && txt[txt.length - 1] != '\n') txt += '\n';
|
||||||
|
if (n.children) txt += this.getText(n.children);
|
||||||
|
if (br && txt[txt.length - 1] != '\n') txt += '\n';
|
||||||
|
else if (n.name == 'td' || n.name == 'th') txt += '\t';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return txt;
|
||||||
|
},
|
||||||
|
// 获取视频 context
|
||||||
|
getVideoContext(id) {
|
||||||
|
if (!id) return this.videoContexts;
|
||||||
|
for (var i = this.videoContexts.length; i--;)
|
||||||
|
if (this.videoContexts[i].id == id) return this.videoContexts[i];
|
||||||
|
},
|
||||||
|
// 渲染富文本
|
||||||
|
setContent(html, append, _watch) {
|
||||||
|
var data = {};
|
||||||
|
if (!html) {
|
||||||
|
if (_watch || append) return;
|
||||||
|
data.html = '';
|
||||||
|
} else if (typeof html == 'string') {
|
||||||
|
let parser = new Parser(html, this.data);
|
||||||
|
// 缓存读取
|
||||||
|
if (this.data.useCache) {
|
||||||
|
var hashVal = hash(html);
|
||||||
|
if (cache[hashVal]) data.html = cache[hashVal];
|
||||||
|
else {
|
||||||
|
data.html = parser.parse();
|
||||||
|
cache[hashVal] = data.html;
|
||||||
|
}
|
||||||
|
} else data.html = parser.parse();
|
||||||
|
this._refresh = true;
|
||||||
|
this.triggerEvent('parse', data.html);
|
||||||
|
} else if (html.constructor == Array) {
|
||||||
|
// 转换不符合格式的 array
|
||||||
|
if (html.length && html[0].PoweredBy != 'Parser') {
|
||||||
|
let parser = new Parser('', this.data);
|
||||||
|
(function f(ns) {
|
||||||
|
for (var i = 0, n; n = ns[i]; i++) {
|
||||||
|
if (n.type == 'text') continue;
|
||||||
|
n.attrs = n.attrs || {};
|
||||||
|
for (var key in n.attrs)
|
||||||
|
if (typeof n.attrs[key] != 'string') n.attrs[key] = n.attrs[key].toString();
|
||||||
|
parser.matchAttr(n);
|
||||||
|
if (n.children) {
|
||||||
|
parser.STACK.push(n);
|
||||||
|
f(n.children);
|
||||||
|
parser.popNode(parser.STACK.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(html);
|
||||||
|
data.html = html;
|
||||||
|
}
|
||||||
|
if (!_watch) data.html = html;
|
||||||
|
} else if (typeof html == 'object' && html.nodes) {
|
||||||
|
data.html = html.nodes;
|
||||||
|
console.warn('错误的 html 类型:object 类型已废弃');
|
||||||
|
} else
|
||||||
|
return console.warn('错误的 html 类型:' + typeof html);
|
||||||
|
if (append) {
|
||||||
|
this._refresh = true;
|
||||||
|
data.html = (this.data.html || []).concat(data.html);
|
||||||
|
} else if (this.data.showWithAnimation) data.showAm = 'animation: show .5s';
|
||||||
|
if (data.html || data.showAm) this.setData(data);
|
||||||
|
// 设置标题
|
||||||
|
if (this.data.html.length && this.data.html[0].title && this.data.autosetTitle)
|
||||||
|
wx.setNavigationBarTitle({
|
||||||
|
title: this.data.html[0].title
|
||||||
|
})
|
||||||
|
this.imgList.length = 0;
|
||||||
|
this.videoContexts = [];
|
||||||
|
var ns = this.selectAllComponents('.top,.top>>>._node');
|
||||||
|
for (let i = 0, n; n = ns[i++];) {
|
||||||
|
n.top = this;
|
||||||
|
for (var j = 0, item; item = n.data.nodes[j++];) {
|
||||||
|
if (item.c) continue;
|
||||||
|
// 获取图片列表
|
||||||
|
if (item.name == 'img')
|
||||||
|
this.imgList.setItem(item.attrs.i, item.attrs.src);
|
||||||
|
// 音视频控制
|
||||||
|
else if (item.name == 'video' || item.name == 'audio') {
|
||||||
|
var ctx;
|
||||||
|
if (item.name == 'video') ctx = wx.createVideoContext(item.attrs.id, n);
|
||||||
|
else ctx = n.selectComponent('#' + item.attrs.id);
|
||||||
|
if (ctx) {
|
||||||
|
ctx.id = item.attrs.id;
|
||||||
|
this.videoContexts.push(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(wx.nextTick || setTimeout)(() => this.triggerEvent('load'), 50);
|
||||||
|
var height;
|
||||||
|
clearInterval(this._timer);
|
||||||
|
this._timer = setInterval(() => {
|
||||||
|
this.createSelectorQuery().select('.top').boundingClientRect(res => {
|
||||||
|
this.rect = res;
|
||||||
|
if (res.height == height) {
|
||||||
|
this.triggerEvent('ready', res)
|
||||||
|
clearInterval(this._timer);
|
||||||
|
}
|
||||||
|
height = res.height;
|
||||||
|
}).exec();
|
||||||
|
}, 350)
|
||||||
|
},
|
||||||
|
// 预加载
|
||||||
|
preLoad(html, num) {
|
||||||
|
if (typeof html == 'string') {
|
||||||
|
var id = hash(html);
|
||||||
|
html = new Parser(html, this.data).parse();
|
||||||
|
cache[id] = html;
|
||||||
|
}
|
||||||
|
var imgs, wait = [];
|
||||||
|
(function f(ns) {
|
||||||
|
for (var i = 0, n; n = ns[i++];) {
|
||||||
|
if (n.name == 'img' && n.attrs.src && !wait.includes(n.attrs.src))
|
||||||
|
wait.push(n.attrs.src);
|
||||||
|
f(n.children || []);
|
||||||
|
}
|
||||||
|
})(html);
|
||||||
|
if (num) wait = wait.slice(0, num);
|
||||||
|
this._wait = (this._wait || []).concat(wait);
|
||||||
|
if (!this.data.imgs) imgs = this._wait.splice(0, 15);
|
||||||
|
else if (this.data.imgs.length < 15)
|
||||||
|
imgs = this.data.imgs.concat(this._wait.splice(0, 15 - this.data.imgs.length));
|
||||||
|
imgs && this.setData({
|
||||||
|
imgs
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_load(e) {
|
||||||
|
if (this._wait.length)
|
||||||
|
this.setData({
|
||||||
|
[`imgs[${e.target.id}]`]: this._wait.shift()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 事件处理
|
||||||
|
_tap(e) {
|
||||||
|
if (this.data.gestureZoom && e.timeStamp - this._lastT < 300) {
|
||||||
|
var initY = e.detail.y - e.currentTarget.offsetTop;
|
||||||
|
if (this._zoom) {
|
||||||
|
this._scaleAm.translateX(0).scale(1).step();
|
||||||
|
wx.pageScrollTo({
|
||||||
|
scrollTop: (initY + this._initY) / 2 - e.touches[0].clientY,
|
||||||
|
duration: 400
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
var initX = e.detail.x - e.currentTarget.offsetLeft;
|
||||||
|
this._initY = initY;
|
||||||
|
this._scaleAm = wx.createAnimation({
|
||||||
|
transformOrigin: `${initX}px ${this._initY}px 0`,
|
||||||
|
timingFunction: 'ease-in-out'
|
||||||
|
});
|
||||||
|
this._scaleAm.scale(2).step();
|
||||||
|
this._tMax = initX / 2;
|
||||||
|
this._tMin = (initX - this.rect.width) / 2;
|
||||||
|
this._tX = 0;
|
||||||
|
}
|
||||||
|
this._zoom = !this._zoom;
|
||||||
|
this.setData({
|
||||||
|
scaleAm: this._scaleAm.export()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this._lastT = e.timeStamp;
|
||||||
|
},
|
||||||
|
_touchstart(e) {
|
||||||
|
if (e.touches.length == 1)
|
||||||
|
this._initX = this._lastX = e.touches[0].pageX;
|
||||||
|
},
|
||||||
|
_touchmove(e) {
|
||||||
|
var diff = e.touches[0].pageX - this._lastX;
|
||||||
|
if (this._zoom && e.touches.length == 1 && Math.abs(diff) > 20) {
|
||||||
|
this._lastX = e.touches[0].pageX;
|
||||||
|
if ((this._tX <= this._tMin && diff < 0) || (this._tX >= this._tMax && diff > 0)) return;
|
||||||
|
this._tX += diff * Math.abs(this._lastX - this._initX) * 0.05;
|
||||||
|
if (this._tX < this._tMin) this._tX = this._tMin;
|
||||||
|
if (this._tX > this._tMax) this._tX = this._tMax;
|
||||||
|
this._scaleAm.translateX(this._tX).step();
|
||||||
|
this.setData({
|
||||||
|
scaleAm: this._scaleAm.export()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"trees": "./trees/trees"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<!--parser 主组件-->
|
||||||
|
<slot wx:if="{{!html[0].name&&!html[0].type}}" />
|
||||||
|
<trees class="top" style="{{selectable?'user-select:text;-webkit-user-select:text;':''}}{{showAm}}" animation="{{scaleAm}}" lazy-load="{{lazyLoad}}" nodes="{{html[0].name||html[0].type?html:[]}}" bindtap="_tap" bindtouchstart="_touchstart" bindtouchmove="_touchmove" />
|
||||||
|
<image wx:for="{{imgs}}" wx:key="index" id="{{index}}" src="{{item}}" hidden bindload="_load" />
|
|
@ -0,0 +1,16 @@
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
overflow: scroll;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
.top {
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
@keyframes show {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
trees 递归子组件
|
||||||
|
github:https://github.com/jin-yufeng/Parser
|
||||||
|
docs:https://jin-yufeng.github.io/Parser
|
||||||
|
author:JinYufeng
|
||||||
|
update:2020/04/25
|
||||||
|
*/
|
||||||
|
Component({
|
||||||
|
data: {
|
||||||
|
canIUse: !!wx.chooseMessageFile,
|
||||||
|
placeholder: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='225'/>",
|
||||||
|
inlineTags: require('../libs/config.js').inlineTags
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
nodes: Array,
|
||||||
|
lazyLoad: Boolean
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 自定义事件
|
||||||
|
copyCode(e) {
|
||||||
|
wx.showActionSheet({
|
||||||
|
itemList: ['复制代码'],
|
||||||
|
success: () =>
|
||||||
|
wx.setClipboardData({
|
||||||
|
data: e.target.dataset.content
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 视频播放事件
|
||||||
|
play(e) {
|
||||||
|
this.top.group && this.top.group.pause(this.top.i);
|
||||||
|
if (this.top.videoContexts.length > 1 && this.top.data.autopause)
|
||||||
|
for (var i = this.top.videoContexts.length; i--;)
|
||||||
|
if (this.top.videoContexts[i].id != e.currentTarget.id)
|
||||||
|
this.top.videoContexts[i].pause();
|
||||||
|
},
|
||||||
|
// 图片事件
|
||||||
|
imgtap(e) {
|
||||||
|
var attrs = e.currentTarget.dataset.attrs;
|
||||||
|
if (!attrs.ignore) {
|
||||||
|
var preview = true;
|
||||||
|
this.top.triggerEvent('imgtap', {
|
||||||
|
id: e.currentTarget.id,
|
||||||
|
src: attrs.src,
|
||||||
|
ignore: () => preview = false
|
||||||
|
})
|
||||||
|
if (preview) {
|
||||||
|
if (this.top.group) return this.top.group.preview(this.top.i, attrs.i);
|
||||||
|
var urls = this.top.imgList,
|
||||||
|
current = urls[attrs.i] ? urls[attrs.i] : (urls = [attrs.src], attrs.src);
|
||||||
|
wx.previewImage({
|
||||||
|
current,
|
||||||
|
urls
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadImg(e) {
|
||||||
|
var i = e.target.dataset.i;
|
||||||
|
if (this.data.lazyLoad && !this.data.nodes[i].load)
|
||||||
|
this.setData({
|
||||||
|
[`nodes[${i}].load`]: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 链接点击事件
|
||||||
|
linkpress(e) {
|
||||||
|
var jump = true,
|
||||||
|
attrs = e.currentTarget.dataset.attrs;
|
||||||
|
attrs.ignore = () => jump = false;
|
||||||
|
this.top.triggerEvent('linkpress', attrs);
|
||||||
|
if (jump) {
|
||||||
|
if (attrs['app-id'])
|
||||||
|
wx.navigateToMiniProgram({
|
||||||
|
appId: attrs['app-id'],
|
||||||
|
path: attrs.path
|
||||||
|
})
|
||||||
|
else if (attrs.href) {
|
||||||
|
if (attrs.href[0] == '#')
|
||||||
|
this.top.navigateTo({
|
||||||
|
id: attrs.href.substring(1)
|
||||||
|
})
|
||||||
|
else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0)
|
||||||
|
wx.setClipboardData({
|
||||||
|
data: attrs.href,
|
||||||
|
success: () =>
|
||||||
|
wx.showToast({
|
||||||
|
title: '链接已复制'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
else
|
||||||
|
wx.navigateTo({
|
||||||
|
url: attrs.href,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 错误事件
|
||||||
|
error(e) {
|
||||||
|
var context, source = e.target.dataset.source,
|
||||||
|
i = e.target.dataset.i,
|
||||||
|
node = this.data.nodes[i];
|
||||||
|
if (source == 'video' || source == 'audio') {
|
||||||
|
// 加载其他 source
|
||||||
|
var index = (node.i || 0) + 1;
|
||||||
|
if (index < node.attrs.source.length)
|
||||||
|
return this.setData({
|
||||||
|
[`nodes[${i}].i`]: index
|
||||||
|
})
|
||||||
|
if (this.top) context = this.top.getVideoContext(e.target.id);
|
||||||
|
} else if (source == 'img')
|
||||||
|
context = {
|
||||||
|
setSrc: src => {
|
||||||
|
this.setData({
|
||||||
|
[`nodes[${i}].attrs.src`]: src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.top && this.top.triggerEvent('error', {
|
||||||
|
source,
|
||||||
|
target: e.target,
|
||||||
|
context,
|
||||||
|
...e.detail
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 加载视频
|
||||||
|
loadVideo(e) {
|
||||||
|
var i = e.target.dataset.i;
|
||||||
|
this.setData({
|
||||||
|
[`nodes[${i}].lazyLoad`]: false,
|
||||||
|
[`nodes[${i}].attrs.autoplay`]: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"trees": "./trees",
|
||||||
|
"myAudio": "../audio/audio"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!--trees 递归子组件-->
|
||||||
|
<wxs module="handler">
|
||||||
|
module.exports = {
|
||||||
|
visited: function (e, owner) {
|
||||||
|
if (!e.instance.hasClass('_visited'))
|
||||||
|
e.instance.addClass('_visited')
|
||||||
|
owner.callMethod('linkpress', e);
|
||||||
|
},
|
||||||
|
useRichText: function (item, inlineTags) {
|
||||||
|
return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</wxs>
|
||||||
|
<block wx:for="{{nodes}}" wx:key="index" wx:for-item="n">
|
||||||
|
<!--图片-->
|
||||||
|
<view wx:if="{{n.name=='img'}}" id="{{n.attrs.id}}" class="_img {{n.attrs.class}}" style="{{n.attrs.style}}" data-attrs="{{n.attrs}}" bindtap="imgtap">
|
||||||
|
<rich-text nodes="{{[{attrs:{src:lazyLoad&&!n.load?placeholder:n.attrs.src,alt:n.attrs.alt||'',width:n.attrs.width||'',style:'max-width:100%;display:inherit'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]}}" />
|
||||||
|
<image class="_image" src="{{lazyLoad&&!n.load?placeholder:n.attrs.src}}" lazy-load="{{lazyLoad}}" show-menu-by-longpress="{{!n.attrs.ignore}}" data-i="{{index}}" data-source="img" bindload="loadImg" binderror="error" />
|
||||||
|
</view>
|
||||||
|
<!--文本-->
|
||||||
|
<text wx:elif="{{n.type=='text'}}" decode>{{n.text}}</text>
|
||||||
|
<text wx:elif="{{n.name=='br'}}">\n</text>
|
||||||
|
<!--链接-->
|
||||||
|
<view wx:elif="{{n.name=='a'}}" class="_a {{n.attrs.class}}" hover-class="_hover" style="{{n.attrs.style}}" data-attrs="{{n.attrs}}" bindtap="{{canIUse?handler.visited:'linkpress'}}">
|
||||||
|
<trees nodes="{{n.children}}" />
|
||||||
|
</view>
|
||||||
|
<!--视频-->
|
||||||
|
<block wx:elif="{{n.name=='video'}}">
|
||||||
|
<view wx:if="{{n.lazyLoad}}" id="{{n.attrs.id}}" class="_video {{n.attrs.class}}" style="{{n.attrs.style}}" data-i="{{index}}" bindtap="loadVideo" />
|
||||||
|
<video wx:else id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" autoplay="{{n.attrs.autoplay}}" controls="{{n.attrs.controls}}" loop="{{n.attrs.loop}}" muted="{{n.attrs.muted}}" poster="{{n.attrs.poster}}" src="{{n.attrs.source[n.i||0]}}" unit-id="{{n.attrs['unit-id']}}" data-i="{{index}}" data-source="video" binderror="error" bindplay="play" />
|
||||||
|
</block>
|
||||||
|
<!--音频-->
|
||||||
|
<myAudio wx:elif="{{n.name=='audio'}}" id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" author="{{n.attrs.author}}" autoplay="{{n.attrs.autoplay}}" controls="{{n.attrs.controls}}" loop="{{n.attrs.loop}}" name="{{n.attrs.name}}" poster="{{n.attrs.poster}}" src="{{n.attrs.source[n.i||0]}}" data-i="{{index}}" data-source="audio" binderror="error" bindplay="play" />
|
||||||
|
<!--广告-->
|
||||||
|
<ad wx:elif="{{n.name=='ad'}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" unit-id="{{n.attrs['unit-id']}}" data-source="ad" binderror="error" />
|
||||||
|
<!--列表-->
|
||||||
|
<view wx:elif="{{n.name=='li'}}" class="{{n.attrs.class}}" style="{{n.attrs.style}};display:flex">
|
||||||
|
<view wx:if="{{n.type=='ol'}}" class="_ol-bef">{{n.num}}</view>
|
||||||
|
<view wx:else class="_ul-bef">
|
||||||
|
<view wx:if="{{n.floor%3==0}}" class="_ul-p1">█</view>
|
||||||
|
<view wx:elif="{{n.floor%3==2}}" class="_ul-p2" />
|
||||||
|
<view wx:else class="_ul-p1" style="border-radius:50%">█</view>
|
||||||
|
</view>
|
||||||
|
<trees class="_node _li" lazy-load="{{lazyLoad}}" nodes="{{n.children}}" />
|
||||||
|
</view>
|
||||||
|
<!--自定义标签-->
|
||||||
|
<rich-text wx:elif="{{n.name=='pre'}}" class="_p" nodes="{{[n]}}" data-content="{{n.attrs['data-content']}}" bindlongpress="copyCode" />
|
||||||
|
<!--富文本-->
|
||||||
|
<rich-text wx:elif="{{handler.useRichText(n, inlineTags)}}" id="{{n.attrs.id}}" class="_p __{{n.name}}" nodes="{{[n]}}" />
|
||||||
|
<!--继续递归-->
|
||||||
|
<trees wx:else id="{{n.attrs.id}}" class="_node _{{n.name}} {{n.attrs.class}}" style="{{n.attrs.style}}" lazy-load="{{lazyLoad}}" nodes="{{n.children}}" />
|
||||||
|
</block>
|
|
@ -0,0 +1,136 @@
|
||||||
|
/* 在这里引入自定义样式 */
|
||||||
|
@import "../libs/prism.wxss";
|
||||||
|
|
||||||
|
/* 链接和图片效果 */
|
||||||
|
._a {
|
||||||
|
color: #366092;
|
||||||
|
display: inline;
|
||||||
|
padding: 1.5px 0 1.5px 0;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
._hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
._visited {
|
||||||
|
color: #551a8b;
|
||||||
|
}
|
||||||
|
._img {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
/* 内部样式 */
|
||||||
|
:host {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
._blockquote, ._div, ._p, ._ul, ._ol, ._li {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
._b, ._strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
._code {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
._del {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
._em, ._i {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
._h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
._h2 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
._h3 {
|
||||||
|
font-size: 1.17em;
|
||||||
|
}
|
||||||
|
._h5 {
|
||||||
|
font-size: 0.83em;
|
||||||
|
}
|
||||||
|
._h6 {
|
||||||
|
font-size: 0.67em;
|
||||||
|
}
|
||||||
|
._h1, ._h2, ._h3, ._h4, ._h5, ._h6 {
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
._image {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
._ins {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
._li {
|
||||||
|
flex: 1;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
._ol-bef {
|
||||||
|
margin-right: 5px;
|
||||||
|
text-align: right;
|
||||||
|
width: 36px;
|
||||||
|
}
|
||||||
|
._ul-bef {
|
||||||
|
line-height: normal;
|
||||||
|
margin: 0 12px 0 23px;
|
||||||
|
}
|
||||||
|
._ol-bef, ._ul_bef {
|
||||||
|
flex: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
._ul-p1 {
|
||||||
|
display: inline-block;
|
||||||
|
height: 0.3em;
|
||||||
|
line-height: 0.3em;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 0.3em;
|
||||||
|
}
|
||||||
|
._ul-p2 {
|
||||||
|
border: 0.05em solid black;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
height: 0.23em;
|
||||||
|
width: 0.23em;
|
||||||
|
}
|
||||||
|
._q::before {
|
||||||
|
content: '"';
|
||||||
|
}
|
||||||
|
._q::after {
|
||||||
|
content: '"';
|
||||||
|
}
|
||||||
|
._sub {
|
||||||
|
font-size: smaller;
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
._sup {
|
||||||
|
font-size: smaller;
|
||||||
|
vertical-align: super;
|
||||||
|
}
|
||||||
|
.__bdi, .__bdo, .__ruby, .__rt {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
._video {
|
||||||
|
background-color: black;
|
||||||
|
display: inline-block;
|
||||||
|
height: 225px;
|
||||||
|
position: relative;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
._video::after {
|
||||||
|
border-color: transparent transparent transparent white;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 15px 0 15px 30px;
|
||||||
|
content: '';
|
||||||
|
left: 50%;
|
||||||
|
margin: -15px 0 0 -15px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
}
|
|
@ -6,7 +6,8 @@ Page({
|
||||||
* 页面的初始数据
|
* 页面的初始数据
|
||||||
*/
|
*/
|
||||||
data: {
|
data: {
|
||||||
elink_f:''
|
elink_f:'',
|
||||||
|
domain:getApp().globalData.mediahost
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +69,7 @@ Page({
|
||||||
getDetail: function (id) {
|
getDetail: function (id) {
|
||||||
var that = this
|
var that = this
|
||||||
api.request(`/cms/article/${id}/`,'GET').then(res => {
|
api.request(`/cms/article/${id}/`,'GET').then(res => {
|
||||||
|
// res.data.content = res.data.content.replace(/"media/g, '"'+getApp().globalData.mediahost + '/media').replace(/\<img/gi, '<img style="max-width:100%;height:auto" ')
|
||||||
that.setData(res.data)
|
that.setData(res.data)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
{
|
{
|
||||||
"usingComponents": {}
|
"usingComponents": {
|
||||||
|
"parser": "/components/parser/parser"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,16 @@
|
||||||
<view class="page">
|
<web-view src="elink" wx:if="{{elink}}"></web-view>
|
||||||
|
<view class="page" wx:else>
|
||||||
<view class="page__hd" style="padding:20px">
|
<view class="page__hd" style="padding:20px">
|
||||||
<view class="page__title" >{{title}}</view>
|
<view class="page__title" >{{title}}</view>
|
||||||
<view class="page__desc">
|
<view class="page__desc">
|
||||||
<span style="font-weight:bold;color:darkblue;font-size:16px">{{ifrom}} </span>
|
<span style="font-weight:bold;color:darkblue;font-size:16px">{{ifrom}} </span>
|
||||||
<text class="weui-badge" style="background:orange" wx:if="{{is_top}}">置顶</text>
|
<text class="weui-badge" style="background:orange" wx:if="{{is_top}}">置顶</text>
|
||||||
<text class="weui-badge" style="background:green" wx:if="{{!elink}}">原创</text>
|
<text class="weui-badge" style="background:green" >原创</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="page__bd">
|
<view class="page__bd">
|
||||||
<view class="weui-article">
|
<view class="weui-article">
|
||||||
<rich-text nodes="{{content}}"></rich-text>
|
<parser html="{{content}}" domain="{{domain}}"/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
|
@ -11,10 +11,7 @@
|
||||||
<view class="weui-media-box__bd">
|
<view class="weui-media-box__bd">
|
||||||
<h4 class="weui-media-box__title">{{item.name}}</h4>
|
<h4 class="weui-media-box__title">{{item.name}}</h4>
|
||||||
<view class="weui-media-box__desc">
|
<view class="weui-media-box__desc">
|
||||||
<span style="color:orange;font-weight:bold">{{item.type}}</span>
|
已答
|
||||||
--共
|
|
||||||
<span style="color:darkblue;font-weight:bold">{{item.tmtotal}}</span>
|
|
||||||
道/已答
|
|
||||||
<span style="color:darkblue;font-weight:bold">{{item.ydtmtotal}}</span>
|
<span style="color:darkblue;font-weight:bold">{{item.ydtmtotal}}</span>
|
||||||
道
|
道
|
||||||
</view>
|
</view>
|
||||||
|
|
|
@ -32,7 +32,7 @@ class Consumer(SoftCommonModel):
|
||||||
subjects = models.ManyToManyField(Questioncat, verbose_name='付费学科', through='PaySubject')
|
subjects = models.ManyToManyField(Questioncat, verbose_name='付费学科', through='PaySubject')
|
||||||
workscope = models.ForeignKey(WorkScope, verbose_name='工作类别', on_delete=models.SET_NULL, null=True, blank=True)
|
workscope = models.ForeignKey(WorkScope, verbose_name='工作类别', on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
collects = models.ManyToManyField(Question, verbose_name='收藏试题')
|
collects = models.ManyToManyField(Question, verbose_name='收藏试题')
|
||||||
remain_count = models.IntegerField('可考次数', default=1)
|
remain_count = models.IntegerField('体验次数', default=3)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
Loading…
Reference in New Issue