You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

449 lines
9.6 KiB

import {
Observer
} from './observer.js'
export default class Edit extends Observer {
#_DsEFTEXT;
constructor({context,maxCount}) {
super();
this.deftext = '######################################################NBLSJ######################################################';
this.ctx = context;
this.maxCount = maxCount;
this.textCount = 0;
this.overstep = false;
this.timeoutArr = [];
this.flagArr = [];
this.isSetContents=false;
}
/**
* 撤销undo(),恢复redo(),清空内容clear(),清空当前选区样式removeFormat()
* 插入分割线insertDivider();
* 初始化html内容setContents({html}),设置文本insertText({text})
*/
tool(fn, arg = {}) {
if (typeof(this.ctx[fn]) === 'function') {
this.ctx[fn](arg);
}
return this;
}
// 设置初始html
ready(html) {
this.tool('setContents', {
html
})
}
// 设置字体相关 https://uniapp.dcloud.io/api/media/editor-context?id=editorcontextformat
format(name, value) {
this.ctx.format(name, value);
return this;
}
/**
* 写入表情
*/
emoji(text) {
this.tool('insertText', {text});
return this;
}
/**
* 写入链接
* {
prefix: '#',
suffix: '#',
name:'name',
data: {}
}
*/
addLink({
prefix = '',
suffix = '',
data = {}
}) {
// #ifdef APP-PLUS
this.format('color','#ffffff')
// #endif
this.tool('insertText', {
text: this.deftext
})
.tool('blur')
.getContents()
.then((e) => {
let ops = e.delta.ops,arr = [];
for (let i = 0; i < ops.length; i++) {
let item = ops[i];
if (!item.insert || typeof item.insert === 'object') {
arr.push(item);
continue;
}
let isNext = item.insert.indexOf(this.deftext);
if (isNext > -1) {
if (item.attributes && item.attributes.link) {
delete item.attributes;
}
let [textPrefix,textSuffix] = item.insert.split(this.deftext);
arr.push({...item,insert: textPrefix});
if(typeof data === 'object' && !Array.isArray(data)){
let newObj = {
attributes: {
"link": `${data.user_id}`,
"textDecoration": "none",
"color": "#333",
"pointerEvents":"none"
},
insert: prefix+data.realname
};
arr.push(newObj);
arr.push({insert: ' '});
}else{
data.forEach((item,index)=>{
let newObj = {
attributes: {
"link": `${item.user_id}`,
"textDecoration": "none",
"color": "#333",
"pointerEvents":"none"
},
insert: prefix+item.realname
};
arr.push(newObj);
arr.push({insert: ' '});
})
}
if (textSuffix) {
arr.push({...item,insert: textSuffix});
}
let remainingArr = ops.slice(i+1);
arr = [...arr,...remainingArr];
break;
}
else {
arr.push(item);
}
}
// let insertLen = name.length - this.deftext.length + n;
this.ctx.setContents({
delta: {
ops:arr
},
// insertLen,
complete:()=>{
this.format('fontFamily', 'inherit')
.input();
}
})
})
.catch(err => uni.showToast({
title: '操作失败',
icon: 'error'
}));
}
/**
* 获取所有链接
*/
async getLink() {
let {
delta: {
ops
}
} = await this.getContents();
let arr = [];
ops.forEach(item => {
if (item.attributes && item.attributes.link) {
arr.push(parseInt(item.attributes.link));
}
});
return arr;
}
/**
* 添加图片
* 如传入tempFilePaths则不再通过相册/相机选择
*/
addImage(tempFilePaths) {
const handle = (filePaths)=> {
filePaths.forEach(src => {
this.tool('insertImage', {
src: src,
alt: 'IMAGE'
})
.tool('insertText', {
text: "\n"
})
})
this.tool('scrollIntoView')
return this;
}
if (tempFilePaths) {
return handle(tempFilePaths);
}
return uni.chooseImage({
count: 9, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: (res) => {
return handle(res.tempFilePaths);
}
});
}
/**
* 获取所有图片
*/
async getImages() {
let {
delta: {
ops
}
} = await this.getContents();
let arr = [];
ops.forEach(item => {
if (item.attributes && item.attributes.alt === 'IMAGE') {
arr.push(item.insert.image.replace(/data:image\/png;base64,/, ''));
}
});
return arr;
}
/**
* 替换图片
* @param {Function} fn 返回替换后图片地址
*/
async replaceImage(fn) {
let res = await this.getContents();
let cuops = JSON.stringify(res.delta.ops);
let ops = res.delta.ops;
for (let temp of ops) {
if (typeof temp.insert === "object") {
if ("image" in temp.insert) {
let img = temp.insert.image;
// 将本地图片路径替换为网络路径
temp.insert.image = await fn(img);
}
}
}
if (cuops === JSON.stringify(ops)) {
return res;
}
return await this.tool('setContents', {
delta: {
ops
}
}).getContents();
}
// 获取内容
getContents() {
return new Promise((resolve, reject) => {
this.ctx.getContents({
success: res => {
resolve(res);
}
})
})
}
// 光标进入并唤起键盘
upKeyboard() {
this.tool('blur').format('fontFamily', 'inherit')
return this;
}
/**
* 监听输入框变化是否改变链接
*/
eventLink(detail) {
if (!detail) {return;}
let ops = detail.delta.ops || [];
let jops = JSON.stringify(ops);
if (jops.indexOf(this.deftext) > -1) {
return;
}
this.isSetContents=false;
for (let i = 0, len = ops.length; i < len; i++) {
let item = ops[i];
let isLink = item.attributes && item.attributes.link;
if (isLink) {
let nextText = ops[i + 1].insert;
if (nextText && (nextText.indexOf('\\n') ===0 || nextText.indexOf(' ') ===0)) {
continue;
}
ops.splice(i, 1, {
insert: ''
});
this.isSetContents=true;
break;
}
}
if (this.isSetContents) {
this.tool('blur')
this.ctx.setContents({
delta: {ops},
complete:()=>{
this.input();
// #ifdef APP-PLUS
setTimeout(()=>{
this.upKeyboard();
},100)
// #endif
}
})
}
else {
this.input(detail);
}
}
// 检查字数是否超出
eventTextLenght(detail) {
this.textCount = detail.text.length - 1;
if (this.maxCount && this.textCount > this.maxCount) {
return true;
}
return false
}
// 监听输入框变化
async input(detail) {
if (!detail) {detail = await this.getContents();}
if (detail.text.indexOf(this.deftext) < 0) {
this.overstep = this.eventTextLenght(detail)
detail['overstep'] = this.overstep;
this.$fire('edit:input', detail);
}
}
// 监听样式变化
statuschange({detail}) {
if (detail.link) {
this.ctx.blur();
return;
}
this.debounce(()=> {
this.$fire('edit:statuschange', detail);
}, 100,false);
}
// 监听焦点进入
focus({
detail
}) {
this.debounce(()=> {
this.input(detail);
}, 100,false);
}
// 监听焦点离开
blur({
detail
}) {
this.debounce(()=> {
this.$fire('edit:blur', detail);
}, 100,false);
}
debounce(fn, time = 500, isImmediate = true, timeoutName = "default") {
// 清除定时器
if(!this.timeoutArr[timeoutName]) this.timeoutArr[timeoutName] = null;
if (this.timeoutArr[timeoutName] !== null) clearTimeout(this.timeoutArr[timeoutName]);
// 立即执行一次
if (isImmediate) {
var callNow = !this.timeoutArr[timeoutName];
this.timeoutArr[timeoutName] = setTimeout(function() {
this.timeoutArr[timeoutName] = null;
}, time);
if (callNow){
if(typeof fn === 'function') fn();
}
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时time毫秒后执行fn回调方法
this.timeoutArr[timeoutName] = setTimeout(function() {
if(typeof fn === 'function') fn();
}, time);
}
}
queryParamsReverse(locationhref) {
let href = locationhref || "";
let theRequest = new Object();
let str = href.split("?")[1];
if (str != undefined) {
let strs = str.split("&");
for (let i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = (strs[i].split("=")[1]);
}
}
return theRequest;
}
queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
let newData = JSON.parse(JSON.stringify(data));
let prefix = isPrefix ? '?' : ''
let _result = []
if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets';
for (let key in newData) {
let value = newData[key]
// 去掉为空的参数
if (['', undefined, null].indexOf(value) >= 0) {
continue;
}
// 如果值为数组,另行处理
if (value.constructor === Array) {
// e.g. {ids: [1, 2, 3]}
switch (arrayFormat) {
case 'indices':
// 结果: ids[0]=1&ids[1]=2&ids[2]=3
for (let i = 0; i < value.length; i++) {
_result.push(key + '[' + i + ']=' + value[i])
}
break;
case 'brackets':
// 结果: ids[]=1&ids[]=2&ids[]=3
value.forEach(_value => {
_result.push(key + '[]=' + _value)
})
break;
case 'repeat':
// 结果: ids=1&ids=2&ids=3
value.forEach(_value => {
_result.push(key + '=' + _value)
})
break;
case 'comma':
// 结果: ids=1,2,3
let commaStr = "";
value.forEach(_value => {
commaStr += (commaStr ? "," : "") + _value;
})
_result.push(key + '=' + commaStr)
break;
default:
value.forEach(_value => {
_result.push(key + '[]=' + _value)
})
}
} else {
_result.push(key + '=' + value)
}
}
return _result.length ? prefix + _result.join('&') : ''
}
}