Element.uts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. // @ts-ignore
  2. import type { Callback } from '../index.uts'
  3. import {
  4. getElementById,
  5. getElementByNodeIdOrElementId,
  6. getComponentVmBySelector,
  7. getValidNodes,
  8. getComponentVmByNodeId,
  9. componentGetData,
  10. componentSetData,
  11. getElementByIdOrNodeId,
  12. // @ts-ignore
  13. } from './util.uts'
  14. // @ts-ignore
  15. import { getChildrenText, toCamelCase } from './util.uts'
  16. export type GetElementParams = {
  17. pageId: string
  18. nodeId?: number | null
  19. elementId?: string | null
  20. selector: string
  21. }
  22. export const getElement = (
  23. params: GetElementParams,
  24. callback: Callback
  25. ): void => {
  26. // TODO: support get component by class or id selector
  27. const element = getElementByNodeIdOrElementId(
  28. params.pageId,
  29. params.nodeId,
  30. params.elementId,
  31. callback
  32. )
  33. if (element != null) {
  34. let selector = params.selector
  35. if (selector.startsWith('uni-')) {
  36. selector = selector.replace('uni-', '')
  37. const component = getComponentVmBySelector(
  38. params.pageId,
  39. selector,
  40. callback
  41. )
  42. const result = {
  43. nodeId: component != null ? component.$.uid : null,
  44. tagName: component != null ? selector : null,
  45. elementId: component != null ? `${Date.now()}` : null,
  46. }
  47. callback(result, null)
  48. return
  49. }
  50. // @ts-ignore
  51. const list: UTSJSONObject[] = []
  52. getValidNodes(element, selector, list)
  53. if (list.length > 0) {
  54. callback(list[0], null)
  55. } else {
  56. callback(null, { errMsg: `Element[${params.selector}] not exists` })
  57. }
  58. }
  59. }
  60. export const getElements = (
  61. params: GetElementParams,
  62. callback: Callback
  63. ): void => {
  64. const element = getElementByNodeIdOrElementId(
  65. params.pageId,
  66. params.nodeId,
  67. params.elementId,
  68. callback
  69. )
  70. if (element != null) {
  71. let selector = params.selector
  72. if (selector.startsWith('uni-')) {
  73. selector = selector.replace('uni-', '')
  74. }
  75. // @ts-ignore
  76. const list: UTSJSONObject[] = []
  77. getValidNodes(element, selector, list, true)
  78. callback({ elements: list }, null)
  79. }
  80. }
  81. export type GetDOMPropertiesParams = {
  82. pageId: string
  83. elementId?: string | null
  84. nodeId?: number | null
  85. names: string[]
  86. }
  87. export const getDOMProperties = (
  88. params: GetDOMPropertiesParams,
  89. callback: Callback
  90. ): void => {
  91. const dom = getElementByIdOrNodeId(
  92. params.pageId,
  93. params.elementId,
  94. params.nodeId,
  95. callback
  96. )
  97. if (dom != null) {
  98. const properties = params.names.map((name: string): any | null => {
  99. if (name == 'innerText') {
  100. // @ts-expect-error
  101. if (isTextElement(dom)) {
  102. return dom.getAttribute('value')
  103. } else {
  104. return getChildrenText(dom)
  105. }
  106. }
  107. if (name == 'value') {
  108. return dom.getAttribute('value')
  109. }
  110. if (name == 'offsetWidth') {
  111. return dom.offsetWidth
  112. }
  113. if (name == 'offsetHeight') {
  114. return dom.offsetHeight
  115. }
  116. return `Element.getDOMProperties not support ${name}`
  117. })
  118. callback({ properties }, null)
  119. }
  120. }
  121. export type GetPropertiesParams = {
  122. pageId: string
  123. elementId?: string | null
  124. nodeId?: number | null
  125. names: string[]
  126. }
  127. export const getProperties = (
  128. params: GetPropertiesParams,
  129. callback: Callback
  130. ): void => {
  131. const dom = getElementByIdOrNodeId(
  132. params.pageId,
  133. params.elementId,
  134. params.nodeId,
  135. callback
  136. )
  137. // @ts-ignore
  138. let component: ComponentPublicInstance | null = null
  139. if (params.nodeId != null) {
  140. component = getComponentVmByNodeId(params.pageId, params.nodeId!, callback)
  141. }
  142. const properties = params.names.map((name: string): any | null => {
  143. if (component != null && component.$props[toCamelCase(name)] != null) {
  144. return component.$props[toCamelCase(name)]
  145. }
  146. if (dom != null) {
  147. return dom.getAttribute(name)
  148. }
  149. return null
  150. })
  151. callback({ properties }, null)
  152. }
  153. export type GetAttributesParams = {
  154. pageId: string
  155. elementId?: string | null
  156. nodeId?: number | null
  157. names: string[]
  158. }
  159. export const getAttributes = (
  160. params: GetAttributesParams,
  161. callback: Callback
  162. ): void => {
  163. const dom = getElementByIdOrNodeId(
  164. params.pageId,
  165. params.elementId,
  166. params.nodeId,
  167. callback
  168. )
  169. if (dom != null) {
  170. const attributes = params.names.map((name: string): any | null => {
  171. if (name == 'class') {
  172. return dom.classList.join(' ')
  173. }
  174. return dom.getAttribute(name)
  175. })
  176. callback({ attributes }, null)
  177. }
  178. }
  179. export type CallFunctionParams = {
  180. pageId: string
  181. elementId: string
  182. functionName: string
  183. args: any[]
  184. }
  185. type Coordinate = {
  186. x: number
  187. y: number
  188. }
  189. export const callFunction = (
  190. params: CallFunctionParams,
  191. callback: Callback
  192. ): void => {
  193. const element = getElementById(params.pageId, params.elementId, callback)
  194. if (element != null) {
  195. const functionName = params.functionName
  196. switch (functionName) {
  197. case 'input.input':
  198. element.dispatchEvent(
  199. 'input',
  200. // @ts-ignore
  201. new InputEvent(
  202. 'input',
  203. // @ts-ignore
  204. InputEventDetail(params.args[0] as string, 0, 0)
  205. )
  206. )
  207. callback({ result: `${functionName} success` }, null)
  208. break
  209. case 'scroll-view.scrollTo':
  210. if (element.tagName == 'SCROLL-VIEW') {
  211. // @ts-ignore
  212. const arg = JSON.parse<Coordinate>(JSON.stringify(params.args[0]))!
  213. element.scrollLeft = arg.x
  214. element.scrollTop = arg.y
  215. callback({ result: `${functionName} success` }, null)
  216. } else {
  217. callback(null, {
  218. errMsg: `${functionName} fail, element is not scroll-view`,
  219. })
  220. }
  221. break
  222. case 'swiper.swipeTo':
  223. if (element.tagName == 'SWIPER') {
  224. callback(null, { errMsg: `${functionName} not support` })
  225. } else {
  226. callback(null, {
  227. errMsg: `${functionName} fail, element is not swiper`,
  228. })
  229. return
  230. }
  231. break
  232. case 'scroll-view.scrollWidth':
  233. if (element.tagName == 'SCROLL-VIEW') {
  234. callback({ result: element.scrollWidth }, null)
  235. } else {
  236. callback(null, {
  237. errMsg: `${functionName} fail, element is not scroll-view`,
  238. })
  239. return
  240. }
  241. break
  242. case 'scroll-view.scrollHeight':
  243. if (element.tagName == 'SCROLL-VIEW') {
  244. callback({ result: element.scrollHeight }, null)
  245. } else {
  246. callback(null, {
  247. errMsg: `${functionName} fail, element is not scroll-view`,
  248. })
  249. return
  250. }
  251. break
  252. case 'scroll-view.scrollTop':
  253. if (element.tagName == 'SCROLL-VIEW') {
  254. callback({ result: element.scrollTop }, null)
  255. } else {
  256. callback(null, {
  257. errMsg: `${functionName} fail, element is not scroll-view`,
  258. })
  259. return
  260. }
  261. break
  262. case 'scroll-view.scrollLeft':
  263. if (element.tagName == 'SCROLL-VIEW') {
  264. callback({ result: element.scrollLeft }, null)
  265. } else {
  266. callback(null, {
  267. errMsg: `${functionName} fail, element is not scroll-view`,
  268. })
  269. return
  270. }
  271. break
  272. default:
  273. callback(null, { errMsg: `${functionName} not support` })
  274. break
  275. }
  276. } else {
  277. callback(null, { errMsg: `Element not exists` })
  278. }
  279. }
  280. export type TapParams = {
  281. pageId: string
  282. elementId?: string | null
  283. nodeId?: number | null
  284. }
  285. export const tap = (params: TapParams, callback: Callback): void => {
  286. const dom = getElementByIdOrNodeId(
  287. params.pageId,
  288. params.elementId,
  289. params.nodeId,
  290. callback
  291. )
  292. if (dom != null) {
  293. const num = 0
  294. // @ts-ignore
  295. const _float = num.toFloat()
  296. dom.dispatchEvent(
  297. 'click',
  298. new MouseEvent(
  299. 'click',
  300. _float,
  301. // @ts-ignore
  302. _float,
  303. _float,
  304. _float,
  305. _float,
  306. _float,
  307. _float,
  308. _float
  309. )
  310. )
  311. callback({ result: `Element.tap success` }, null)
  312. }
  313. }
  314. export type CallMethodParams = {
  315. pageId: string
  316. nodeId: number
  317. method: string
  318. args: any[]
  319. }
  320. export const callMethod = (
  321. params: CallMethodParams,
  322. callback: Callback
  323. ): void => {
  324. const component = getComponentVmByNodeId(
  325. params.pageId,
  326. params.nodeId,
  327. callback
  328. )
  329. if (component != null) {
  330. const result =
  331. params.args.length > 0
  332. ? component.$callMethod(params.method, params.args[0])
  333. : component.$callMethod(params.method)
  334. // @ts-ignore
  335. if (result instanceof Promise<unknown>) {
  336. (result as Promise<any>).then((res: any) => {
  337. callback({ result: res }, null)
  338. }).catch((err) => {
  339. const errMsg = err instanceof Error ? err.message : err
  340. callback({ result: errMsg }, null)
  341. })
  342. } else {
  343. callback({ result }, null)
  344. }
  345. }
  346. }
  347. export type GetDataParams = {
  348. pageId: string
  349. nodeId: number
  350. path?: string | null
  351. }
  352. export const getData = (params: GetDataParams, callback: Callback): void => {
  353. const component = getComponentVmByNodeId(
  354. params.pageId,
  355. params.nodeId,
  356. callback
  357. )
  358. if (component != null) {
  359. const data = componentGetData(
  360. component,
  361. )
  362. callback({ data }, null)
  363. }
  364. }
  365. export type SetDataParams = {
  366. pageId: string
  367. nodeId: number
  368. data: Map<string, any | null>
  369. }
  370. export const setData = (params: SetDataParams, callback: Callback): void => {
  371. const component = getComponentVmByNodeId(
  372. params.pageId,
  373. params.nodeId,
  374. callback
  375. )
  376. if (component != null) {
  377. componentSetData(component, params.data)
  378. callback({ result: { errMsg: 'Page.setData: ok.' } }, null)
  379. }
  380. }
  381. export type GetOffsetParams = {
  382. pageId: string
  383. elementId?: string | null
  384. nodeId?: number | null
  385. }
  386. export const getOffset = (
  387. params: GetOffsetParams,
  388. callback: Callback
  389. ): void => {
  390. const dom = getElementByIdOrNodeId(
  391. params.pageId,
  392. params.elementId,
  393. params.nodeId,
  394. callback
  395. )
  396. if (dom != null) {
  397. callback({ left: dom.offsetLeft, top: dom.offsetTop }, null)
  398. }
  399. }
  400. export type LongpressParams = {
  401. pageId: string
  402. elementId?: string | null
  403. nodeId?: number | null
  404. }
  405. export const longpress = (
  406. params: LongpressParams,
  407. callback: Callback
  408. ): void => {
  409. const dom = getElementByIdOrNodeId(
  410. params.pageId,
  411. params.elementId,
  412. params.nodeId,
  413. callback
  414. )
  415. if (dom != null) {
  416. const x: number = 0
  417. const y: number = 0
  418. dom.dispatchEvent(
  419. 'longpress',
  420. // @ts-ignore
  421. new TouchEvent(null, 'longpress', getTouches([]), getTouches([]))
  422. )
  423. callback({ result: `Element.longpress success` }, null)
  424. }
  425. }
  426. export type HandleTouchEventParams = {
  427. pageId: string
  428. elementId?: string | null
  429. nodeId?: number | null
  430. touches: any[]
  431. changedTouches: any[]
  432. }
  433. export const handleTouchEvent = (
  434. params: HandleTouchEventParams,
  435. eventName: string,
  436. callback: Callback
  437. ): void => {
  438. const dom = getElementByIdOrNodeId(
  439. params.pageId,
  440. params.elementId,
  441. params.nodeId,
  442. callback
  443. )
  444. if (dom != null) {
  445. const touches = getTouches(params.touches)
  446. const changedTouches = getTouches(params.changedTouches)
  447. dom.dispatchEvent(
  448. eventName,
  449. // @ts-ignore
  450. new TouchEvent(null, eventName, touches, changedTouches)
  451. )
  452. callback({ result: `Element.${eventName} success` }, null)
  453. }
  454. }
  455. type TypeTouch = {
  456. identifier: number
  457. pageX: number
  458. pageY: number,
  459. screenX?: number | null,
  460. screenY?: number | null,
  461. clientX?: number | null,
  462. clientY?: number | null,
  463. }
  464. function getTouches(touches: any[]): Touch[] {
  465. return touches.map((touch): Touch => {
  466. // @ts-ignore
  467. const touchObj = JSON.parse<TypeTouch>(JSON.stringify(touch))!
  468. // @ts-ignore
  469. const result = Touch()
  470. result.identifier = touchObj.identifier.toFloat()
  471. result.pageX = touchObj.pageX.toFloat()
  472. result.pageY = touchObj.pageY.toFloat()
  473. if (touchObj.screenX !== null) {
  474. result.screenX = touchObj.screenX!.toFloat()
  475. }
  476. if (touchObj.screenY !== null) {
  477. result.screenY = touchObj.screenY!.toFloat()
  478. }
  479. if (touchObj.clientX !== null) {
  480. result.clientX = touchObj.clientX!.toFloat()
  481. }
  482. if (touchObj.clientY !== null) {
  483. result.clientY = touchObj.clientY!.toFloat()
  484. }
  485. return result
  486. })
  487. }
  488. export type GetStylesParams = {
  489. pageId: string
  490. elementId?: string | null
  491. nodeId?: number | null
  492. names: string[]
  493. }
  494. export const getStyles = (
  495. params: GetStylesParams,
  496. callback: Callback
  497. ): void => {
  498. const dom = getElementByIdOrNodeId(
  499. params.pageId,
  500. params.elementId,
  501. params.nodeId,
  502. callback
  503. )
  504. if (dom != null) {
  505. const styles = params.names.map((name: string): any | null => {
  506. return dom.style.getPropertyValue(name)
  507. })
  508. callback({ styles }, null)
  509. }
  510. }