2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
@@ -0,0 +1,169 @@
// @ts-expect-error
import type { Callback } from '../../index.uts'
type SocketInstanceData = {
instance: SocketTask,
isOpend: boolean,
openData?: OnSocketOpenCallbackResult | null
}
const socketInstanceMap = new Map<string, SocketInstanceData>()
export const connectSocket = (id: string, url: string, callback: Callback): void => {
const socketTask = uni.connectSocket({
url,
success() {
callback({ result: { errMsg: 'connectSocket:ok' } }, null)
},
fail() {
callback(null, { errMsg: 'connectSocket:fail' })
}
})
socketInstanceMap.set(id, { instance: socketTask, isOpend: false } as SocketInstanceData)
socketTask.onOpen((data: OnSocketOpenCallbackResult) => {
socketInstanceMap.get(id)!.isOpend = true
socketInstanceMap.get(id)!.openData = data
})
}
export type FirstSocketTaskEmitterParams = {
method: string,
data?: any | null,
code?: number | null,
reason?: string | null,
}
export const firstSocketTaskEmitter = (params: FirstSocketTaskEmitterParams, callback: Callback): void => {
let socketInstanceData: SocketInstanceData | null = null;
socketInstanceMap.forEach((value: SocketInstanceData) => {
if (socketInstanceData == null) {
socketInstanceData = value
}
})
if (socketInstanceData == null) {
callback(null, { errMsg: "socketTask not exists." });
} else {
const _socketInstanceData = socketInstanceData as SocketInstanceData
const socketTask = _socketInstanceData.instance
if (params.method == 'onOpen') {
const isOpend = _socketInstanceData.isOpend
if (isOpend) {
callback(_socketInstanceData.openData, null)
} else {
let timer: number | null = null
// @ts-expect-error
timer = setInterval(() => {
if (_socketInstanceData.isOpend) {
clearInterval(timer!)
callback(_socketInstanceData.openData, null)
}
}, 200)
setTimeout(() => {
// @ts-expect-error
clearInterval(timer)
}, 2000)
}
} else if (params.method == 'onMessage') {
socketTask.onMessage((data: any) => {
callback(data, null)
})
} else if (params.method == 'onClose') {
socketTask.onClose((data: any) => {
callback(data, null)
})
} else if (params.method == 'onError') {
socketTask.onError((data: any) => {
callback(data, null)
})
} else if (params.method == 'send') {
socketTask.send({
data: params.data!,
success(result: any) {
callback({ result }, null)
},
fail(error: any) {
callback(null, error)
}
} as SendSocketMessageOptions)
} else if (params.method == 'close') {
socketTask.close({
code: params.code,
reason: params.reason,
success(result: any) {
callback({ result }, null)
socketInstanceMap.clear();
},
fail(error: any) {
callback(null, error)
}
} as CloseSocketOptions)
}
}
}
export type SocketEmitterParams = {
id: string,
method: string,
data?: any | null,
code?: number | null,
reason?: string | null,
}
export const socketEmitter = (params: SocketEmitterParams, callback: Callback): void => {
if (!socketInstanceMap.has(params.id)) {
callback(null, { errMsg: 'socketTask not exists.' })
} else {
const socketInstanceData = socketInstanceMap.get(params.id)!
const socketTask = socketInstanceData.instance
if (params.method == 'onOpen') {
const isOpend = socketInstanceData.isOpend
if (isOpend) {
callback({ method: 'Socket.onOpen', id: params.id, data: socketInstanceData.openData }, null)
} else {
let timer: number | null = null
// @ts-expect-error
timer = setInterval(() => {
if (socketInstanceData.isOpend) {
clearInterval(timer!)
callback({ method: 'Socket.onOpen', id: params.id, data: socketInstanceData.openData }, null)
}
}, 200)
setTimeout(() => {
// @ts-expect-error
clearInterval(timer)
}, 2000)
}
} else if (params.method == 'onMessage') {
socketTask.onMessage((data: any) => {
callback({ method: 'Socket.onMessage', id: params.id, data }, null)
})
} else if (params.method == 'onClose') {
socketTask.onClose((data: any) => {
callback({ method: 'Socket.onClose', id: params.id, data }, null)
})
} else if (params.method == 'onError') {
socketTask.onError((data: any) => {
callback({ method: 'Socket.onError', id: params.id, data }, null)
})
} else if (params.method == 'send') {
socketTask.send({
data: params.data!,
success(result: any) {
callback(result, null)
},
fail(error: any) {
callback(null, error)
}
} as SendSocketMessageOptions)
} else if (params.method == 'close') {
socketTask.close({
code: params.code,
reason: params.reason,
success(result: any) {
callback(result, null)
socketInstanceMap.delete(params.id);
},
fail(error: any) {
callback(null, error)
}
} as CloseSocketOptions)
}
}
}
@@ -0,0 +1,459 @@
// @ts-expect-error
import type { Callback } from '../../index.uts'
// @ts-expect-error
import { parsePage } from '../util.uts'
// @ts-expect-error
import { send } from '../../index.uts'
import {
type FirstSocketTaskEmitterParams,
connectSocket,
firstSocketTaskEmitter,
// @ts-expect-error
} from './Socket.uts'
export const getPageStack = (callback: Callback): void => {
callback(
{
// @ts-expect-error
pageStack: getCurrentPages().map((page: UniPage): UTSJSONObject => {
return parsePage(page.vm!)
}),
},
null
)
}
export type GetCurrentPageParams = {
// @ts-expect-error
callback: (result: UTSJSONObject | null, error: any | null) => void
}
function _getCurrentPage(): Page | null {
const pages = getCurrentPages() as UniPage[]
return pages.length > 0 ? pages[pages.length - 1].vm! : null
}
export const getCurrentPage = (params: GetCurrentPageParams): void => {
const page = _getCurrentPage()
const result = page != null ? parsePage(page) : null
params.callback(result, null)
}
export type CallUniMethodParams = {
method: string
args: any[]
}
export const callUniMethod = (
params: CallUniMethodParams,
callback: Callback
): void => {
const method = params.method
const args = params.args
const success = (result: any) => {
const timeout = method == 'pageScrollTo' ? 350 : 0
setTimeout(() => {
callback({ result }, null)
}, timeout)
}
const onApiCallback = (data: any | null, _: any | null) => {
const id = args[0] as string
send({ id, result: { method, data } })
}
switch (method) {
case 'navigateTo':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.navigateTo({
url: _arg['url'] as string,
// @ts-expect-error
animationType:
_arg['animationType'] != null
? (_arg['animationType'] as string)
: 'pop-in',
animationDuration:
_arg['animationDuration'] != null
? (_arg['animationDuration'] as number)
: 300,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'redirectTo':
uni.redirectTo({
// @ts-expect-error
url: new UTSJSONObject(args[0])['url'] as string,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'reLaunch':
uni.reLaunch({
// @ts-expect-error
url: new UTSJSONObject(args[0])['url'] as string,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'navigateBack':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.navigateBack({
// @ts-expect-error
animationType:
_arg['animationType'] != null
? (_arg['animationType'] as string)
: 'pop-out',
animationDuration:
_arg['animationDuration'] != null
? (_arg['animationDuration'] as number)
: 300,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'switchTab':
uni.switchTab({
// @ts-expect-error
url: new UTSJSONObject(args[0])['url'] as string,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'getStorage':
uni.getStorage({
// @ts-expect-error
key: new UTSJSONObject(args[0])['key'] as string,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'setStorage':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.setStorage({
key: _arg['key'] as string,
data: _arg['data']!,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'getStorageSync':
callback({ result: uni.getStorageSync(args[0] as string) }, null)
break
case 'setStorageSync':
callback({ result: uni.setStorageSync(args[0] as string, args[1]) }, null)
break
case 'getStorageInfo':
uni.getStorageInfo({
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'getStorageInfoSync':
callback({ result: uni.getStorageInfoSync() }, null)
break
case 'removeStorage':
uni.removeStorage({
// @ts-expect-error
key: new UTSJSONObject(args[0])['key'] as string,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'removeStorageSync':
callback({ result: uni.removeStorageSync(args[0] as string) }, null)
break
case 'clearStorage':
// @ts-expect-error
uni.clearStorage({
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'clearStorageSync':
callback({ result: uni.clearStorageSync() }, null)
break
case 'showToast':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.showToast({
title: _arg['title'] as string,
// @ts-expect-error
icon: _arg['icon'] != null ? (_arg['icon'] as string) : 'success',
// @ts-expect-error
image:
_arg['image'] != null && _arg['image'] != ''
? (_arg['image'] as string)
: null,
mask: _arg['mask'] != null ? (_arg['mask'] as boolean) : false,
duration:
_arg['duration'] != null ? (_arg['duration'] as number) : 1500,
// @ts-expect-error
position:
_arg['position'] != null ? (_arg['position'] as string) : null,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'hideToast':
uni.hideToast()
break
case 'showLoading':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.showLoading({
title: _arg['title'] as string,
mask: _arg['mask'] != null ? (_arg['mask'] as boolean) : false,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'hideLoading':
uni.hideLoading()
break
case 'showModal':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.showModal({
// @ts-expect-error
title: _arg['title'] != null ? (_arg['title'] as string) : null,
// @ts-expect-error
content: _arg['content'] != null ? (_arg['content'] as string) : null,
showCancel:
_arg['showCancel'] != null ? (_arg['showCancel'] as boolean) : true,
// @ts-expect-error
cancelText:
_arg['cancelText'] != null ? (_arg['cancelText'] as string) : null,
// @ts-expect-error
cancelColor:
_arg['cancelColor'] != null ? (_arg['cancelColor'] as string) : null,
// @ts-expect-error
confirmText:
_arg['confirmText'] != null ? (_arg['confirmText'] as string) : null,
// @ts-expect-error
confirmColor:
_arg['confirmColor'] != null
? (_arg['confirmColor'] as string)
: null,
editable:
_arg['editable'] != null ? (_arg['editable'] as boolean) : false,
// @ts-expect-error
placeholderText:
_arg['placeholderText'] != null
? (_arg['placeholderText'] as string)
: null,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'showActionSheet':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.showActionSheet({
// @ts-expect-error
title: _arg['title'] != null ? (_arg['title'] as string) : null,
// @ts-expect-error
itemList: JSON.parse<string[]>(JSON.stringify(_arg['itemList']))!,
// @ts-expect-error
itemColor:
_arg['itemColor'] != null ? (_arg['itemColor'] as string) : null,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'connectSocket':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
connectSocket(_arg['id'] as string, _arg['url'] as string, callback)
break
case 'onSocketOpen':
firstSocketTaskEmitter(
{ method: 'onOpen' } as FirstSocketTaskEmitterParams,
onApiCallback
)
break
case 'onSocketMessage':
firstSocketTaskEmitter(
{ method: 'onMessage' } as FirstSocketTaskEmitterParams,
onApiCallback
)
break
case 'onSocketError':
firstSocketTaskEmitter(
{ method: 'onError' } as FirstSocketTaskEmitterParams,
onApiCallback
)
break
case 'onSocketClose':
firstSocketTaskEmitter(
{ method: 'onClose' } as FirstSocketTaskEmitterParams,
onApiCallback
)
break
case 'sendSocketMessage':
firstSocketTaskEmitter(
{
method: 'send',
// @ts-expect-error
data: new UTSJSONObject(args[0])['data'],
} as FirstSocketTaskEmitterParams,
callback
)
break
case 'closeSocket':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
firstSocketTaskEmitter(
{
method: 'close',
code: _arg['code'] as number,
reason: _arg['reason'] as string,
} as FirstSocketTaskEmitterParams,
callback
)
break
case 'getSystemInfo':
uni.getSystemInfo({
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'getSystemInfoSync':
callback({ result: uni.getSystemInfoSync() }, null)
break
case 'getDeviceInfo':
callback({ result: uni.getDeviceInfo() }, null)
break
case 'getSystemSetting':
callback({ result: uni.getSystemSetting() }, null)
break
case 'getAppBaseInfo':
callback({ result: uni.getAppBaseInfo() }, null)
break
case 'getAppAuthorizeSetting':
callback({ result: uni.getAppAuthorizeSetting() }, null)
break
case 'openAppAuthorizeSetting':
uni.openAppAuthorizeSetting({
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
case 'pageScrollTo':
// @ts-expect-error
const _arg = new UTSJSONObject(args[0])
uni.pageScrollTo({
scrollTop: _arg['scrollTop'] as number,
duration: _arg['duration'] as number,
success,
fail(error) {
error.errMsg = error.errMsg.replace(`${method}: fail `, '')
callback(null, error)
},
})
break
default:
callback(null, { errMsg: 'uni.' + method + ' not exists.' })
break
}
}
export type CaptureScreenshotParams = {
id?: string | null
fullPage?: boolean | null
path?: string | null
offsetX?: string | null
offsetY?: string | null
}
export const captureScreenshot = (
params: CaptureScreenshotParams,
callback: Callback
): void => {
const currentPage = _getCurrentPage()
if (currentPage != null) {
// @ts-expect-error
currentPage.$viewToTempFilePath({
id: params.id,
offsetX: params.offsetX !== null ? params.offsetX : '0',
offsetY: params.offsetY !== null ? params.offsetY : '0',
wholeContent: params.fullPage == true,
path: params.path,
success: (res) => {
const fileManager = uni.getFileSystemManager()
// @ts-expect-error
fileManager.readFile({
encoding: 'base64',
filePath: res.tempFilePath,
success(readFileRes) {
callback(
{
errMsg: 'screenshot:ok',
tempFilePath: res.tempFilePath,
data: readFileRes.data,
},
null
)
},
fail(error) {
callback(null, error)
},
} as ReadFileOptions)
},
fail: (error) => {
callback(null, error)
},
})
} else {
callback(null, { errMsg: `currentPage is not found.` })
}
}
@@ -0,0 +1,644 @@
// @ts-expect-error
import type { Callback } from '../index.uts'
import {
componentGetData,
componentSetData,
getComponentVmByNodeId,
getComponentVmBySelector,
getElementById,
getElementByIdOrNodeId,
getElementByNodeIdOrElementId,
getValidNodes,
removeUniPrefix,
// @ts-expect-error
} from './util.uts'
// @ts-expect-error
import { getChildrenText, toCamelCase } from './util.uts'
export type GetElementParams = {
pageId: string
nodeId?: number | null
elementId?: string | null
selector: string
}
export const getElement = (
params: GetElementParams,
callback: Callback
): void => {
// TODO: support get component by class or id selector
const element = getElementByNodeIdOrElementId(
params.pageId,
params.nodeId,
params.elementId,
callback
)
if (element != null) {
if (params.selector.startsWith('uni-')) {
const selector = removeUniPrefix(params.selector)
const component = getComponentVmBySelector(
params.pageId,
selector,
callback
)
const result = {
nodeId: component != null ? component.$.uid : null,
tagName: component != null ? selector : null,
elementId: component != null ? `${Date.now()}` : null,
}
callback(result, null)
return
}
// @ts-expect-error
const list: UTSJSONObject[] = []
getValidNodes(element, params.selector, list)
if (list.length > 0) {
callback(list[0], null)
} else {
callback(null, { errMsg: `Element[${params.selector}] not exists` })
}
}
}
export const getElements = (
params: GetElementParams,
callback: Callback
): void => {
const element = getElementByNodeIdOrElementId(
params.pageId,
params.nodeId,
params.elementId,
callback
)
if (element != null) {
// @ts-expect-error
const list: UTSJSONObject[] = []
getValidNodes(element, removeUniPrefix(params.selector), list, true)
callback({ elements: list }, null)
}
}
export type GetDOMPropertiesParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
names: string[]
}
export const getDOMProperties = (
params: GetDOMPropertiesParams,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const properties = params.names.map((name: string): any | null => {
if (name == 'innerText') {
// @ts-expect-error
if (isTextElement(dom)) {
return dom.getAttribute('value')
} else {
return getChildrenText(dom)
}
}
if (name == 'value') {
return dom.getAttribute('value')
}
if (name == 'offsetWidth') {
return dom.offsetWidth
}
if (name == 'offsetHeight') {
return dom.offsetHeight
}
return `Element.getDOMProperties not support ${name}`
})
callback({ properties }, null)
}
}
export type GetPropertiesParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
names: string[]
}
export const getProperties = (
params: GetPropertiesParams,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
// @ts-expect-error
let component: ComponentPublicInstance | null = null
if (params.nodeId != null) {
component = getComponentVmByNodeId(params.pageId, params.nodeId!, callback)
}
const properties = params.names.map((name: string): any | null => {
if (component != null && component.$props[toCamelCase(name)] != null) {
return component.$props[toCamelCase(name)]
}
if (dom != null) {
return dom.getAttribute(name)
}
return null
})
callback({ properties }, null)
}
export type GetAttributesParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
names: string[]
}
export const getAttributes = (
params: GetAttributesParams,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const attributes = params.names.map((name: string): any | null => {
if (name == 'class') {
return dom.classList.join(' ')
}
return dom.getAttribute(name)
})
callback({ attributes }, null)
}
}
export type CallFunctionParams = {
pageId: string
elementId: string
functionName: string
args: any[]
}
type Coordinate = {
x: number
y: number
}
export const callFunction = (
params: CallFunctionParams,
callback: Callback
): void => {
const element = getElementById(params.pageId, params.elementId, callback)
if (element != null) {
const functionName = params.functionName
switch (functionName) {
case 'input.input':
element.dispatchEvent(
'input',
new InputEvent(
'input',
// @ts-expect-error
InputEventDetail(params.args[0] as string, 0, 0)
)
)
callback({ result: `${functionName} success` }, null)
break
case 'textarea.input':
element.dispatchEvent(
'input',
new InputEvent(
'input',
// @ts-expect-error
InputEventDetail(params.args[0] as string, 0, 0)
)
)
callback({ result: `${functionName} success` }, null)
break
case 'scroll-view.scrollTo':
if (element.tagName == 'SCROLL-VIEW') {
const x: number = params.args[0] as number
const y: number = params.args[1] as number
element.scrollLeft = x
element.scrollTop = y
callback({ result: `${functionName} success` }, null)
} else {
callback(null, {
errMsg: `${functionName} fail, element is not scroll-view`,
})
}
break
case 'swiper.swipeTo':
if (element.tagName == 'SWIPER') {
callback(null, { errMsg: `${functionName} not support` })
} else {
callback(null, {
errMsg: `${functionName} fail, element is not swiper`,
})
return
}
break
case 'scroll-view.scrollWidth':
if (element.tagName == 'SCROLL-VIEW') {
callback({ result: element.scrollWidth }, null)
} else {
callback(null, {
errMsg: `${functionName} fail, element is not scroll-view`,
})
return
}
break
case 'scroll-view.scrollHeight':
if (element.tagName == 'SCROLL-VIEW') {
callback({ result: element.scrollHeight }, null)
} else {
callback(null, {
errMsg: `${functionName} fail, element is not scroll-view`,
})
return
}
break
case 'scroll-view.scrollTop':
if (element.tagName == 'SCROLL-VIEW') {
callback({ result: element.scrollTop }, null)
} else {
callback(null, {
errMsg: `${functionName} fail, element is not scroll-view`,
})
return
}
break
case 'scroll-view.scrollLeft':
if (element.tagName == 'SCROLL-VIEW') {
callback({ result: element.scrollLeft }, null)
} else {
callback(null, {
errMsg: `${functionName} fail, element is not scroll-view`,
})
return
}
break
default:
callback(null, { errMsg: `${functionName} not support` })
break
}
} else {
callback(null, { errMsg: `Element not exists` })
}
}
export type TapParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
}
export const tap = (params: TapParams, callback: Callback): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const num = 0
// @ts-expect-error
const _float = num.toFloat()
dom.dispatchEvent(
'click',
new MouseEvent(
'click',
_float,
// @ts-expect-error
_float,
_float,
_float,
_float,
_float,
_float,
_float
)
)
callback({ result: `Element.tap success` }, null)
}
}
export type CallMethodParams = {
pageId: string
nodeId: number
method: string
args: any[]
}
export const callMethod = (
params: CallMethodParams,
callback: Callback
): void => {
const component = getComponentVmByNodeId(
params.pageId,
params.nodeId,
callback
)
if (component != null) {
const result =
params.args.length > 0
? component.$callMethod(params.method, params.args[0])
: component.$callMethod(params.method)
// @ts-expect-error
if (result instanceof Promise<unknown>) {
; (result as Promise<any>)
.then((res: any) => {
callback({ result: res }, null)
})
.catch((err) => {
const errMsg = err instanceof Error ? err.message : err
callback({ result: errMsg }, null)
})
} else {
callback({ result }, null)
}
}
}
export type GetDataParams = {
pageId: string
nodeId: number
path?: string | null
}
export const getData = (params: GetDataParams, callback: Callback): void => {
const component = getComponentVmByNodeId(
params.pageId,
params.nodeId,
callback
)
if (component != null) {
const data = componentGetData(component)
callback({ data }, null)
}
}
export type SetDataParams = {
pageId: string
nodeId: number
data: Map<string, any | null>
}
export const setData = (params: SetDataParams, callback: Callback): void => {
const component = getComponentVmByNodeId(
params.pageId,
params.nodeId,
callback
)
if (component != null) {
componentSetData(component, params.data)
callback({ result: { errMsg: 'Page.setData: ok.' } }, null)
}
}
export type GetOffsetParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
}
export const getOffset = (
params: GetOffsetParams,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
callback({ left: dom.offsetLeft, top: dom.offsetTop }, null)
}
}
export type LongpressParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
}
export const longpress = (
params: LongpressParams,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const x: number = 0
const y: number = 0
dom.dispatchEvent(
'longpress',
new TouchEvent(
null,
'longpress',
// @ts-expect-error
getTouches([
{
identifier: 1,
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
screenX: 0,
screenY: 0,
},
]),
getTouches([
{
identifier: 1,
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
screenX: 0,
screenY: 0,
},
])
)
)
callback({ result: `Element.longpress success` }, null)
}
}
export type HandleTouchEventParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
touches: any[]
changedTouches: any[]
}
export const handleTouchEvent = (
params: HandleTouchEventParams,
eventName: string,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const touches = getTouches(params.touches)
const changedTouches = getTouches(params.changedTouches)
dom.dispatchEvent(
eventName,
// @ts-expect-error
new TouchEvent(null, eventName, touches, changedTouches)
)
callback({ result: `Element.${eventName} success` }, null)
}
}
type TypeTouch = {
identifier: number
pageX: number
pageY: number
screenX?: number | null
screenY?: number | null
clientX?: number | null
clientY?: number | null
}
function getTouches(touches: any[]): Touch[] {
return touches.map((touch): Touch => {
// @ts-expect-error
const touchObj = JSON.parse<TypeTouch>(JSON.stringify(touch))!
// @ts-expect-error
const result = Touch()
result.identifier = touchObj.identifier.toFloat()
result.pageX = touchObj.pageX.toFloat()
result.pageY = touchObj.pageY.toFloat()
if (touchObj.screenX !== null) {
result.screenX = touchObj.screenX!.toFloat()
}
if (touchObj.screenY !== null) {
result.screenY = touchObj.screenY!.toFloat()
}
if (touchObj.clientX !== null) {
result.clientX = touchObj.clientX!.toFloat()
}
if (touchObj.clientY !== null) {
result.clientY = touchObj.clientY!.toFloat()
}
return result
})
}
export type GetStylesParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
names: string[]
}
export const getStyles = (
params: GetStylesParams,
callback: Callback
): void => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const styles = params.names.map((name: string): any | null => {
return dom.style.getPropertyValue(name)
})
callback({ styles }, null)
}
}
type CustomEventDetail = {
value?: string
}
export type TriggerEventParams = {
pageId: string
elementId?: string | null
nodeId?: number | null
type: string
detail?: CustomEventDetail | null
}
export const triggerEvent = (
params: TriggerEventParams,
callback: Callback
) => {
const dom = getElementByIdOrNodeId(
params.pageId,
params.elementId,
params.nodeId,
callback
)
if (dom != null) {
const tagName = dom.tagName.toLocaleLowerCase()
const type = params.type
const detail = params.detail
const functionName = `${tagName}.${type}`
switch (functionName) {
case 'input.input':
dom.dispatchEvent(
type,
new UniInputEvent(
type,
// @ts-expect-error
UniInputEventDetail(detail === null ? '' : detail.value!, 0, 0)
)
)
callback({ result: `${functionName} success` }, null)
break
case 'input.focus':
dom.dispatchEvent(
type,
new UniInputFocusEvent(
type,
new InputFocusEventDetail(300, '')
)
)
callback({ result: `${functionName} success` }, null)
break
case 'input.blur':
dom.dispatchEvent(
type,
new UniInputBlurEvent(
type,
new UniInputBlurEventDetail('', 10)
)
)
callback({ result: `${functionName} success` }, null)
break
case 'textarea.input':
dom.dispatchEvent(
type,
new UniInputEvent(
type,
// @ts-expect-error
UniInputEventDetail(detail === null ? '' : detail.value!, 0, 0)
)
)
callback({ result: `${functionName} success` }, null)
break
}
callback(null, {
errMsg: `${functionName} not exists`,
})
}
}
+127
View File
@@ -0,0 +1,127 @@
// @ts-expect-error
import type { Callback } from '../index.uts'
// @ts-expect-error
import { getPageVm, getValidComponentsOrNodes, pageGetData, pageSetData, removeUniPrefix } from './util.uts'
export type GetDataParams = {
pageId: string
path?: string | null
}
export const getData = (params: GetDataParams, callback: Callback): void => {
const page = getPageVm(params.pageId)
if (page == null) {
callback(null, { errMsg: 'Page.getData:fail, Page not found.' })
return
}
const data = pageGetData(page)
callback({ data }, null)
}
export type SetDataParams = {
pageId: string
data: Map<string, any | null>
}
export const setData = (params: SetDataParams, callback: Callback): void => {
const pageId = params.pageId
const page = getPageVm(pageId)
if (page != null) {
pageSetData(page, params.data)
callback({ result: { errMsg: 'Page.setData: ok.' } }, null)
} else {
callback(null, { errMsg: `Page.setData:fail, Page:${pageId} is not found.` })
}
}
export type CallMethodParams = {
pageId: string
method: string
args: any[]
}
export const callMethod = (params: CallMethodParams, callback: Callback): void => {
const page = getPageVm(params.pageId)
if (page == null) {
callback(null, { errMsg: `Page[${params.pageId}] not exists` })
// @ts-expect-error
} else if (findVueMethod(page.$.type.type, params.method, page) == null) {
callback(null, { errMsg: `Page.${params.method} not exists` })
} else {
const result = params.args.length > 0 ? page.$callMethod(params.method, params.args[0]) : page.$callMethod(params.method)
// @ts-expect-error
if (result instanceof Promise<unknown>) {
(result as Promise<any>).then((res: any) => {
callback({ result: res }, null)
}).catch((err) => {
const errMsg = err instanceof Error ? err.message : err
callback({ result: errMsg }, null)
})
} else {
callback({ result }, null)
}
}
}
export type GetElementParams = {
pageId: string
selector: string
}
export const getElement = (params: GetElementParams, callback: Callback): void => {
const page = getPageVm(params.pageId)
if (page == null) {
callback(null, { errMsg: `Page[${params.pageId}] not exists` })
} else {
// @ts-expect-error
const list: UTSJSONObject[] = []
getValidComponentsOrNodes(page.$.subTree, removeUniPrefix(params.selector), list)
if (list.length > 0) {
callback(list[0], null)
} else {
callback(null, { errMsg: `Element[${params.selector}] not exists` })
}
}
}
export const getElements = (params: GetElementParams, callback: Callback): void => {
const page = getPageVm(params.pageId)
if (page == null) {
callback(null, { errMsg: `Page[${params.pageId}] not exists` })
} else {
const elements = page.$querySelectorAll(removeUniPrefix(params.selector))
// @ts-expect-error
const result = [] as UTSJSONObject[]
elements?.forEach(element => {
result.push({
elementId: element.getNodeId(),
tagName: element.tagName
})
})
callback({ elements: result }, null)
}
}
export type GetWindowPropertiesParams = {
pageId: string,
names: string[]
}
export const getWindowProperties = (params: GetWindowPropertiesParams, callback: Callback): void => {
const page = getPageVm(params.pageId)
if (page == null) {
callback(null, { errMsg: 'Page.getWindowProperties:fail, Page not found.' })
return
}
const document = page.$nativePage!.document
const rootNode = document.childNodes[0]
const properties = params.names.map((name): any | null => {
switch (name) {
case 'document.documentElement.scrollWidth':
return rootNode.scrollWidth
case 'document.documentElement.scrollHeight':
return rootNode.scrollHeight
case 'document.documentElement.scrollTop':
return rootNode.scrollTop
}
return null
})
callback({ properties }, null)
}
+323
View File
@@ -0,0 +1,323 @@
/// <reference types="@dcloudio/uni-app-x/types/native-global" />
/// <reference types="@dcloudio/uni-app-x/types/page" />
// @ts-expect-error
import type { IUniNativeDocument } from 'io.dcloud.uniapp.dom'
function getPageId(page: Page): string {
return page.$nativePage!.pageId
}
function getPagePath(page: Page): string {
return page.route
}
// @ts-expect-error
function getPageQuery(page: Page): UTSJSONObject {
return page.options
}
function getPageById(id: string): Page | null {
const pages = getCurrentPages() as UniPage[]
let result: Page | null = null
pages.forEach((page: UniPage) => {
if (getPageId(page.vm!) == id) {
result = page.vm!
}
})
return result
}
export function getPageVm(id: string): Page | null {
return getPageById(id)
}
export function pageGetData(
vm: Page
// @ts-expect-error
): UTSJSONObject {
// TODO: path 目前无法处理类型问题,暂由服务端处理
// @ts-expect-error
if (vm.$.exposed.size > 0) {
// @ts-expect-error
return new UTSJSONObject(vm.$.exposed)
}
// @ts-expect-error
return new UTSJSONObject(vm.$data)
}
export function pageSetData(vm: Page, data: Map<string, any | null>): void {
data.forEach((value: any | null, key: string) => {
// @ts-expect-error
vm.$data.set(key, value)
})
}
// @ts-expect-error
export function parsePage(page: Page): UTSJSONObject {
return {
id: getPageId(page),
path: getPagePath(page),
query: getPageQuery(page),
// @ts-expect-error
} as UTSJSONObject
}
export function getComponentVmBySelector(
pageId: string,
selector: string,
callback: (result: any | null, error: any | null) => void
// @ts-expect-error
): ComponentPublicInstance | null {
const page = getPageVm(pageId)
if (page == null) {
callback(null, { errMsg: `Page[${pageId}] not exists` })
return null
}
// @ts-expect-error
const component = page.$children.find(
// @ts-expect-error
(child: ComponentPublicInstance): boolean => child.$options.name == selector
)
if (component == null) {
callback(null, { errMsg: `component[${selector}] not exists` })
return null
}
return component
}
export function getComponentVmByNodeId(
pageId: string,
nodeId: number,
callback: (result: any | null, error: any | null) => void
// @ts-expect-error
): ComponentPublicInstance | null {
const page = getPageVm(pageId)
if (page == null) {
callback(null, { errMsg: `Page[${pageId}] not exists` })
return null
}
// @ts-expect-error
let component: ComponentPublicInstance | null = null
// @ts-expect-error
function getComponentChild(parent: ComponentPublicInstance) {
// @ts-expect-error
if (parent.$.uid.toInt() == nodeId.toInt()) {
component = parent
return
}
// @ts-expect-error
parent.$children.forEach((child: ComponentPublicInstance) => {
getComponentChild(child)
})
}
getComponentChild(page)
if (component == null) {
callback(null, { errMsg: `component[${nodeId}] not exists` })
return null
}
return component
}
export function getElementByIdOrNodeId(
pageId: string,
elementId: string | null,
nodeId: number | null,
callback: (result: any | null, error: any | null) => void
): UniElement | null {
if (nodeId != null) {
return getComponentDomByNodeId(pageId, nodeId, callback)
} else if (elementId != null) {
return getElementById(pageId, elementId, callback)
}
return null
}
export function getComponentDomByNodeId(
pageId: string,
nodeId: number,
callback: (result: any | null, error: any | null) => void
): UniElement | null {
const component = getComponentVmByNodeId(pageId, nodeId, callback)
if (component == null) {
return null
}
return component.$el
}
export function getElementByNodeIdOrElementId(
pageId: string,
nodeId: number | null,
elementId: string | null,
callback: (result: any | null, error: any | null) => void
): UniElement | null {
const page = getPageVm(pageId)
if (page == null) {
callback(null, { errMsg: `Page[${pageId}] not exists` })
return null
}
if (nodeId != null) {
return getComponentDomByNodeId(pageId, nodeId, callback)
} else if (elementId != null) {
return getElementById(pageId, elementId, callback)
}
return null
}
export function getElementById(
pageId: string,
elementId: string,
callback: (result: any | null, error: any | null) => void
): UniElement | null {
const page = getPageVm(pageId)
if (page == null) {
callback(null, { errMsg: `Page[${pageId}] not exists` })
return null
}
const document = page.$nativePage!.document
const element = (document as IUniNativeDocument).getNativeElementById(
elementId
)
if (element == null) {
callback(null, { errMsg: `element[${elementId}] not exists` })
return null
}
return element
}
export function getValidComponentsOrNodes(
// @ts-expect-error
vnode: VNode | null,
selector: string,
// @ts-expect-error
list: UTSJSONObject[],
getAll = false
): void {
if (vnode == null || (!getAll && list.length > 0)) {
return
}
if (isValidComponentOrNode(vnode, selector)) {
if (vnode.component != null) {
list.push({
// @ts-expect-error
nodeId: (vnode.component as ComponentInternalInstance).uid,
// @ts-expect-error
tagName: (vnode.component as ComponentInternalInstance).options.name,
elementId: `${Date.now()}`,
})
} else {
list.push({
// @ts-expect-error
elementId: (vnode.el as UniElementImpl).id,
tagName: vnode.el!.tagName,
})
}
if (!getAll) {
return
}
}
// @ts-expect-error
if (vnode.children !== null && isArray(vnode.children)) {
;(vnode.children as any[]).forEach((child) => {
// @ts-expect-error
if (child instanceof VNode) {
getValidComponentsOrNodes(child, selector, list, getAll)
}
})
}
if (vnode.component != null) {
const component = vnode.component
getValidComponentsOrNodes(component!.subTree, selector, list, getAll)
}
}
// @ts-expect-error
function isValidComponentOrNode(vnode: VNode, selector: string): boolean {
if (
vnode.component != null &&
// @ts-expect-error
(vnode.component as ComponentInternalInstance).options.name == selector
) {
return true
}
if (vnode.el != null) {
const node = vnode.el!
if (selector.startsWith('.')) {
return node.classList.includes(selector.substring(1))
} else if (selector.startsWith('#')) {
return node.getAttribute('id') == selector.substring(1)
}
return node.tagName.toUpperCase() == selector.toUpperCase()
}
return false
}
export function getValidNodes(
node: UniElement | null,
selector: string,
// @ts-expect-error
list: UTSJSONObject[],
getAll = false
): void {
if (node == null) {
return
}
if (isValidNode(node, selector)) {
list.push({
elementId: node.getNodeId(),
tagName: node.tagName,
})
if (!getAll) {
return
}
}
node.childNodes.forEach((child: UniElement) => {
getValidNodes(child, selector, list, getAll)
})
}
function isValidNode(node: UniElement, selector: string): boolean {
if (selector.startsWith('.')) {
return node.classList.includes(selector.substring(1))
} else if (selector.startsWith('#')) {
return node.getAttribute('id') == selector.substring(1)
}
return node.tagName.toUpperCase() == selector.toUpperCase()
}
export function componentGetData(
// @ts-expect-error
vm: ComponentPublicInstance
// @ts-expect-error
): UTSJSONObject {
// TODO: path 目前无法处理类型问题,暂由服务端处理
if (vm.$.exposed.size > 0) {
// @ts-expect-error
return new UTSJSONObject(vm.$.exposed)
}
// @ts-expect-error
return new UTSJSONObject(vm.$data)
}
export function componentSetData(
// @ts-expect-error
vm: ComponentPublicInstance,
data: Map<string, any | null>
): void {
data.forEach((value: any | null, key: string) => {
vm.$data.set(key, value)
})
}
export function getChildrenText(node: UniElement): string {
let result = ''
node.childNodes.forEach((child: UniElement) => {
// @ts-expect-error
if (isTextElement(child)) {
result += child.getAttribute('value')
} else {
result += getChildrenText(child)
}
})
return result
}
export function toCamelCase(str: string): string {
const wordList = str.split('-')
for (let i = 1; i < wordList.length; i++) {
const word = wordList[i]
wordList[i] = word.at(0)!.toUpperCase() + word.substring(1)
}
return wordList.join('')
}
export function removeUniPrefix(selector: string): string {
if (selector.startsWith("uni-")) {
return selector.replace("uni-", "");
}
return selector;
}
+229
View File
@@ -0,0 +1,229 @@
import {
type CallUniMethodParams,
type CaptureScreenshotParams,
type GetCurrentPageParams,
callUniMethod,
captureScreenshot,
getCurrentPage,
getPageStack,
// @ts-expect-error
} from './apis/App/index.uts'
import {
type CallMethodParams,
type GetWindowPropertiesParams,
type GetDataParams as PageGetDataParams,
type GetElementParams as PageGetElementParams,
type SetDataParams as PageSetDataParams,
getWindowProperties,
callMethod as pageCallMethod,
getData as pageGetData,
getElement as pageGetElement,
getElements as pageGetElements,
setData as pageSetData,
// @ts-expect-error
} from './apis/Page.uts'
// @ts-expect-error
import { type SocketEmitterParams, socketEmitter } from './apis/App/Socket.uts'
import {
type CallFunctionParams as ElementCallFunctionParams,
type CallMethodParams as ElementCallMethodParams,
type GetDataParams as ElementGetDataParams,
type GetElementParams as ElementGetElementParams,
type SetDataParams as ElementSetDataParams,
type GetAttributesParams,
type GetDOMPropertiesParams,
type GetOffsetParams,
type GetPropertiesParams,
type GetStylesParams,
type HandleTouchEventParams,
type LongpressParams,
type TapParams,
type TriggerEventParams,
callFunction as elementCallFunction,
callMethod as elementCallMethod,
getData as elementGetData,
getElement as elementGetElement,
getElements as elementGetElements,
setData as elementSetData,
getAttributes,
getDOMProperties,
getOffset,
getProperties,
getStyles,
handleTouchEvent,
longpress,
tap,
triggerEvent
// @ts-expect-error
} from './apis/Element.uts'
let socketTask: SocketTask | null = null
// @ts-expect-error
const wsEndpoint = process.env.UNI_AUTOMATOR_WS_ENDPOINT
export function send(data: any) {
socketTask?.send({ data: JSON.stringify(data) } as SendSocketMessageOptions)
}
export type Callback = (result: any | null, error: any | null) => void
type Msg = {
id: string,
method: string,
params: any
}
export function onMessage(msg: string) {
// @ts-expect-error
const json = JSON.parse<Msg>(msg)!
const method = json.method
if ((method == 'ping')) {
send('pong')
return
}
const params = JSON.stringify(json.params)
const res = { id: json.id }
try {
const callback = (result?: any | null, error?: any | null) => {
res['result'] = result
res['error'] = error
send(res)
}
if (method.startsWith('App.')) {
switch (method) {
case 'App.callUniMethod':
// @ts-expect-error
callUniMethod(JSON.parse<CallUniMethodParams>(params)!, callback)
break
case 'App.captureScreenshot':
// @ts-expect-error
captureScreenshot(JSON.parse<CaptureScreenshotParams>(params)!, callback)
break
case 'App.getPageStack':
getPageStack(callback)
break
case 'App.getCurrentPage':
getCurrentPage({ callback } as GetCurrentPageParams)
break
case 'App.socketEmitter':
// @ts-expect-error
socketEmitter(JSON.parse<SocketEmitterParams>(params)!, callback)
break
}
} else if (method.startsWith('Page.')) {
switch (method) {
case 'Page.getData':
// @ts-expect-error
pageGetData(JSON.parse<PageGetDataParams>(params)!, callback)
break
case 'Page.setData':
// @ts-expect-error
pageSetData(JSON.parse<PageSetDataParams>(params)!, callback)
break
case 'Page.callMethod':
// @ts-expect-error
pageCallMethod(JSON.parse<CallMethodParams>(params)!, callback)
break
case 'Page.getElement':
// @ts-expect-error
pageGetElement(JSON.parse<PageGetElementParams>(params)!, callback)
break
case 'Page.getElements':
// @ts-expect-error
pageGetElements(JSON.parse<PageGetElementParams>(params)!, callback)
break
case 'Page.getWindowProperties':
// @ts-expect-error
getWindowProperties(JSON.parse<GetWindowPropertiesParams>(params)!, callback)
break
}
} else if (method.startsWith('Element.')) {
switch (method) {
case 'Element.getElement':
// @ts-expect-error
elementGetElement(JSON.parse<ElementGetElementParams>(params)!, callback)
break
case 'Element.getElements':
// @ts-expect-error
elementGetElements(JSON.parse<ElementGetElementParams>(params)!, callback)
break
case 'Element.getDOMProperties':
// @ts-expect-error
getDOMProperties(JSON.parse<GetDOMPropertiesParams>(params)!, callback)
break
case 'Element.getProperties':
// @ts-expect-error
getProperties(JSON.parse<GetPropertiesParams>(params)!, callback)
break
case 'Element.callFunction':
// @ts-expect-error
elementCallFunction(JSON.parse<ElementCallFunctionParams>(params)!, callback)
break
case 'Element.tap':
// @ts-expect-error
tap(JSON.parse<TapParams>(params)!, callback)
break
case 'Element.callMethod':
// @ts-expect-error
elementCallMethod(JSON.parse<ElementCallMethodParams>(params)!, callback)
break
case 'Element.getData':
// @ts-expect-error
elementGetData(JSON.parse<ElementGetDataParams>(params)!, callback)
break
case 'Element.setData':
// @ts-expect-error
elementSetData(JSON.parse<ElementSetDataParams>(params)!, callback)
break
case 'Element.getOffset':
// @ts-expect-error
getOffset(JSON.parse<GetOffsetParams>(params)!, callback)
break
case 'Element.longpress':
// @ts-expect-error
longpress(JSON.parse<LongpressParams>(params)!, callback)
break
case 'Element.touchstart':
case 'Element.touchmove':
case 'Element.touchend':
// @ts-expect-error
handleTouchEvent(JSON.parse<HandleTouchEventParams>(params)!, method.split('.')[1], callback)
break
case 'Element.getAttributes':
// @ts-expect-error
getAttributes(JSON.parse<GetAttributesParams>(params)!, callback)
break
case 'Element.getStyles':
// @ts-expect-error
getStyles(JSON.parse<GetStylesParams>(params)!, callback)
break
case 'Element.triggerEvent':
// @ts-expect-error
triggerEvent(JSON.parse<TriggerEventParams>(params)!, callback)
break
}
}
} catch (error) {
res['error'] = { message: error.stackTraceToString() }
send(res)
}
}
export function initAutomator() {
// @ts-expect-error
socketTask = uni.connectSocket({
url: wsEndpoint
});
socketTask!.onMessage((res) => {
onMessage(res.data as string)
})
socketTask!.onOpen((_) => {
console.warn("automator.onOpen")
})
socketTask!.onError((err) => {
console.warn(`automator.onError: ${JSON.stringify(err)}`);
})
socketTask!.onClose((_) => {
console.warn("automator.onClose");
})
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long