oxy-uni-ui 1.2.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/attributes.json +1 -1
- package/components/common/abstracts/variable.scss +51 -1
- package/components/common/path.ts +9 -0
- package/components/common/util.ts +42 -0
- package/components/composables/useGlobalLoading.ts +42 -0
- package/components/composables/useGlobalMessage.ts +48 -0
- package/components/composables/useGlobalToast.ts +84 -0
- package/components/composables/useVirtualScroll.ts +3 -2
- package/components/oxy-cell/oxy-cell.vue +15 -2
- package/components/oxy-cell/types.ts +4 -0
- package/components/oxy-checkbox/index.scss +1 -1
- package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
- package/components/oxy-col-picker/oxy-col-picker.vue +3 -0
- package/components/oxy-col-picker/types.ts +5 -1
- package/components/oxy-corner/oxy-corner.vue +15 -3
- package/components/oxy-corner/types.ts +15 -1
- package/components/oxy-date-strip/index.scss +10 -0
- package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
- package/components/oxy-date-strip/types.ts +98 -0
- package/components/oxy-date-strip/utils.ts +67 -0
- package/components/oxy-date-strip-item/index.scss +94 -0
- package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
- package/components/oxy-date-strip-item/types.ts +53 -0
- package/components/oxy-datetime-picker/oxy-datetime-picker.vue +3 -1
- package/components/oxy-datetime-picker/types.ts +5 -1
- package/components/oxy-echarts/index.scss +17 -0
- package/components/oxy-echarts/index.ts +1 -0
- package/components/oxy-echarts/oxy-echarts.vue +32 -0
- package/components/oxy-echarts/types.ts +12 -0
- package/components/oxy-file-list/index.scss +26 -0
- package/components/oxy-file-list/oxy-file-list.vue +208 -34
- package/components/oxy-file-list/types.ts +58 -2
- package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
- package/components/oxy-global-message/oxy-global-message.vue +64 -0
- package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
- package/components/oxy-img-lazy/index.scss +17 -0
- package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
- package/components/oxy-img-lazy/types.ts +69 -0
- package/components/oxy-link/index.scss +57 -0
- package/components/oxy-link/oxy-link.vue +130 -0
- package/components/oxy-link/types.ts +81 -0
- package/components/oxy-list/index.scss +7 -1
- package/components/oxy-list/types.ts +1 -1
- package/components/oxy-picker/oxy-picker.vue +3 -0
- package/components/oxy-picker/types.ts +5 -1
- package/components/oxy-radio/index.scss +3 -3
- package/components/oxy-radio/oxy-radio.vue +1 -1
- package/components/oxy-rich-text/icon/emjio.svg +1 -0
- package/components/oxy-rich-text/icon/quote.svg +1 -0
- package/components/oxy-rich-text/icon/text.svg +1 -0
- package/components/oxy-rich-text/icon/title.svg +1 -0
- package/components/oxy-rich-text/index.scss +159 -0
- package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
- package/components/oxy-rich-text/mp-html/card/index.js +7 -0
- package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
- package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
- package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
- package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
- package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
- package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
- package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
- package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
- package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
- package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
- package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
- package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
- package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
- package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
- package/components/oxy-rich-text/mp-html/mp-html.vue +675 -0
- package/components/oxy-rich-text/mp-html/node/node.vue +1161 -0
- package/components/oxy-rich-text/mp-html/parser.js +1428 -0
- package/components/oxy-rich-text/mp-html/search/index.js +132 -0
- package/components/oxy-rich-text/mp-html/style/index.js +129 -0
- package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
- package/components/oxy-rich-text/mp-html/template/index.js +67 -0
- package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
- package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
- package/components/oxy-rich-text/types.ts +71 -0
- package/components/oxy-select/index.scss +255 -0
- package/components/oxy-select/oxy-select.vue +421 -0
- package/components/oxy-select/types.ts +71 -0
- package/components/oxy-select-picker/oxy-select-picker.vue +3 -0
- package/components/oxy-select-picker/types.ts +5 -1
- package/components/oxy-stream-render/index.scss +6 -0
- package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
- package/components/oxy-stream-render/types.ts +5 -0
- package/components/oxy-tree/index.scss +17 -1
- package/components/oxy-tree/oxy-tree.vue +89 -8
- package/components/oxy-tree/types.ts +11 -1
- package/components/oxy-waterfall/index.scss +18 -0
- package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
- package/components/oxy-waterfall/types.ts +90 -0
- package/components/oxy-waterfall-item/index.scss +8 -0
- package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
- package/components/oxy-waterfall-item/types.ts +16 -0
- package/global.d.ts +7 -0
- package/index.ts +3 -0
- package/locale/lang/en-US.ts +26 -0
- package/locale/lang/zh-CN.ts +26 -0
- package/oxy-uni-ui.zip +0 -0
- package/package.json +1 -1
- package/tags.json +1 -1
- package/uni-echarts/changelog.md +2 -0
- package/uni-echarts/components/index.js +1 -0
- package/uni-echarts/components/uni-echarts/events.js +95 -0
- package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
- package/uni-echarts/components/uni-echarts/types.js +1 -0
- package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
- package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
- package/uni-echarts/global.d.ts +7 -0
- package/uni-echarts/index.d.ts +440 -0
- package/uni-echarts/index.js +2 -0
- package/uni-echarts/package.json +105 -0
- package/uni-echarts/shared-core.d.ts +269 -0
- package/uni-echarts/shared-core.js +900 -0
- package/web-types.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview search 插件
|
|
3
|
+
*/
|
|
4
|
+
function Search (vm) {
|
|
5
|
+
/**
|
|
6
|
+
* @description 关键词搜索
|
|
7
|
+
* @param {regexp|string} key 要搜索的关键词
|
|
8
|
+
* @param {boolean} anchor 是否将搜索结果设置为锚点
|
|
9
|
+
* @param {string} style 搜索结果的样式
|
|
10
|
+
*/
|
|
11
|
+
vm.search = function (key, anchor, style = 'background-color:yellow') {
|
|
12
|
+
const res = []
|
|
13
|
+
const stack = [];
|
|
14
|
+
|
|
15
|
+
// 遍历搜索
|
|
16
|
+
(function traversal (nodes) {
|
|
17
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
18
|
+
let node = nodes[i]
|
|
19
|
+
if (node.type === 'text' && key) {
|
|
20
|
+
const text = node.text
|
|
21
|
+
const arr = text.split(key)
|
|
22
|
+
if (arr.length > 1) {
|
|
23
|
+
node = {
|
|
24
|
+
name: 'span',
|
|
25
|
+
attrs: {},
|
|
26
|
+
type: 'node',
|
|
27
|
+
c: 1,
|
|
28
|
+
s: 1,
|
|
29
|
+
children: []
|
|
30
|
+
}
|
|
31
|
+
vm.$set(nodes, i, node)
|
|
32
|
+
for (let j = 0; j < arr.length; j++) {
|
|
33
|
+
if (arr[j]) {
|
|
34
|
+
node.children.push({
|
|
35
|
+
type: 'text',
|
|
36
|
+
text: arr[j]
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
if (j !== arr.length - 1) {
|
|
40
|
+
// 关键词转为一个 span
|
|
41
|
+
node.children.push({
|
|
42
|
+
name: 'span',
|
|
43
|
+
attrs: {
|
|
44
|
+
id: anchor ? 'search' + (res.length + 1) : undefined, // 用于锚点的 id
|
|
45
|
+
style: style
|
|
46
|
+
},
|
|
47
|
+
// #ifdef VUE3
|
|
48
|
+
c: 1,
|
|
49
|
+
// #endif
|
|
50
|
+
children: [{
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: key instanceof RegExp ? key.exec(text)[0] : key
|
|
53
|
+
}]
|
|
54
|
+
})
|
|
55
|
+
res.push(node.children[node.children.length - 1].attrs)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (key instanceof RegExp) {
|
|
59
|
+
key.exec(text)
|
|
60
|
+
}
|
|
61
|
+
if (anchor) {
|
|
62
|
+
for (let l = stack.length; l--;) {
|
|
63
|
+
if (stack[l].c) {
|
|
64
|
+
break
|
|
65
|
+
} else {
|
|
66
|
+
vm.$set(stack[l], 'c', 1)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} else if (node.s) {
|
|
72
|
+
let text = ''
|
|
73
|
+
// 复原上一次的结果
|
|
74
|
+
for (let k = 0; k < node.children.length; k++) {
|
|
75
|
+
const child = node.children[k]
|
|
76
|
+
if (child.text) {
|
|
77
|
+
text += child.text
|
|
78
|
+
} else {
|
|
79
|
+
text += child.children[0].text
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
vm.$set(nodes, i, {
|
|
83
|
+
type: 'text',
|
|
84
|
+
text
|
|
85
|
+
})
|
|
86
|
+
if (key && (key instanceof RegExp ? key.test(text) : text.includes(key))) {
|
|
87
|
+
i--
|
|
88
|
+
}
|
|
89
|
+
} else if (node.children) {
|
|
90
|
+
stack.push(node)
|
|
91
|
+
traversal(node.children)
|
|
92
|
+
stack.pop()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})(vm.nodes)
|
|
96
|
+
|
|
97
|
+
return new Promise(function (resolve) {
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
resolve({
|
|
100
|
+
num: res.length, // 结果数量
|
|
101
|
+
/**
|
|
102
|
+
* @description 高亮某一个结果
|
|
103
|
+
* @param {number} i 第几个
|
|
104
|
+
* @param {string} hlstyle 高亮的样式
|
|
105
|
+
*/
|
|
106
|
+
highlight (i, hlstyle = 'background-color:#FF9632') {
|
|
107
|
+
if (i < 1 || i > res.length) return
|
|
108
|
+
if (this.last) {
|
|
109
|
+
res[this.last - 1].style = style
|
|
110
|
+
}
|
|
111
|
+
this.last = i
|
|
112
|
+
res[i - 1].style = hlstyle
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* @description 跳转到搜索结果
|
|
116
|
+
* @param {number} i 第几个
|
|
117
|
+
* @param {number} offset 偏移量
|
|
118
|
+
*/
|
|
119
|
+
jump: anchor
|
|
120
|
+
? (i, offset) => {
|
|
121
|
+
if (i > 0 && i <= res.length) {
|
|
122
|
+
vm.navigateTo('search' + i, offset)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
: undefined
|
|
126
|
+
})
|
|
127
|
+
}, 200)
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default Search
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview style 插件
|
|
3
|
+
*/
|
|
4
|
+
// #ifndef APP-PLUS-NVUE
|
|
5
|
+
import Parser from './parser'
|
|
6
|
+
// #endif
|
|
7
|
+
|
|
8
|
+
function Style () {
|
|
9
|
+
this.styles = []
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// #ifndef APP-PLUS-NVUE
|
|
13
|
+
Style.prototype.onParse = function (node, vm) {
|
|
14
|
+
// 获取样式
|
|
15
|
+
if (node.name === 'style' && node.children.length && node.children[0].type === 'text') {
|
|
16
|
+
this.styles = this.styles.concat(new Parser().parse(node.children[0].text))
|
|
17
|
+
} else if (node.name) {
|
|
18
|
+
// 匹配样式(对非文本标签)
|
|
19
|
+
// 存储不同优先级的样式 name < class < id < 后代
|
|
20
|
+
let matched = ['', '', '', '']
|
|
21
|
+
for (let i = 0, len = this.styles.length; i < len; i++) {
|
|
22
|
+
const item = this.styles[i]
|
|
23
|
+
let res = match(node, item.key || item.list[item.list.length - 1])
|
|
24
|
+
let j
|
|
25
|
+
if (res) {
|
|
26
|
+
// 后代选择器
|
|
27
|
+
if (!item.key) {
|
|
28
|
+
j = item.list.length - 2
|
|
29
|
+
for (let k = vm.stack.length; j >= 0 && k--;) {
|
|
30
|
+
// 子选择器
|
|
31
|
+
if (item.list[j] === '>') {
|
|
32
|
+
// 错误情况
|
|
33
|
+
if (j < 1 || j > item.list.length - 2) break
|
|
34
|
+
if (match(vm.stack[k], item.list[j - 1])) {
|
|
35
|
+
j -= 2
|
|
36
|
+
} else {
|
|
37
|
+
j++
|
|
38
|
+
}
|
|
39
|
+
} else if (match(vm.stack[k], item.list[j])) {
|
|
40
|
+
j--
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
res = 4
|
|
44
|
+
}
|
|
45
|
+
if (item.key || j < 0) {
|
|
46
|
+
// 添加伪类
|
|
47
|
+
if (item.pseudo && node.children) {
|
|
48
|
+
let text
|
|
49
|
+
item.style = item.style.replace(/content:([^;]+)/, (_, $1) => {
|
|
50
|
+
text = $1.replace(/['"]/g, '')
|
|
51
|
+
// 处理 attr 函数
|
|
52
|
+
.replace(/attr\((.+?)\)/, (_, $1) => node.attrs[$1.trim()] || '')
|
|
53
|
+
// 编码 \xxx
|
|
54
|
+
.replace(/\\(\w{4})/, (_, $1) => String.fromCharCode(parseInt($1, 16)))
|
|
55
|
+
return ''
|
|
56
|
+
})
|
|
57
|
+
const pseudo = {
|
|
58
|
+
name: 'span',
|
|
59
|
+
attrs: {
|
|
60
|
+
style: item.style
|
|
61
|
+
},
|
|
62
|
+
children: [{
|
|
63
|
+
type: 'text',
|
|
64
|
+
text
|
|
65
|
+
}]
|
|
66
|
+
}
|
|
67
|
+
if (item.pseudo === 'before') {
|
|
68
|
+
node.children.unshift(pseudo)
|
|
69
|
+
} else {
|
|
70
|
+
node.children.push(pseudo)
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
matched[res - 1] += item.style + (item.style[item.style.length - 1] === ';' ? '' : ';')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
matched = matched.join('')
|
|
79
|
+
if (matched.length > 2) {
|
|
80
|
+
node.attrs.style = matched + (node.attrs.style || '')
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @description 匹配样式
|
|
87
|
+
* @param {object} node 要匹配的标签
|
|
88
|
+
* @param {string|string[]} keys 选择器
|
|
89
|
+
* @returns {number} 0:不匹配;1:name 匹配;2:class 匹配;3:id 匹配
|
|
90
|
+
*/
|
|
91
|
+
function match (node, keys) {
|
|
92
|
+
function matchItem (key) {
|
|
93
|
+
if (key[0] === '#') {
|
|
94
|
+
// 匹配 id
|
|
95
|
+
if (node.attrs.id && node.attrs.id.trim() === key.substr(1)) return 3
|
|
96
|
+
} else if (key[0] === '.') {
|
|
97
|
+
// 匹配 class
|
|
98
|
+
key = key.substr(1)
|
|
99
|
+
const selectors = (node.attrs.class || '').split(' ')
|
|
100
|
+
for (let i = 0; i < selectors.length; i++) {
|
|
101
|
+
if (selectors[i].trim() === key) return 2
|
|
102
|
+
}
|
|
103
|
+
} else if (node.name === key) {
|
|
104
|
+
// 匹配 name
|
|
105
|
+
return 1
|
|
106
|
+
}
|
|
107
|
+
return 0
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 多选择器交集
|
|
111
|
+
if (keys instanceof Array) {
|
|
112
|
+
let res = 0
|
|
113
|
+
for (let j = 0; j < keys.length; j++) {
|
|
114
|
+
const tmp = matchItem(keys[j])
|
|
115
|
+
// 任意一个不匹配就失败
|
|
116
|
+
if (!tmp) return 0
|
|
117
|
+
// 优先级最大的一个作为最终优先级
|
|
118
|
+
if (tmp > res) {
|
|
119
|
+
res = tmp
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return res
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return matchItem(keys)
|
|
126
|
+
}
|
|
127
|
+
// #endif
|
|
128
|
+
|
|
129
|
+
export default Style
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
const blank = {
|
|
2
|
+
' ': true,
|
|
3
|
+
'\n': true,
|
|
4
|
+
'\t': true,
|
|
5
|
+
'\r': true,
|
|
6
|
+
'\f': true
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function Parser () {
|
|
10
|
+
this.styles = []
|
|
11
|
+
this.selectors = []
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @description 解析 css 字符串
|
|
16
|
+
* @param {string} content css 内容
|
|
17
|
+
*/
|
|
18
|
+
Parser.prototype.parse = function (content) {
|
|
19
|
+
new Lexer(this).parse(content)
|
|
20
|
+
return this.styles
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @description 解析到一个选择器
|
|
25
|
+
* @param {string} name 名称
|
|
26
|
+
*/
|
|
27
|
+
Parser.prototype.onSelector = function (name) {
|
|
28
|
+
// 不支持的选择器
|
|
29
|
+
if (name.includes('[') || name.includes('*') || name.includes('@')) return
|
|
30
|
+
const selector = {}
|
|
31
|
+
// 伪类
|
|
32
|
+
if (name.includes(':')) {
|
|
33
|
+
const info = name.split(':')
|
|
34
|
+
const pseudo = info.pop()
|
|
35
|
+
if (pseudo === 'before' || pseudo === 'after') {
|
|
36
|
+
selector.pseudo = pseudo
|
|
37
|
+
name = info[0]
|
|
38
|
+
} else return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 分割交集选择器
|
|
42
|
+
function splitItem (str) {
|
|
43
|
+
const arr = []
|
|
44
|
+
let i, start
|
|
45
|
+
for (i = 1, start = 0; i < str.length; i++) {
|
|
46
|
+
if (str[i] === '.' || str[i] === '#') {
|
|
47
|
+
arr.push(str.substring(start, i))
|
|
48
|
+
start = i
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!arr.length) {
|
|
52
|
+
return str
|
|
53
|
+
} else {
|
|
54
|
+
arr.push(str.substring(start, i))
|
|
55
|
+
return arr
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 后代选择器
|
|
60
|
+
if (name.includes(' ')) {
|
|
61
|
+
selector.list = []
|
|
62
|
+
const list = name.split(' ')
|
|
63
|
+
for (let i = 0; i < list.length; i++) {
|
|
64
|
+
if (list[i].length) {
|
|
65
|
+
// 拆分子选择器
|
|
66
|
+
const arr = list[i].split('>')
|
|
67
|
+
for (let j = 0; j < arr.length; j++) {
|
|
68
|
+
selector.list.push(splitItem(arr[j]))
|
|
69
|
+
if (j < arr.length - 1) {
|
|
70
|
+
selector.list.push('>')
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
selector.key = splitItem(name)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.selectors.push(selector)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @description 解析到选择器内容
|
|
84
|
+
* @param {string} content 内容
|
|
85
|
+
*/
|
|
86
|
+
Parser.prototype.onContent = function (content) {
|
|
87
|
+
// 并集选择器
|
|
88
|
+
for (let i = 0; i < this.selectors.length; i++) {
|
|
89
|
+
this.selectors[i].style = content
|
|
90
|
+
}
|
|
91
|
+
this.styles = this.styles.concat(this.selectors)
|
|
92
|
+
this.selectors = []
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @description css 词法分析器
|
|
97
|
+
* @param {object} handler 高层处理器
|
|
98
|
+
*/
|
|
99
|
+
function Lexer (handler) {
|
|
100
|
+
this.selector = ''
|
|
101
|
+
this.style = ''
|
|
102
|
+
this.handler = handler
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
Lexer.prototype.parse = function (content) {
|
|
106
|
+
this.i = 0
|
|
107
|
+
this.content = content
|
|
108
|
+
this.state = this.blank
|
|
109
|
+
for (let len = content.length; this.i < len; this.i++) {
|
|
110
|
+
this.state(content[this.i])
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Lexer.prototype.comment = function () {
|
|
115
|
+
this.i = this.content.indexOf('*/', this.i) + 1
|
|
116
|
+
if (!this.i) {
|
|
117
|
+
this.i = this.content.length
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Lexer.prototype.blank = function (c) {
|
|
122
|
+
if (!blank[c]) {
|
|
123
|
+
if (c === '/' && this.content[this.i + 1] === '*') {
|
|
124
|
+
this.comment()
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
this.selector += c
|
|
128
|
+
this.state = this.name
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Lexer.prototype.name = function (c) {
|
|
133
|
+
if (c === '/' && this.content[this.i + 1] === '*') {
|
|
134
|
+
this.comment()
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
if (c === '{' || c === ',' || c === ';') {
|
|
138
|
+
this.handler.onSelector(this.selector.trimEnd())
|
|
139
|
+
this.selector = ''
|
|
140
|
+
if (c !== '{') {
|
|
141
|
+
while (blank[this.content[++this.i]]);
|
|
142
|
+
}
|
|
143
|
+
if (this.content[this.i] === '{') {
|
|
144
|
+
this.floor = 1
|
|
145
|
+
this.state = this.val
|
|
146
|
+
} else {
|
|
147
|
+
this.selector += this.content[this.i]
|
|
148
|
+
}
|
|
149
|
+
} else if (blank[c]) {
|
|
150
|
+
this.selector += ' '
|
|
151
|
+
} else {
|
|
152
|
+
this.selector += c
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Lexer.prototype.val = function (c) {
|
|
157
|
+
if (c === '/' && this.content[this.i + 1] === '*') {
|
|
158
|
+
this.comment()
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
if (c === '{') {
|
|
162
|
+
this.floor++
|
|
163
|
+
} else if (c === '}') {
|
|
164
|
+
this.floor--
|
|
165
|
+
if (!this.floor) {
|
|
166
|
+
this.handler.onContent(this.style)
|
|
167
|
+
this.style = ''
|
|
168
|
+
this.state = this.blank
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
this.style += c
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export default Parser
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview 插件入口文件模板
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const data = {} // 全局数据
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @description 组件被创建时将实例化插件
|
|
9
|
+
* @param {Component} vm 组件实例
|
|
10
|
+
*/
|
|
11
|
+
function Plugin (vm) {
|
|
12
|
+
this.vm = vm // 保存实例在其他周期使用
|
|
13
|
+
this.compData = {} // 仅在单个组件中使用的数据
|
|
14
|
+
data.xxx = 'xxx' // 记录全局数据
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @description html 数据更新时触发
|
|
19
|
+
* @param {string} content 要更新的 html 字符串
|
|
20
|
+
* @param {object} config 解析配置
|
|
21
|
+
* @returns {string|void} 如果要对 html 字符串进行一些预处理,则返回处理后的字符串
|
|
22
|
+
*/
|
|
23
|
+
Plugin.prototype.onUpdate = function (content, config) {
|
|
24
|
+
config.ignoreTags.xxx = true // 移除 xxx 标签
|
|
25
|
+
// 对 html 内容进行预处理并返回修改,没有修改则不需要返回
|
|
26
|
+
return content
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @description 解析到一个标签时触发
|
|
31
|
+
* @param {object} node 标签
|
|
32
|
+
* @param {object} parser 解析器实例
|
|
33
|
+
* @returns {boolean|void} 如果返回 false 将移除该标签
|
|
34
|
+
*/
|
|
35
|
+
Plugin.prototype.onParse = function (node, parser) {
|
|
36
|
+
// 处理文本标签
|
|
37
|
+
if (node.type === 'text') {
|
|
38
|
+
// node.text 文本内容
|
|
39
|
+
} else {
|
|
40
|
+
// 处理元素标签
|
|
41
|
+
// node.name 标签名
|
|
42
|
+
// node.attrs 属性列表
|
|
43
|
+
// node.children 子节点(非自闭合标签有)
|
|
44
|
+
|
|
45
|
+
if (node.name === 'xxx') {
|
|
46
|
+
parser.expose() // 如果该标签不能被 rich-text 包含,需要调用此方法暴露出来
|
|
47
|
+
// parser.options 组件传入的一些解析属性
|
|
48
|
+
// parser.stack 可以从栈中获取祖先节点
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @description dom 树加载完毕时触发(load 事件)
|
|
55
|
+
*/
|
|
56
|
+
Plugin.prototype.onLoad = function () {
|
|
57
|
+
// 可以获取媒体 context 对象等
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @description 组件被移除时触发
|
|
62
|
+
*/
|
|
63
|
+
Plugin.prototype.onDetached = function () {
|
|
64
|
+
// 可以释放一些必要的资源(计时器等)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default Plugin
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview txv-video 插件
|
|
3
|
+
* Include txv-video (https://github.com/tvfe/txv-miniprogram-plugin)
|
|
4
|
+
*/
|
|
5
|
+
const TxvVideo = function (vm) {
|
|
6
|
+
this.vm = vm
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// #ifdef MP-WEIXIN || MP-QQ
|
|
10
|
+
try {
|
|
11
|
+
const TxvContext = requirePlugin('tencentvideo')
|
|
12
|
+
|
|
13
|
+
TxvVideo.prototype.onLoad = function () {
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
for (let i = 0; i < this.videos.length; i++) {
|
|
16
|
+
const ctx = TxvContext.getTxvContext(this.videos[i])
|
|
17
|
+
ctx.id = this.videos[i]
|
|
18
|
+
this.vm._videos.push(ctx)
|
|
19
|
+
}
|
|
20
|
+
}, 50)
|
|
21
|
+
}
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.error('使用txv-video扩展需注册腾讯视频插件')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
TxvVideo.prototype.onUpdate = function (_, config) {
|
|
27
|
+
config.trustTags['txv-video'] = true
|
|
28
|
+
this.videos = []
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
TxvVideo.prototype.onParse = function (node, parser) {
|
|
32
|
+
if (node.name === 'iframe' && (node.attrs.src || '').includes('vid')) {
|
|
33
|
+
const vid = node.attrs.src.match(/vid=([^&\s]+)/)
|
|
34
|
+
if (vid) {
|
|
35
|
+
node.name = 'txv-video'
|
|
36
|
+
node.attrs.vid = vid[1]
|
|
37
|
+
this.videos.push(vid[1])
|
|
38
|
+
node.attrs.src = undefined
|
|
39
|
+
parser.expose()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// #endif
|
|
45
|
+
|
|
46
|
+
export default TxvVideo
|