Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
20岁爱吃必胜客
uni-app
提交
75d36c63
U
uni-app
项目概览
20岁爱吃必胜客
/
uni-app
与 Fork 源项目一致
Fork自
DCloud / uni-app
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
75d36c63
编写于
12月 06, 2019
作者:
Q
qiang
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'editor' into v3
上级
cc29d0ae
00b27668
变更
32
展开全部
隐藏空白更改
内联
并排
Showing
32 changed file
with
1158 addition
and
64 deletion
+1158
-64
docs/api/media/editor-context.md
docs/api/media/editor-context.md
+1
-1
docs/api/ui/nodes-info.md
docs/api/ui/nodes-info.md
+37
-37
docs/component/editor.md
docs/component/editor.md
+3
-3
lib/apis.js
lib/apis.js
+6
-6
lib/modules.json
lib/modules.json
+2
-2
packages/uni-cli-shared/lib/tags.js
packages/uni-cli-shared/lib/tags.js
+3
-2
packages/uni-cli-shared/template/v3/__uniappquill.js
packages/uni-cli-shared/template/v3/__uniappquill.js
+8
-0
packages/uni-cli-shared/template/v3/__uniappquillimageresize.js
...es/uni-cli-shared/template/v3/__uniappquillimageresize.js
+1
-0
src/core/helpers/tags.js
src/core/helpers/tags.js
+1
-0
src/core/service/api/context/canvas.js
src/core/service/api/context/canvas.js
+1
-1
src/core/service/api/context/create-map-context.js
src/core/service/api/context/create-map-context.js
+2
-2
src/core/service/api/context/create-video-context.js
src/core/service/api/context/create-video-context.js
+6
-6
src/core/service/api/context/editor.js
src/core/service/api/context/editor.js
+44
-0
src/core/service/api/ui/create-selector-query.js
src/core/service/api/ui/create-selector-query.js
+38
-1
src/core/view/bridge/subscribe/api/request-component-info.js
src/core/view/bridge/subscribe/api/request-component-info.js
+6
-1
src/core/view/components/editor/editor.css
src/core/view/components/editor/editor.css
+395
-0
src/core/view/components/editor/formats/align.js
src/core/view/components/editor/formats/align.js
+11
-0
src/core/view/components/editor/formats/background.js
src/core/view/components/editor/formats/background.js
+10
-0
src/core/view/components/editor/formats/box.js
src/core/view/components/editor/formats/box.js
+16
-0
src/core/view/components/editor/formats/direction.js
src/core/view/components/editor/formats/direction.js
+11
-0
src/core/view/components/editor/formats/divider.js
src/core/view/components/editor/formats/divider.js
+9
-0
src/core/view/components/editor/formats/font.js
src/core/view/components/editor/formats/font.js
+15
-0
src/core/view/components/editor/formats/image.js
src/core/view/components/editor/formats/image.js
+4
-0
src/core/view/components/editor/formats/index.js
src/core/view/components/editor/formats/index.js
+28
-0
src/core/view/components/editor/formats/ins.js
src/core/view/components/editor/formats/ins.js
+9
-0
src/core/view/components/editor/formats/list.js
src/core/view/components/editor/formats/list.js
+95
-0
src/core/view/components/editor/formats/text.js
src/core/view/components/editor/formats/text.js
+26
-0
src/core/view/components/editor/index.vue
src/core/view/components/editor/index.vue
+310
-0
src/core/view/mixins/subscriber.js
src/core/view/mixins/subscriber.js
+15
-0
src/shared/callback.js
src/shared/callback.js
+38
-0
src/shared/index.js
src/shared/index.js
+1
-0
src/shared/util.js
src/shared/util.js
+6
-2
未找到文件。
docs/api/media/editor-context.md
浏览文件 @
75d36c63
...
...
@@ -8,7 +8,7 @@ editor 组件对应的 editorContext 实例,可通过 [uni.createSelectorQuery
|App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√|
x
|√|x|x|x|x|
|√|
2.4.5+
|√|x|x|x|x|
## editorContext.format(name, value)
...
...
docs/api/ui/nodes-info.md
浏览文件 @
75d36c63
## uni.createSelectorQuery()
返回一个
``SelectorQuery``
对象实例。可以在这个实例上使用
``select``
等方法选择节点,并使用
``boundingClientRect``
等方法选择需要查询的信息。
**Tips:**
...
...
@@ -16,12 +16,12 @@
将选择器的选取范围更改为自定义组件
``component``
内,返回一个
``SelectorQuery``
对象实例。(初始时,选择器仅选取页面范围的节点,不会选取任何自定义组件中的节点)。
**代码示例**
```
javascript
```
javascript
const
query
=
uni
.
createSelectorQuery
().
in
(
this
);
query
.
select
(
'
#id
'
).
boundingClientRect
(
data
=>
{
console
.
log
(
"
得到布局位置信息
"
+
JSON
.
stringify
(
data
));
console
.
log
(
"
节点离页面顶部的距离为
"
+
data
.
top
);
}).
exec
();
query
.
select
(
'
#id
'
).
boundingClientRect
(
data
=>
{
console
.
log
(
"
得到布局位置信息
"
+
JSON
.
stringify
(
data
));
console
.
log
(
"
节点离页面顶部的距离为
"
+
data
.
top
);
}).
exec
();
```
### selectorQuery.select(selector)
...
...
@@ -36,21 +36,21 @@ query.select('#id').boundingClientRect(data => {
-
子元素选择器:
``.the-parent > .the-child``
-
后代选择器:
``.the-ancestor .the-descendant``
-
跨自定义组件的后代选择器:
``.the-ancestor >>> .the-descendant``
-
多选择器的并集:
``#a-node, .some-other-nodes``
-
多选择器的并集:
``#a-node, .some-other-nodes``
### selectorQuery.selectAll(selector)
在当前页面下选择匹配选择器
``selector``
的所有节点,返回一个
``NodesRef``
对象实例,可以用于获取节点信息。
### selectorQuery.selectViewport()
选择显示区域,可用于获取显示区域的尺寸、滚动位置等信息,返回一个
``NodesRef``
对象实例。
### selectorQuery.exec(callback)
执行所有的请求。请求结果按请求次序构成数组,在callback的第一个参数中返回。
执行所有的请求。请求结果按请求次序构成数组,在callback的第一个参数中返回。
## NodesRef
用于获取节点信息的对象
...
...
@@ -110,37 +110,37 @@ query.select('#id').boundingClientRect(data => {
|App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√|
x
|√|x|x|x|√|
|√|
2.4.5+
|√|x|x|x|√|
**callback 返回参数**
| 属性 | 类型 | 说明 |
| --- | --- | --- |
| context | Object | 节点对应的 Context 对象 |
### 代码示例
```
javascript
uni
.
createSelectorQuery
().
selectViewport
().
scrollOffset
(
res
=>
{
console
.
log
(
"
竖直滚动位置
"
+
res
.
scrollTop
);
}).
exec
();
let
view
=
uni
.
createSelectorQuery
().
in
(
this
).
select
(
"
.test
"
);
view
.
fields
({
size
:
true
,
scrollOffset
:
true
},
data
=>
{
console
.
log
(
"
得到节点信息
"
+
JSON
.
stringify
(
data
));
console
.
log
(
"
节点的宽为
"
+
data
.
width
);
}).
exec
();
view
.
boundingClientRect
(
data
=>
{
console
.
log
(
"
得到布局位置信息
"
+
JSON
.
stringify
(
data
));
console
.
log
(
"
节点离页面顶部的距离为
"
+
data
.
top
);
}).
exec
();
### 代码示例
```
javascript
uni
.
createSelectorQuery
().
selectViewport
().
scrollOffset
(
res
=>
{
console
.
log
(
"
竖直滚动位置
"
+
res
.
scrollTop
);
}).
exec
();
let
view
=
uni
.
createSelectorQuery
().
in
(
this
).
select
(
"
.test
"
);
view
.
fields
({
size
:
true
,
scrollOffset
:
true
},
data
=>
{
console
.
log
(
"
得到节点信息
"
+
JSON
.
stringify
(
data
));
console
.
log
(
"
节点的宽为
"
+
data
.
width
);
}).
exec
();
view
.
boundingClientRect
(
data
=>
{
console
.
log
(
"
得到布局位置信息
"
+
JSON
.
stringify
(
data
));
console
.
log
(
"
节点离页面顶部的距离为
"
+
data
.
top
);
}).
exec
();
```
**注意**
...
...
docs/component/editor.md
浏览文件 @
75d36c63
...
...
@@ -6,7 +6,7 @@
通过
`setContents`
接口设置内容时,解析插入的
`html`
可能会由于一些非法标签导致解析错误,建议开发者在应用内使用时通过 delta 进行插入。
富文本组件内部引入了一些基本的样式使得内容可以正确的展示,开发时可以进行覆盖。需要注意的是,在其它组件或环境中使用富文本组件导出的html时,需要额外引入
[
这段样式
](
https://github.com/
wechat-miniprogram/editor-style/blob/maste
r/editor.css
)
,并维护
`<ql-container><ql-editor></ql-editor></ql-container>`
的结构,参考:
[
使用 editor 组件导出的 html
](
https://ask.dcloud.net.cn/article/36205
)
。
富文本组件内部引入了一些基本的样式使得内容可以正确的展示,开发时可以进行覆盖。需要注意的是,在其它组件或环境中使用富文本组件导出的html时,需要额外引入
[
这段样式
](
https://github.com/
dcloudio/uni-app/blob/master/src/core/view/components/edito
r/editor.css
)
,并维护
`<ql-container><ql-editor></ql-editor></ql-container>`
的结构,参考:
[
使用 editor 组件导出的 html
](
https://ask.dcloud.net.cn/article/36205
)
。
图片控件仅初始化时设置有效。
...
...
@@ -16,11 +16,11 @@
|App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|2.0.0+
[
自定义组件编译模式
](
https://ask.dcloud.net.cn/article/35843
)
,不含nvue|
x
|基础库 2.7.0+|x|x|x|x|
|2.0.0+
[
自定义组件编译模式
](
https://ask.dcloud.net.cn/article/35843
)
,不含nvue|
2.4.5+
|基础库 2.7.0+|x|x|x|x|
本功能自HBuilderX2.0起支持。运行到微信小程序工具时,注意在微信工具里选择最新的基础库。
editor组件目前只有App的vue页面和微信支持,其他端的富文本编辑解决方案,可使用web-view加载web页面,也可搜索
[
插件市场
](
https://ext.dcloud.net.cn/search?q=%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91
)
获取简单的markdown富文本编辑器
editor组件目前只有
H5、
App的vue页面和微信支持,其他端的富文本编辑解决方案,可使用web-view加载web页面,也可搜索
[
插件市场
](
https://ext.dcloud.net.cn/search?q=%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91
)
获取简单的markdown富文本编辑器
| 属性 | 类型 | 默认值 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
...
...
lib/apis.js
浏览文件 @
75d36c63
...
...
@@ -111,9 +111,9 @@ const device = [
'
onBeaconUpdate
'
,
'
getBeacons
'
,
'
startBeaconDiscovery
'
,
'
stopBeaconDiscovery
'
,
'
checkIsSupportSoterAuthentication
'
,
'
checkIsSoterEnrolledInDevice
'
,
'
stopBeaconDiscovery
'
,
'
checkIsSupportSoterAuthentication
'
,
'
checkIsSoterEnrolledInDevice
'
,
'
startSoterAuthentication
'
]
...
...
@@ -194,9 +194,9 @@ const third = [
'
onPush
'
,
'
offPush
'
,
'
requireNativePlugin
'
,
'
upx2px
'
,
'
restoreGlobal
'
,
'
getSubNVueById
'
,
'
upx2px
'
,
'
restoreGlobal
'
,
'
getSubNVueById
'
,
'
getCurrentSubNVue
'
]
...
...
lib/modules.json
浏览文件 @
75d36c63
...
...
@@ -152,7 +152,7 @@
"uni.stopPullDownRefresh"
:
true
,
"uni.createSelectorQuery"
:
true
,
"uni.createIntersectionObserver"
:
true
,
"uni.hideKeyboard"
:
true
,
"uni.hideKeyboard"
:
true
,
"uni.onKeyboardHeightChange"
:
true
}
},
{
...
...
@@ -206,4 +206,4 @@
"uni.base64ToArrayBuffer"
:
true
,
"uni.arrayBufferToBase64"
:
true
}
}]
}]
packages/uni-cli-shared/lib/tags.js
浏览文件 @
75d36c63
module
.
exports
=
{
module
.
exports
=
{
'
resize-sensor
'
:
[
'
h5
'
],
'
ad
'
:
[
'
mp-weixin
'
],
'
audio
'
:
[
'
app-plus
'
,
'
mp-weixin
'
,
'
h5
'
],
...
...
@@ -9,6 +9,7 @@ module.exports = {
'
checkbox-group
'
:
[
'
app-plus
'
,
'
mp-weixin
'
,
'
h5
'
],
'
cover-image
'
:
[
'
app-plus
'
,
'
mp-weixin
'
],
'
cover-view
'
:
[
'
app-plus
'
,
'
mp-weixin
'
],
'
editor
'
:
[
'
app-plus
'
,
'
mp-weixin
'
,
'
h5
'
],
'
form
'
:
[
'
app-plus
'
,
'
mp-weixin
'
,
'
h5
'
],
'
functional-page-navigator
'
:
[
'
mp-weixin
'
],
'
icon
'
:
[
'
app-plus
'
,
'
mp-weixin
'
],
...
...
@@ -40,4 +41,4 @@ module.exports = {
'
video
'
:
[
'
app-plus
'
,
'
mp-weixin
'
,
'
h5
'
],
'
view
'
:
[
'
app-plus
'
,
'
mp-weixin
'
,
'
h5
'
],
'
web-view
'
:
[
'
app-plus
'
,
'
mp-weixin
'
]
}
}
packages/uni-cli-shared/template/v3/__uniappquill.js
0 → 100644
浏览文件 @
75d36c63
因为 它太大了无法显示 source diff 。你可以改为
查看blob
。
packages/uni-cli-shared/template/v3/__uniappquillimageresize.js
0 → 100644
浏览文件 @
75d36c63
此差异已折叠。
点击以展开。
src/core/helpers/tags.js
浏览文件 @
75d36c63
...
...
@@ -20,6 +20,7 @@ module.exports = [
'
uni-checkbox-group
'
,
'
uni-cover-image
'
,
'
uni-cover-view
'
,
'
uni-editor
'
,
'
uni-form
'
,
'
uni-functional-page-navigator
'
,
'
uni-icon
'
,
...
...
src/core/service/api/context/canvas.js
浏览文件 @
75d36c63
...
...
@@ -258,7 +258,7 @@ var methods3 = ['setFillStyle', 'setTextAlign', 'setStrokeStyle', 'setGlobalAlph
'
setTextBaseline
'
,
'
setLineDash
'
]
class
CanvasContext
{
export
class
CanvasContext
{
constructor
(
id
,
pageId
)
{
this
.
id
=
id
this
.
pageId
=
pageId
...
...
src/core/service/api/context/create-map-context.js
浏览文件 @
75d36c63
...
...
@@ -7,7 +7,7 @@ function operateMapPlayer (mapId, pageVm, type, data) {
invokeMethod
(
'
operateMapPlayer
'
,
mapId
,
pageVm
,
type
,
data
)
}
class
MapContext
{
export
class
MapContext
{
constructor
(
id
,
pageVm
)
{
this
.
id
=
id
this
.
pageVm
=
pageVm
...
...
@@ -43,4 +43,4 @@ export function createMapContext (id, context) {
return
new
MapContext
(
id
,
context
)
}
return
new
MapContext
(
id
,
getCurrentPageVm
(
'
createMapContext
'
))
}
}
src/core/service/api/context/create-video-context.js
浏览文件 @
75d36c63
...
...
@@ -9,7 +9,7 @@ function operateVideoPlayer (videoId, pageVm, type, data) {
invokeMethod
(
'
operateVideoPlayer
'
,
videoId
,
pageVm
,
type
,
data
)
}
class
VideoContext
{
export
class
VideoContext
{
constructor
(
id
,
pageVm
)
{
this
.
id
=
id
this
.
pageVm
=
pageVm
...
...
@@ -25,8 +25,8 @@ class VideoContext {
operateVideoPlayer
(
this
.
id
,
this
.
pageVm
,
'
stop
'
)
}
seek
(
position
)
{
operateVideoPlayer
(
this
.
id
,
this
.
pageVm
,
'
seek
'
,
{
position
operateVideoPlayer
(
this
.
id
,
this
.
pageVm
,
'
seek
'
,
{
position
})
}
sendDanmu
(
args
)
{
...
...
@@ -36,8 +36,8 @@ class VideoContext {
if
(
!~
RATES
.
indexOf
(
rate
))
{
rate
=
1.0
}
operateVideoPlayer
(
this
.
id
,
this
.
pageVm
,
'
playbackRate
'
,
{
rate
operateVideoPlayer
(
this
.
id
,
this
.
pageVm
,
'
playbackRate
'
,
{
rate
})
}
requestFullScreen
(
args
=
{})
{
...
...
@@ -59,4 +59,4 @@ export function createVideoContext (id, context) {
return
new
VideoContext
(
id
,
context
)
}
return
new
VideoContext
(
id
,
getCurrentPageVm
(
'
createVideoContext
'
))
}
}
src/core/service/api/context/editor.js
0 → 100644
浏览文件 @
75d36c63
import
{
callback
}
from
'
uni-shared
'
function
operateEditor
(
componentId
,
pageId
,
type
,
data
)
{
UniServiceJSBridge
.
publishHandler
(
pageId
+
'
-editor-
'
+
componentId
,
{
componentId
,
type
,
data
},
pageId
)
}
UniServiceJSBridge
.
subscribe
(
'
onEditorMethodCallback
'
,
({
callbackId
,
data
})
=>
{
callback
.
invoke
(
callbackId
,
data
)
})
const
methods
=
[
'
insertDivider
'
,
'
insertImage
'
,
'
insertText
'
,
'
setContents
'
,
'
getContents
'
,
'
clear
'
,
'
removeFormat
'
,
'
undo
'
,
'
redo
'
]
export
class
EditorContext
{
constructor
(
id
,
pageId
)
{
this
.
id
=
id
this
.
pageId
=
pageId
}
format
(
name
,
value
)
{
operateEditor
(
this
.
id
,
this
.
pageId
,
'
format
'
,
{
options
:
{
name
,
value
}
})
}
}
methods
.
forEach
(
function
(
method
)
{
EditorContext
.
prototype
[
method
]
=
callback
.
warp
(
function
(
options
,
callbackId
)
{
operateEditor
(
this
.
id
,
this
.
pageId
,
method
,
{
options
,
callbackId
})
})
})
src/core/service/api/ui/create-selector-query.js
浏览文件 @
75d36c63
...
...
@@ -7,6 +7,26 @@ import {
getCurrentPageVm
}
from
'
../../platform
'
import
{
CanvasContext
}
from
'
../context/canvas
'
import
{
MapContext
}
from
'
../context/create-map-context
'
import
{
VideoContext
}
from
'
../context/create-video-context
'
import
{
EditorContext
}
from
'
../context/editor
'
const
ContextClasss
=
{
canvas
:
CanvasContext
,
map
:
MapContext
,
video
:
VideoContext
,
editor
:
EditorContext
}
function
convertContext
(
result
)
{
if
(
result
.
context
)
{
const
{
id
,
name
,
page
}
=
result
.
context
const
ContextClass
=
ContextClasss
[
name
]
result
.
context
=
ContextClass
&&
new
ContextClass
(
id
,
page
)
}
}
class
NodesRef
{
constructor
(
selectorQuery
,
component
,
selector
,
single
)
{
this
.
_selectorQuery
=
selectorQuery
...
...
@@ -53,6 +73,18 @@ class NodesRef {
)
return
this
.
_selectorQuery
}
context
(
callback
)
{
this
.
_selectorQuery
.
_push
(
this
.
_selector
,
this
.
_component
,
this
.
_single
,
{
context
:
true
},
callback
)
return
this
.
_selectorQuery
}
}
class
SelectorQuery
{
...
...
@@ -66,6 +98,11 @@ class SelectorQuery {
invokeMethod
(
'
requestComponentInfo
'
,
this
.
_page
,
this
.
_queue
,
res
=>
{
const
queueCbs
=
this
.
_queueCb
res
.
forEach
((
result
,
index
)
=>
{
if
(
Array
.
isArray
(
result
))
{
result
.
forEach
(
convertContext
)
}
else
{
convertContext
(
result
)
}
const
queueCb
=
queueCbs
[
index
]
if
(
isFn
(
queueCb
))
{
queueCb
.
call
(
this
,
result
)
...
...
@@ -109,4 +146,4 @@ export function createSelectorQuery (context) {
return
new
SelectorQuery
(
context
)
}
return
new
SelectorQuery
(
getCurrentPageVm
(
'
createSelectorQuery
'
))
}
}
src/core/view/bridge/subscribe/api/request-component-info.js
浏览文件 @
75d36c63
...
...
@@ -74,6 +74,11 @@ function getNodeInfo (el, fields) {
info
.
scrollTop
=
0
}
}
if
(
fields
.
context
)
{
if
(
el
.
__vue__
&&
el
.
__vue__
.
_getContextInfo
)
{
info
.
context
=
el
.
__vue__
.
_getContextInfo
()
}
}
return
info
}
...
...
@@ -134,4 +139,4 @@ export function requestComponentInfo ({
reqId
,
res
:
result
},
pageVm
.
$page
.
id
)
}
}
src/core/view/components/editor/editor.css
0 → 100644
浏览文件 @
75d36c63
.ql-container
{
display
:
block
;
position
:
relative
;
box-sizing
:
border-box
;
-webkit-user-select
:
text
;
user-select
:
text
;
outline
:
none
;
overflow
:
hidden
;
width
:
100%
;
height
:
200px
;
min-height
:
200px
;
}
.ql-container
[
hidden
]
{
display
:
none
;
}
.ql-container
.ql-editor
{
position
:
relative
;
font-size
:
inherit
;
line-height
:
inherit
;
font-family
:
inherit
;
min-height
:
inherit
;
width
:
100%
;
height
:
100%
;
padding
:
0
;
overflow-x
:
hidden
;
overflow-y
:
auto
;
-webkit-tap-highlight-color
:
transparent
;
-webkit-touch-callout
:
none
;
-webkit-overflow-scrolling
:
touch
;
}
.ql-container
.ql-editor
::-webkit-scrollbar
{
width
:
0
!important
;
}
.ql-container
.ql-editor.scroll-disabled
{
overflow
:
hidden
;
}
.ql-container
.ql-image-overlay
{
display
:
flex
;
position
:
absolute
;
box-sizing
:
border-box
;
border
:
1px
dashed
#ccc
;
justify-content
:
center
;
align-items
:
center
;
-webkit-user-select
:
none
;
user-select
:
none
;
}
.ql-container
.ql-image-overlay
.ql-image-size
{
position
:
absolute
;
padding
:
4px
8px
;
text-align
:
center
;
background-color
:
#fff
;
color
:
#888
;
border
:
1px
solid
#ccc
;
box-sizing
:
border-box
;
opacity
:
0.8
;
right
:
4px
;
top
:
4px
;
font-size
:
12px
;
display
:
inline-block
;
width
:
auto
;
}
.ql-container
.ql-image-overlay
.ql-image-toolbar
{
position
:
relative
;
text-align
:
center
;
box-sizing
:
border-box
;
background
:
#000
;
border-radius
:
5px
;
color
:
#fff
;
font-size
:
0
;
min-height
:
24px
;
z-index
:
100
;
}
.ql-container
.ql-image-overlay
.ql-image-toolbar
span
{
display
:
inline-block
;
cursor
:
pointer
;
padding
:
5px
;
font-size
:
12px
;
border-right
:
1px
solid
#fff
;
}
.ql-container
.ql-image-overlay
.ql-image-toolbar
span
:last-child
{
border-right
:
0
;
}
.ql-container
.ql-image-overlay
.ql-image-toolbar
span
.triangle-up
{
padding
:
0
;
position
:
absolute
;
top
:
-12px
;
left
:
50%
;
transform
:
translatex
(
-50%
);
width
:
0
;
height
:
0
;
border-width
:
6px
;
border-style
:
solid
;
border-color
:
transparent
transparent
black
transparent
;
}
.ql-container
.ql-image-overlay
.ql-image-handle
{
position
:
absolute
;
height
:
12px
;
width
:
12px
;
border-radius
:
50%
;
border
:
1px
solid
#ccc
;
box-sizing
:
border-box
;
background
:
#fff
;
}
.ql-container
img
{
display
:
inline-block
;
max-width
:
100%
;
}
.ql-clipboard
p
{
margin
:
0
;
padding
:
0
;
}
.ql-editor
{
box-sizing
:
border-box
;
height
:
100%
;
outline
:
none
;
overflow-y
:
auto
;
tab-size
:
4
;
-moz-tab-size
:
4
;
text-align
:
left
;
white-space
:
pre-wrap
;
word-wrap
:
break-word
;
}
.ql-editor
>
*
{
cursor
:
text
;
}
.ql-editor
p
,
.ql-editor
ol
,
.ql-editor
ul
,
.ql-editor
pre
,
.ql-editor
blockquote
,
.ql-editor
h1
,
.ql-editor
h2
,
.ql-editor
h3
,
.ql-editor
h4
,
.ql-editor
h5
,
.ql-editor
h6
{
margin
:
0
;
padding
:
0
;
counter-reset
:
list-1
list-2
list-3
list-4
list-5
list-6
list-7
list-8
list-9
;
}
.ql-editor
ol
>
li
,
.ql-editor
ul
>
li
{
list-style-type
:
none
;
}
.ql-editor
ul
>
li
::before
{
content
:
'\2022'
;
}
.ql-editor
ul
[
data-checked
=
true
],
.ql-editor
ul
[
data-checked
=
false
]
{
pointer-events
:
none
;
}
.ql-editor
ul
[
data-checked
=
true
]
>
li
*,
.ql-editor
ul
[
data-checked
=
false
]
>
li
*
{
pointer-events
:
all
;
}
.ql-editor
ul
[
data-checked
=
true
]
>
li
::before
,
.ql-editor
ul
[
data-checked
=
false
]
>
li
::before
{
color
:
#777
;
cursor
:
pointer
;
pointer-events
:
all
;
}
.ql-editor
ul
[
data-checked
=
true
]
>
li
::before
{
content
:
'\2611'
;
}
.ql-editor
ul
[
data-checked
=
false
]
>
li
::before
{
content
:
'\2610'
;
}
.ql-editor
li
::before
{
display
:
inline-block
;
white-space
:
nowrap
;
width
:
2em
;
}
.ql-editor
ol
li
{
counter-reset
:
list-1
list-2
list-3
list-4
list-5
list-6
list-7
list-8
list-9
;
counter-increment
:
list-0
;
}
.ql-editor
ol
li
:before
{
content
:
counter
(
list-0
,
decimal
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-1
{
counter-increment
:
list-1
;
}
.ql-editor
ol
li
.ql-indent-1
:before
{
content
:
counter
(
list-1
,
lower-alpha
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-1
{
counter-reset
:
list-2
list-3
list-4
list-5
list-6
list-7
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-2
{
counter-increment
:
list-2
;
}
.ql-editor
ol
li
.ql-indent-2
:before
{
content
:
counter
(
list-2
,
lower-roman
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-2
{
counter-reset
:
list-3
list-4
list-5
list-6
list-7
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-3
{
counter-increment
:
list-3
;
}
.ql-editor
ol
li
.ql-indent-3
:before
{
content
:
counter
(
list-3
,
decimal
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-3
{
counter-reset
:
list-4
list-5
list-6
list-7
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-4
{
counter-increment
:
list-4
;
}
.ql-editor
ol
li
.ql-indent-4
:before
{
content
:
counter
(
list-4
,
lower-alpha
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-4
{
counter-reset
:
list-5
list-6
list-7
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-5
{
counter-increment
:
list-5
;
}
.ql-editor
ol
li
.ql-indent-5
:before
{
content
:
counter
(
list-5
,
lower-roman
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-5
{
counter-reset
:
list-6
list-7
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-6
{
counter-increment
:
list-6
;
}
.ql-editor
ol
li
.ql-indent-6
:before
{
content
:
counter
(
list-6
,
decimal
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-6
{
counter-reset
:
list-7
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-7
{
counter-increment
:
list-7
;
}
.ql-editor
ol
li
.ql-indent-7
:before
{
content
:
counter
(
list-7
,
lower-alpha
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-7
{
counter-reset
:
list-8
list-9
;
}
.ql-editor
ol
li
.ql-indent-8
{
counter-increment
:
list-8
;
}
.ql-editor
ol
li
.ql-indent-8
:before
{
content
:
counter
(
list-8
,
lower-roman
)
'. '
;
}
.ql-editor
ol
li
.ql-indent-8
{
counter-reset
:
list-9
;
}
.ql-editor
ol
li
.ql-indent-9
{
counter-increment
:
list-9
;
}
.ql-editor
ol
li
.ql-indent-9
:before
{
content
:
counter
(
list-9
,
decimal
)
'. '
;
}
.ql-editor
.ql-indent-1
:not
(
.ql-direction-rtl
)
{
padding-left
:
2em
;
}
.ql-editor
li
.ql-indent-1
:not
(
.ql-direction-rtl
)
{
padding-left
:
2em
;
}
.ql-editor
.ql-indent-1.ql-direction-rtl.ql-align-right
{
padding-right
:
2em
;
}
.ql-editor
li
.ql-indent-1.ql-direction-rtl.ql-align-right
{
padding-right
:
2em
;
}
.ql-editor
.ql-indent-2
:not
(
.ql-direction-rtl
)
{
padding-left
:
4em
;
}
.ql-editor
li
.ql-indent-2
:not
(
.ql-direction-rtl
)
{
padding-left
:
4em
;
}
.ql-editor
.ql-indent-2.ql-direction-rtl.ql-align-right
{
padding-right
:
4em
;
}
.ql-editor
li
.ql-indent-2.ql-direction-rtl.ql-align-right
{
padding-right
:
4em
;
}
.ql-editor
.ql-indent-3
:not
(
.ql-direction-rtl
)
{
padding-left
:
6em
;
}
.ql-editor
li
.ql-indent-3
:not
(
.ql-direction-rtl
)
{
padding-left
:
6em
;
}
.ql-editor
.ql-indent-3.ql-direction-rtl.ql-align-right
{
padding-right
:
6em
;
}
.ql-editor
li
.ql-indent-3.ql-direction-rtl.ql-align-right
{
padding-right
:
6em
;
}
.ql-editor
.ql-indent-4
:not
(
.ql-direction-rtl
)
{
padding-left
:
8em
;
}
.ql-editor
li
.ql-indent-4
:not
(
.ql-direction-rtl
)
{
padding-left
:
8em
;
}
.ql-editor
.ql-indent-4.ql-direction-rtl.ql-align-right
{
padding-right
:
8em
;
}
.ql-editor
li
.ql-indent-4.ql-direction-rtl.ql-align-right
{
padding-right
:
8em
;
}
.ql-editor
.ql-indent-5
:not
(
.ql-direction-rtl
)
{
padding-left
:
10em
;
}
.ql-editor
li
.ql-indent-5
:not
(
.ql-direction-rtl
)
{
padding-left
:
10em
;
}
.ql-editor
.ql-indent-5.ql-direction-rtl.ql-align-right
{
padding-right
:
10em
;
}
.ql-editor
li
.ql-indent-5.ql-direction-rtl.ql-align-right
{
padding-right
:
10em
;
}
.ql-editor
.ql-indent-6
:not
(
.ql-direction-rtl
)
{
padding-left
:
12em
;
}
.ql-editor
li
.ql-indent-6
:not
(
.ql-direction-rtl
)
{
padding-left
:
12em
;
}
.ql-editor
.ql-indent-6.ql-direction-rtl.ql-align-right
{
padding-right
:
12em
;
}
.ql-editor
li
.ql-indent-6.ql-direction-rtl.ql-align-right
{
padding-right
:
12em
;
}
.ql-editor
.ql-indent-7
:not
(
.ql-direction-rtl
)
{
padding-left
:
14em
;
}
.ql-editor
li
.ql-indent-7
:not
(
.ql-direction-rtl
)
{
padding-left
:
14em
;
}
.ql-editor
.ql-indent-7.ql-direction-rtl.ql-align-right
{
padding-right
:
14em
;
}
.ql-editor
li
.ql-indent-7.ql-direction-rtl.ql-align-right
{
padding-right
:
14em
;
}
.ql-editor
.ql-indent-8
:not
(
.ql-direction-rtl
)
{
padding-left
:
16em
;
}
.ql-editor
li
.ql-indent-8
:not
(
.ql-direction-rtl
)
{
padding-left
:
16em
;
}
.ql-editor
.ql-indent-8.ql-direction-rtl.ql-align-right
{
padding-right
:
16em
;
}
.ql-editor
li
.ql-indent-8.ql-direction-rtl.ql-align-right
{
padding-right
:
16em
;
}
.ql-editor
.ql-indent-9
:not
(
.ql-direction-rtl
)
{
padding-left
:
18em
;
}
.ql-editor
li
.ql-indent-9
:not
(
.ql-direction-rtl
)
{
padding-left
:
18em
;
}
.ql-editor
.ql-indent-9.ql-direction-rtl.ql-align-right
{
padding-right
:
18em
;
}
.ql-editor
li
.ql-indent-9.ql-direction-rtl.ql-align-right
{
padding-right
:
18em
;
}
.ql-editor
.ql-direction-rtl
{
direction
:
rtl
;
text-align
:
inherit
;
}
.ql-editor
.ql-align-center
{
text-align
:
center
;
}
.ql-editor
.ql-align-justify
{
text-align
:
justify
;
}
.ql-editor
.ql-align-right
{
text-align
:
right
;
}
.ql-editor.ql-blank
::before
{
color
:
rgba
(
0
,
0
,
0
,
0.6
);
content
:
attr
(
data-placeholder
);
font-style
:
italic
;
pointer-events
:
none
;
position
:
absolute
;
}
.ql-container.ql-disabled
.ql-editor
ul
[
data-checked
]
>
li
::before
{
pointer-events
:
none
;
}
.ql-clipboard
{
left
:
-100000px
;
height
:
1px
;
overflow-y
:
hidden
;
position
:
absolute
;
top
:
50%
;
}
src/core/view/components/editor/formats/align.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
{
Scope
,
Attributor
}
=
Quill
.
import
(
'
parchment
'
)
const
config
=
{
scope
:
Scope
.
BLOCK
,
whitelist
:
[
'
left
'
,
'
right
'
,
'
center
'
,
'
justify
'
]
}
const
AlignStyle
=
new
Attributor
.
Style
(
'
align
'
,
'
text-align
'
,
config
)
return
{
'
formats/align
'
:
AlignStyle
}
}
src/core/view/components/editor/formats/background.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
{
Scope
}
=
Quill
.
import
(
'
parchment
'
)
const
BackgroundStyle
=
Quill
.
import
(
'
formats/background
'
)
const
BackgroundColorStyle
=
new
BackgroundStyle
.
constructor
(
'
backgroundColor
'
,
'
background-color
'
,
{
scope
:
Scope
.
INLINE
})
return
{
'
formats/backgroundColor
'
:
BackgroundColorStyle
}
}
src/core/view/components/editor/formats/box.js
0 → 100644
浏览文件 @
75d36c63
import
{
kebabCase
}
from
'
uni-shared
'
export
default
function
(
Quill
)
{
const
{
Scope
,
Attributor
}
=
Quill
.
import
(
'
parchment
'
)
const
config
=
{
scope
:
Scope
.
BLOCK
}
const
margin
=
[
'
margin
'
,
'
marginTop
'
,
'
marginBottom
'
,
'
marginLeft
'
,
'
marginRight
'
]
const
padding
=
[
'
padding
'
,
'
paddingTop
'
,
'
paddingBottom
'
,
'
paddingLeft
'
,
'
paddingRight
'
]
const
result
=
{}
margin
.
concat
(
padding
).
forEach
(
name
=>
{
result
[
`formats/
${
name
}
`
]
=
new
Attributor
.
Style
(
name
,
kebabCase
(
name
),
config
)
})
return
result
}
src/core/view/components/editor/formats/direction.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
{
Scope
,
Attributor
}
=
Quill
.
import
(
'
parchment
'
)
const
config
=
{
scope
:
Scope
.
BLOCK
,
whitelist
:
[
'
rtl
'
]
}
const
DirectionStyle
=
new
Attributor
.
Style
(
'
direction
'
,
'
direction
'
,
config
)
return
{
'
formats/direction
'
:
DirectionStyle
}
}
src/core/view/components/editor/formats/divider.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
BlockEmbed
=
Quill
.
import
(
'
blots/block/embed
'
)
class
Divider
extends
BlockEmbed
{
}
Divider
.
blotName
=
'
divider
'
Divider
.
tagName
=
'
HR
'
return
{
'
formats/divider
'
:
Divider
}
}
src/core/view/components/editor/formats/font.js
0 → 100644
浏览文件 @
75d36c63
import
{
kebabCase
}
from
'
uni-shared
'
export
default
function
(
Quill
)
{
const
{
Scope
,
Attributor
}
=
Quill
.
import
(
'
parchment
'
)
const
config
=
{
scope
:
Scope
.
INLINE
}
const
font
=
[
'
font
'
,
'
fontSize
'
,
'
fontStyle
'
,
'
fontVariant
'
,
'
fontWeight
'
,
'
fontFamily
'
]
const
result
=
{}
font
.
forEach
(
name
=>
{
result
[
`formats/
${
name
}
`
]
=
new
Attributor
.
Style
(
name
,
kebabCase
(
name
),
config
)
})
return
result
}
src/core/view/components/editor/formats/image.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
Image
=
Quill
.
import
(
'
formats/image
'
)
Image
.
sanitize
=
url
=>
url
}
src/core/view/components/editor/formats/index.js
0 → 100644
浏览文件 @
75d36c63
import
divider
from
'
./divider
'
import
ins
from
'
./ins
'
import
align
from
'
./align
'
import
direction
from
'
./direction
'
import
list
from
'
./list
'
import
background
from
'
./background
'
import
box
from
'
./box
'
import
font
from
'
./font
'
import
text
from
'
./text
'
import
image
from
'
./image
'
export
function
register
(
Quill
)
{
const
formats
=
{
divider
,
ins
,
align
,
direction
,
list
,
background
,
box
,
font
,
text
,
image
}
const
options
=
{}
Object
.
values
(
formats
).
forEach
(
value
=>
Object
.
assign
(
options
,
value
(
Quill
)))
Quill
.
register
(
options
,
true
)
}
src/core/view/components/editor/formats/ins.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
Inline
=
Quill
.
import
(
'
blots/inline
'
)
class
Ins
extends
Inline
{
}
Ins
.
blotName
=
'
ins
'
Ins
.
tagName
=
'
INS
'
return
{
'
formats/ins
'
:
Ins
}
}
src/core/view/components/editor/formats/list.js
0 → 100644
浏览文件 @
75d36c63
export
default
function
(
Quill
)
{
const
Parchment
=
Quill
.
import
(
'
parchment
'
)
const
Container
=
Quill
.
import
(
'
blots/container
'
)
const
ListItem
=
Quill
.
import
(
'
formats/list/item
'
)
class
List
extends
Container
{
static
create
(
value
)
{
let
tagName
=
value
===
'
ordered
'
?
'
OL
'
:
'
UL
'
let
node
=
super
.
create
(
tagName
)
if
(
value
===
'
checked
'
||
value
===
'
unchecked
'
)
{
node
.
setAttribute
(
'
data-checked
'
,
value
===
'
checked
'
)
}
return
node
}
static
formats
(
domNode
)
{
if
(
domNode
.
tagName
===
'
OL
'
)
return
'
ordered
'
if
(
domNode
.
tagName
===
'
UL
'
)
{
if
(
domNode
.
hasAttribute
(
'
data-checked
'
))
{
return
domNode
.
getAttribute
(
'
data-checked
'
)
===
'
true
'
?
'
checked
'
:
'
unchecked
'
}
else
{
return
'
bullet
'
}
}
return
undefined
}
constructor
(
domNode
)
{
super
(
domNode
)
const
listEventHandler
=
(
e
)
=>
{
if
(
e
.
target
.
parentNode
!==
domNode
)
return
let
format
=
this
.
statics
.
formats
(
domNode
)
let
blot
=
Parchment
.
find
(
e
.
target
)
if
(
format
===
'
checked
'
)
{
blot
.
format
(
'
list
'
,
'
unchecked
'
)
}
else
if
(
format
===
'
unchecked
'
)
{
blot
.
format
(
'
list
'
,
'
checked
'
)
}
}
domNode
.
addEventListener
(
'
click
'
,
listEventHandler
)
}
format
(
name
,
value
)
{
if
(
this
.
children
.
length
>
0
)
{
this
.
children
.
tail
.
format
(
name
,
value
)
}
}
formats
()
{
// We don't inherit from FormatBlot
return
{
[
this
.
statics
.
blotName
]:
this
.
statics
.
formats
(
this
.
domNode
)
}
}
insertBefore
(
blot
,
ref
)
{
if
(
blot
instanceof
ListItem
)
{
super
.
insertBefore
(
blot
,
ref
)
}
else
{
let
index
=
ref
==
null
?
this
.
length
()
:
ref
.
offset
(
this
)
let
after
=
this
.
split
(
index
)
after
.
parent
.
insertBefore
(
blot
,
after
)
}
}
optimize
(
context
)
{
super
.
optimize
(
context
)
let
next
=
this
.
next
if
(
next
!=
null
&&
next
.
prev
===
this
&&
next
.
statics
.
blotName
===
this
.
statics
.
blotName
&&
next
.
domNode
.
tagName
===
this
.
domNode
.
tagName
&&
next
.
domNode
.
getAttribute
(
'
data-checked
'
)
===
this
.
domNode
.
getAttribute
(
'
data-checked
'
))
{
next
.
moveChildren
(
this
)
next
.
remove
()
}
}
replace
(
target
)
{
if
(
target
.
statics
.
blotName
!==
this
.
statics
.
blotName
)
{
let
item
=
Parchment
.
create
(
this
.
statics
.
defaultChild
)
target
.
moveChildren
(
item
)
this
.
appendChild
(
item
)
}
super
.
replace
(
target
)
}
}
List
.
blotName
=
'
list
'
List
.
scope
=
Parchment
.
Scope
.
BLOCK_BLOT
List
.
tagName
=
[
'
OL
'
,
'
UL
'
]
List
.
defaultChild
=
'
list-item
'
List
.
allowedChildren
=
[
ListItem
]
return
{
'
formats/list
'
:
List
}
}
src/core/view/components/editor/formats/text.js
0 → 100644
浏览文件 @
75d36c63
import
{
kebabCase
}
from
'
uni-shared
'
export
default
function
(
Quill
)
{
const
{
Scope
,
Attributor
}
=
Quill
.
import
(
'
parchment
'
)
const
text
=
[{
name
:
'
lineHeight
'
,
scope
:
Scope
.
BLOCK
},
{
name
:
'
letterSpacing
'
,
scope
:
Scope
.
INLINE
},
{
name
:
'
textDecoration
'
,
scope
:
Scope
.
INLINE
},
{
name
:
'
textIndent
'
,
scope
:
Scope
.
BLOCK
}]
const
result
=
{}
text
.
forEach
(({
name
,
scope
})
=>
{
result
[
`formats/
${
name
}
`
]
=
new
Attributor
.
Style
(
name
,
kebabCase
(
name
),
{
scope
})
})
return
result
}
src/core/view/components/editor/index.vue
0 → 100644
浏览文件 @
75d36c63
<
template
>
<uni-editor
:id=
"id"
class=
"ql-container"
/>
</
template
>
<
script
>
import
{
subscriber
,
emitter
,
keyboard
}
from
'
uni-mixins
'
import
HTMLParser
from
'
uni-helpers/html-parser
'
import
*
as
formats
from
'
./formats
'
export
default
{
name
:
'
Editor
'
,
mixins
:
[
subscriber
,
emitter
,
keyboard
],
props
:
{
id
:
{
type
:
String
,
default
:
''
},
readOnly
:
{
type
:
[
Boolean
,
String
],
default
:
false
},
placeholder
:
{
type
:
String
,
default
:
''
},
showImgSize
:
{
type
:
[
Boolean
,
String
],
default
:
false
},
showImgToolbar
:
{
type
:
[
Boolean
,
String
],
default
:
false
},
showImgResize
:
{
type
:
[
Boolean
,
String
],
default
:
false
}
},
data
()
{
return
{
quillReady
:
false
}
},
computed
:
{
},
watch
:
{
readOnly
(
value
)
{
if
(
this
.
quillReady
)
{
const
quill
=
this
.
quill
quill
.
enable
(
!
value
)
if
(
!
value
)
{
quill
.
blur
()
}
}
},
placeholder
(
value
)
{
if
(
this
.
quillReady
)
{
this
.
quill
.
root
.
setAttribute
(
'
data-placeholder
'
,
value
)
}
}
},
mounted
()
{
const
imageResizeModules
=
[]
if
(
this
.
showImgSize
)
{
imageResizeModules
.
push
(
'
DisplaySize
'
)
}
if
(
this
.
showImgToolbar
)
{
imageResizeModules
.
push
(
'
Toolbar
'
)
}
if
(
this
.
showImgResize
)
{
imageResizeModules
.
push
(
'
Resize
'
)
}
this
.
loadQuill
(()
=>
{
if
(
imageResizeModules
.
length
)
{
this
.
loadImageResizeModule
(()
=>
{
this
.
initQuill
(
imageResizeModules
)
})
}
else
{
this
.
initQuill
(
imageResizeModules
)
}
})
},
methods
:
{
_handleSubscribe
({
type
,
data
})
{
const
{
options
,
callbackId
}
=
data
const
quill
=
this
.
quill
const
Quill
=
window
.
Quill
let
res
let
range
let
errMsg
if
(
this
.
quillReady
)
{
switch
(
type
)
{
case
'
format
'
:
let
{
name
=
''
,
value
=
false
}
=
options
range
=
quill
.
getSelection
(
true
)
let
format
=
quill
.
getFormat
(
range
)[
name
]
||
false
if
([
'
bold
'
,
'
italic
'
,
'
underline
'
,
'
strike
'
,
'
ins
'
].
includes
(
name
))
{
value
=
!
format
}
else
if
(
name
===
'
direction
'
)
{
value
=
value
===
'
rtl
'
&&
format
?
false
:
value
const
align
=
quill
.
getFormat
(
range
).
align
if
(
value
===
'
rtl
'
&&
!
align
)
{
quill
.
format
(
'
align
'
,
'
right
'
,
Quill
.
sources
.
USER
)
}
else
if
(
!
value
&&
align
===
'
right
'
)
{
quill
.
format
(
'
align
'
,
false
,
Quill
.
sources
.
USER
)
}
}
else
if
(
name
===
'
indent
'
)
{
const
rtl
=
quill
.
getFormat
(
range
).
direction
===
'
rtl
'
if
(
rtl
)
{
value
=
!
value
}
value
=
value
?
'
+1
'
:
'
-1
'
}
else
{
if
(
name
===
'
list
'
)
{
value
=
value
===
'
check
'
?
'
unchecked
'
:
value
format
=
format
===
'
checked
'
?
'
unchecked
'
:
format
}
value
=
((
format
&&
format
!==
(
value
||
false
))
||
(
!
format
&&
value
))
?
value
:
!
format
}
quill
.
format
(
name
,
value
,
Quill
.
sources
.
USER
)
break
case
'
insertDivider
'
:
range
=
quill
.
getSelection
(
true
)
quill
.
insertText
(
range
.
index
,
'
\n
'
,
Quill
.
sources
.
USER
)
quill
.
insertEmbed
(
range
.
index
+
1
,
'
divider
'
,
true
,
Quill
.
sources
.
USER
)
quill
.
setSelection
(
range
.
index
+
2
,
Quill
.
sources
.
SILENT
)
break
case
'
insertImage
'
:
range
=
quill
.
getSelection
(
true
)
const
{
src
=
''
,
alt
=
''
,
data
=
{}
}
=
options
quill
.
insertEmbed
(
range
.
index
,
'
image
'
,
this
.
$getRealPath
(
src
),
Quill
.
sources
.
USER
)
quill
.
formatText
(
range
.
index
,
1
,
'
alt
'
,
alt
)
quill
.
formatText
(
range
.
index
,
1
,
'
data-custom
'
,
Object
.
keys
(
data
).
map
(
key
=>
`
${
key
}
=
${
data
[
key
]}
`
).
join
(
'
&
'
))
quill
.
setSelection
(
range
.
index
+
1
,
Quill
.
sources
.
SILENT
)
break
case
'
insertText
'
:
range
=
quill
.
getSelection
(
true
)
const
{
text
=
''
}
=
options
quill
.
insertText
(
range
.
index
,
text
,
Quill
.
sources
.
USER
)
quill
.
setSelection
(
range
.
index
+
text
.
length
,
0
,
Quill
.
sources
.
SILENT
)
break
case
'
setContents
'
:
const
{
delta
,
html
}
=
options
if
(
typeof
delta
===
'
object
'
)
{
quill
.
setContents
(
delta
,
Quill
.
sources
.
SILENT
)
}
else
if
(
typeof
html
===
'
string
'
)
{
quill
.
setContents
(
this
.
html2delta
(
html
),
Quill
.
sources
.
SILENT
)
}
else
{
errMsg
=
'
contents is missing
'
}
break
case
'
getContents
'
:
res
=
this
.
getContents
()
break
case
'
clear
'
:
quill
.
setContents
([])
break
case
'
removeFormat
'
:
range
=
quill
.
getSelection
(
true
)
var
parchment
=
Quill
.
import
(
'
parchment
'
)
if
(
range
.
length
)
{
quill
.
removeFormat
(
range
,
Quill
.
sources
.
USER
)
}
else
{
Object
.
keys
(
quill
.
getFormat
(
range
)).
forEach
(
key
=>
{
if
(
parchment
.
query
(
key
,
parchment
.
Scope
.
INLINE
))
{
quill
.
format
(
key
,
false
)
}
})
}
break
case
'
undo
'
:
quill
.
history
.
undo
()
break
case
'
redo
'
:
quill
.
history
.
redo
()
break
default
:
break
}
}
else
{
errMsg
=
'
not ready
'
}
if
(
callbackId
)
{
UniViewJSBridge
.
publishHandler
(
'
onEditorMethodCallback
'
,
{
callbackId
,
data
:
Object
.
assign
({},
res
,
{
errMsg
:
`
${
type
}
:
${
errMsg
?
'
fail
'
+
errMsg
:
'
ok
'
}
`
})
},
this
.
$page
.
id
)
}
},
loadQuill
(
callback
)
{
if
(
typeof
window
.
Quill
===
'
function
'
)
{
if
(
typeof
callback
===
'
function
'
)
{
callback
()
}
return
}
let
script
=
document
.
createElement
(
'
script
'
)
script
.
src
=
window
.
plus
?
'
./__uniappquill.js
'
:
'
https://unpkg.com/quill@1.3.7/dist/quill.min.js
'
document
.
body
.
appendChild
(
script
)
script
.
onload
=
callback
},
loadImageResizeModule
(
callback
)
{
if
(
typeof
window
.
ImageResize
===
'
function
'
)
{
if
(
typeof
callback
===
'
function
'
)
{
callback
()
}
return
}
let
script
=
document
.
createElement
(
'
script
'
)
script
.
src
=
window
.
plus
?
'
./__uniappquillimageresize.js
'
:
'
https://unpkg.com/quill-image-resize-mp@3.0.1/image-resize.min.js
'
document
.
body
.
appendChild
(
script
)
script
.
onload
=
callback
},
initQuill
(
imageResizeModules
)
{
const
Quill
=
window
.
Quill
Quill
.
register
(
'
modules/ImageResize
'
,
window
.
ImageResize
.
default
)
formats
.
register
(
Quill
)
const
quill
=
this
.
quill
=
new
Quill
(
this
.
$el
,
{
toolbar
:
false
,
readOnly
:
this
.
readOnly
,
placeholder
:
this
.
placeholder
,
modules
:
{
ImageResize
:
{
modules
:
imageResizeModules
}
}
})
const
$el
=
quill
.
root
const
events
=
[
'
focus
'
,
'
blur
'
]
events
.
forEach
(
name
=>
{
$el
.
addEventListener
(
name
,
(
$event
)
=>
{
this
.
$trigger
(
name
,
$event
,
this
.
getContents
())
})
})
quill
.
on
(
Quill
.
events
.
TEXT_CHANGE
,
()
=>
{
this
.
$trigger
(
'
input
'
,
{},
this
.
getContents
())
})
quill
.
clipboard
.
addMatcher
(
Node
.
ELEMENT_NODE
,
(
node
,
delta
)
=>
{
if
(
this
.
skipMatcher
)
{
return
delta
}
return
{
ops
:
delta
.
ops
.
filter
(({
insert
})
=>
typeof
insert
===
'
string
'
).
map
(({
insert
})
=>
({
insert
}))
}
})
this
.
initKeyboard
(
$el
)
this
.
quillReady
=
true
this
.
$trigger
(
'
ready
'
,
event
,
{})
},
getContents
()
{
const
quill
=
this
.
quill
const
html
=
quill
.
root
.
innerHTML
const
text
=
quill
.
getText
()
const
delta
=
quill
.
getContents
()
return
{
html
,
text
,
delta
}
},
html2delta
(
html
)
{
const
tags
=
[
'
span
'
,
'
strong
'
,
'
b
'
,
'
ins
'
,
'
em
'
,
'
i
'
,
'
u
'
,
'
a
'
,
'
del
'
,
'
s
'
,
'
sub
'
,
'
sup
'
,
'
img
'
,
'
div
'
,
'
p
'
,
'
h1
'
,
'
h2
'
,
'
h3
'
,
'
h4
'
,
'
h5
'
,
'
h6
'
,
'
hr
'
,
'
ol
'
,
'
ul
'
,
'
li
'
]
let
content
=
''
let
disable
HTMLParser
(
html
,
{
start
:
function
(
tag
,
attrs
,
unary
)
{
if
(
!
tags
.
includes
(
tag
))
{
disable
=
!
unary
return
}
disable
=
false
const
arrts
=
attrs
.
map
(({
name
,
value
})
=>
`
${
name
}
="
${
value
}
"`
).
join
(
'
'
)
const
start
=
`<
${
tag
}
${
arrts
}
${
unary
?
'
/
'
:
''
}
>`
content
+=
start
},
end
:
function
(
tag
)
{
if
(
!
disable
)
{
content
+=
`</
${
tag
}
>`
}
},
chars
:
function
(
text
)
{
if
(
!
disable
)
{
content
+=
text
}
}
})
this
.
skipMatcher
=
true
const
delta
=
this
.
quill
.
clipboard
.
convert
(
content
)
this
.
skipMatcher
=
false
return
delta
}
}
}
</
script
>
<
style
src=
"./editor.css"
></
style
>
<
style
>
</
style
>
src/core/view/mixins/subscriber.js
浏览文件 @
75d36c63
...
...
@@ -19,6 +19,9 @@ export default {
},
beforeDestroy
()
{
// 销毁时移除
this
.
_toggleListeners
(
'
unsubscribe
'
,
this
.
id
)
if
(
this
.
_contextId
)
{
this
.
_toggleListeners
(
'
unsubscribe
'
,
this
.
_contextId
)
}
},
methods
:
{
_toggleListeners
(
type
,
id
,
watch
)
{
...
...
@@ -31,6 +34,18 @@ export default {
}
// 纠正VUniVideo等组件命名为Video
UniViewJSBridge
[
type
](
this
.
$page
.
id
+
'
-
'
+
this
.
$options
.
name
.
replace
(
/VUni
([
A-Z
])
/
,
'
$1
'
).
toLowerCase
()
+
'
-
'
+
id
,
this
.
_handleSubscribe
)
},
_getContextInfo
()
{
const
id
=
`context-
${
this
.
_uid
}
`
if
(
!
this
.
_contextId
)
{
this
.
_toggleListeners
(
'
subscribe
'
,
id
)
this
.
_contextId
=
id
}
return
{
name
:
this
.
$options
.
name
.
replace
(
/VUni
([
A-Z
])
/
,
'
$1
'
).
toLowerCase
(),
id
,
page
:
this
.
$page
.
id
}
}
}
}
src/shared/callback.js
0 → 100644
浏览文件 @
75d36c63
let
id
=
0
const
callbacks
=
{}
function
warp
(
fn
)
{
return
function
(
options
=
{})
{
const
callbackId
=
String
(
id
++
)
callbacks
[
callbackId
]
=
{
success
:
options
.
success
,
fail
:
options
.
fail
,
complete
:
options
.
complete
}
const
data
=
Object
.
assign
({},
options
)
delete
data
.
success
delete
data
.
fail
delete
data
.
complete
const
res
=
fn
.
bind
(
this
)(
data
,
callbackId
)
if
(
res
)
{
invoke
(
callbackId
,
res
)
}
}
}
function
invoke
(
callbackId
,
res
)
{
const
callback
=
callbacks
[
callbackId
]
||
{}
delete
callbacks
[
callbackId
]
const
errMsg
=
res
.
errMsg
||
''
if
(
new
RegExp
(
'
\\
:
\\
s*fail
'
).
test
(
errMsg
))
{
callback
.
fail
&&
callback
.
fail
(
res
)
}
else
{
callback
.
success
&&
callback
.
success
(
res
)
}
callback
.
complete
&&
callback
.
complete
(
res
)
}
export
const
callback
=
{
warp
,
invoke
}
src/shared/index.js
浏览文件 @
75d36c63
...
...
@@ -4,3 +4,4 @@ export * from './color'
export
*
from
'
./query
'
export
*
from
'
./scroll
'
export
*
from
'
./platform
'
export
*
from
'
./callback
'
src/shared/util.js
浏览文件 @
75d36c63
...
...
@@ -21,7 +21,7 @@ export function hasOwn (obj, key) {
return
hasOwnProperty
.
call
(
obj
,
key
)
}
export
function
noop
()
{}
export
function
noop
()
{
}
export
function
toRawType
(
val
)
{
return
_toString
.
call
(
val
).
slice
(
8
,
-
1
)
...
...
@@ -87,4 +87,8 @@ export function debounce (fn, delay) {
const
timerFn
=
()
=>
fn
.
apply
(
this
,
arguments
)
timeout
=
setTimeout
(
timerFn
,
delay
)
}
}
}
export
function
kebabCase
(
string
)
{
return
string
.
replace
(
/
[
A-Z
]
/g
,
str
=>
'
-
'
+
str
.
toLowerCase
())
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录