diff --git a/ArkWebKit/ArkWebClipboard/.gitignore b/ArkWebKit/ArkWebClipboard/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/AppScope/app.json5 b/ArkWebKit/ArkWebClipboard/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..52a5b93f239400c0ee5a6aef2156a3c3ef0fdfcf --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "bundleName": "com.samples.webclipboard", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkWebKit/ArkWebClipboard/AppScope/resources/base/element/string.json b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..445db917e30fc9672e25879733c0c8020a1aeb1a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ArkWebClipboard" + } + ] +} diff --git a/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/background.png b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/background.png differ diff --git a/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/foreground.png b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9427585b36d14b12477435b6419d1f07b3e0bb Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/foreground.png differ diff --git a/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/layered_image.json b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/README.md b/ArkWebKit/ArkWebClipboard/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2687b949d9bd3d30e0de3ac4cc212f73ac3aa0f0 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/README.md @@ -0,0 +1,107 @@ +# 使用Web组件与系统剪贴板交互处理网页内容 + +### 介绍 + +1. 开发者能够通过Web组件和系统剪贴板进行交互,实现各种类型数据的复制和粘贴。支持通过[菜单](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/web/web_menu.md)、键盘快捷键以及[W3C剪贴板接口](https://www.w3.org/TR/clipboard-apis/)对网页内容执行剪切、复制和粘贴操作。 +2. 本工程主要实现了对以下指南文档中[使用Web组件与系统剪贴板交互处理网页内容](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/web/web-clipboard.md)示例代码片段的工程化,帮助开发者快速了解Web组件和系统剪贴板之间如何交互。 + +### 通过W3C异步剪贴板接口与系统剪贴板交互 + +#### 介绍 + +[异步剪贴板接口(Async Clipboard API)](https://www.w3.org/TR/clipboard-apis/#async-clipboard-api)提供给网页开发者读写系统剪贴板的方法,这让Web应用程序可以实现剪切、复制和粘贴的功能。 + +#### 效果预览 + +| Clipboard API demo | +|-----------------------------------------------------------| +| | + +##### 使用说明 + +* 通过异步剪贴板接口read()和readText()方法访问系统剪贴板内容,需[申请访问剪贴板权限](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/basic-services/pasteboard/get-pastedata-permission-guidelines.md):ohos.permission.READ_PASTEBOARD。 +* 使用writeText、write等API将内容写入系统剪贴板。使用readText、read等API从系统剪贴板获取文本内容 + +#### 工程目录 + +``` +├── entry +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── EntryAbility.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### 通过W3C剪贴板事件接口与系统剪贴板交互 + +#### 介绍 + +[剪贴板事件(Clipboard Event)](https://www.w3.org/TR/clipboard-apis/#clipboard-events-and-interfaces)描述了与剪切板相关的cut、copy和paste事件。当用户执行剪切、复制或粘贴操作时,相应的事件将被触发。开发者可以通过监听这些事件,对系统剪贴板进行读写操作,或拦截默认行为,以更改复制或粘贴的结果。 +#### 效果预览 + +| Clipboard Event监听示例 | +|----------------------------------------------------------------| +| | + +##### 使用说明 +* 通过监听网页的复制、粘贴、剪切事件,获取到内容。 +* 使用navigator.clipboard 相关 API,访问剪贴板内容。 + + +#### 工程目录 + +``` +├── entry2 +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── EntryAbility.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### 具体实现 +* 使用Web组件与系统剪贴板交互处理网页内容 +* 通过W3C异步剪贴板接口与系统剪贴板交互 + * [异步剪贴板接口(Async Clipboard API)](https://www.w3.org/TR/clipboard-apis/#async-clipboard-api)提供给网页开发者读写系统剪贴板的方法。 + * writeText:将文本内容写入系统剪贴板。write:将任意类型内容写入系统剪贴板。 + * readText:从系统剪贴板读取文本内容。read():从系统剪贴板读取任意类型内容。 +* 通过W3C剪贴板事件接口与系统剪贴板交互 + * [剪贴板事件(Clipboard Event)](https://www.w3.org/TR/clipboard-apis/#clipboard-events-and-interfaces)描述了与剪切板相关的cut、copy和paste事件。当用户执行剪切、复制或粘贴操作时,相应的事件将被触发。 + * 通过addEventListener的方式监听copy、paste、cut事件,对系统剪贴板进行读写操作 + +### 相关权限 + +[ohos.permission.INTERNET](https://docs.openharmony.cn/pages/v6.0/zh-cn/application-dev/security/AccessToken/permissions-for-all.md#ohospermissioninternet) + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行。 +2. 本示例支持API14版本SDK,SDK版本号(API Version 20 Release)。 +3. 本示例需要使用DevEco Studio 版本号(6.0.0Release)才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/ArkWeb/ArkWebClipboard > .git/info/sparse-checkout +git remote add origin https://gitcode.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/build-profile.json5 b/ArkWebKit/ArkWebClipboard/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..cdb0ee92784db908ecca9a70e401d494e38b677d --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/build-profile.json5 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "signingConfigs": [ + { + "name": "default", + "type": "HarmonyOS", + "material": { + "certpath": "C:\\Users\\wangrongfei.ICS-VTBAFCLMWDF\\.ohos\\config\\default_ArkWebClipboard_XRWg3QlnEtyzg2lvV9fxB0T52ZNsTs2OuJ6BzG3JAM8=.cer", + "keyAlias": "debugKey", + "keyPassword": "0000001B802819DC69D0ECB72C90A6761856BCEF2379DD1A524BAADD507B24B197DE36366DF8479C9C050F", + "profile": "C:\\Users\\wangrongfei.ICS-VTBAFCLMWDF\\.ohos\\config\\default_ArkWebClipboard_XRWg3QlnEtyzg2lvV9fxB0T52ZNsTs2OuJ6BzG3JAM8=.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\wangrongfei.ICS-VTBAFCLMWDF\\.ohos\\config\\default_ArkWebClipboard_XRWg3QlnEtyzg2lvV9fxB0T52ZNsTs2OuJ6BzG3JAM8=.p12", + "storePassword": "0000001B8314451DC893A12FCD06A9E50A09625231C90DACCBBCD869FBB13B1B44742538F72298B7CC6263" + } + } + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "targetSdkVersion": "6.0.0(20)", + "compatibleSdkVersion": "6.0.0(20)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/code-linter.json5 b/ArkWebKit/ArkWebClipboard/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5c4682f8164874ec7e9cb8f99ff8b3228ffbc126 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/code-linter.json5 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@security/no-unsafe-aes": "error", + "@security/no-unsafe-hash": "error", + "@security/no-unsafe-mac": "warn", + "@security/no-unsafe-dh": "error", + "@security/no-unsafe-dsa": "error", + "@security/no-unsafe-ecdsa": "error", + "@security/no-unsafe-rsa-encrypt": "error", + "@security/no-unsafe-rsa-sign": "error", + "@security/no-unsafe-rsa-key": "error", + "@security/no-unsafe-dsa-key": "error", + "@security/no-unsafe-dh-key": "error", + "@security/no-unsafe-3des": "error" + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/build-profile.json5 b/ArkWebKit/ArkWebClipboard/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9016faf39f8a65cf648bae246a53575510fe8b9f --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/build-profile.json5 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "resOptions": { + "copyCodeResource": { + "enable": false + } + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/hvigorfile.ts b/ArkWebKit/ArkWebClipboard/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8b117a17af3b2d7cb87a7680e29e2bb8ccd5b46 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/obfuscation-rules.txt b/ArkWebKit/ArkWebClipboard/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/oh-package.json5 b/ArkWebKit/ArkWebClipboard/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..10cda399b0aec3099b257299a57d284393e4e55a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/ets/entryability/EntryAbility.ets b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..62f53acbc95e5be7985f8fb1fe2db591cea260bd --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + try { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + } catch (err) { + hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err)); + } + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a97e21bd7a15599af76a806695860ff1eb0ebfe --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/Index.ets b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..06d96634f37d8fb77be40983d6a4ffdbc211f9b4 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { BusinessError } from '@kit.BasicServicesKit'; +import { common } from '@kit.AbilityKit'; +import hilog from '@ohos.hilog'; + +const TAG = '[Sample_WebClipboard]' +const DOMAIN = 0xF811 +const BUNDLE = 'WebClipboard_' +//Column space +const COLUMN_SPACE: Length = 10; + +@Entry +@Component +struct Index { + build() { + Column({ space: COLUMN_SPACE }) { + Button('clipboard') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebClipboard', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`) + }) + }) + Button('clipboard event') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebClipboardEvent', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('copy Options') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebCopyOptions', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + }.height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebClipboard.ets b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebClipboard.ets new file mode 100644 index 0000000000000000000000000000000000000000..49f5d7973af062cb94bf698c2cc51ab6749a872f --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebClipboard.ets @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start web_clipboard_content] +import { webview } from '@kit.ArkWeb'; + +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + + build() { + Column() { + Web({ src: $rawfile('clipboard.html'), controller: this.controller }) + } + } +} +// [End web_clipboard_content] diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebClipboardEvent.ets b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebClipboardEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..324fde0b8e74eee017ca5dff64c8a59e2c797dd2 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebClipboardEvent.ets @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start web_clipboard_event] +import { webview } from '@kit.ArkWeb'; + +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + + build() { + Column() { + Web({ src: $rawfile('clipboard_event.html'), controller: this.controller }) + } + } +} +// [End web_clipboard_event] diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebCopyOptions.ets b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebCopyOptions.ets new file mode 100644 index 0000000000000000000000000000000000000000..d3d03d684fe93d892dd2d990b4a6d06ba35050cd --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/ets/pages/WebCopyOptions.ets @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start web_clipboard_copyOptions] +import { webview } from '@kit.ArkWeb'; + +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + @State copyOption: CopyOptions = CopyOptions.LocalDevice; + + build() { + Column() { + Web({ src: $rawfile('copyOptions.html'), controller: this.controller }) + .copyOptions(this.copyOption) + } + } +} +// [End web_clipboard_copyOptions] diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/module.json5 b/ArkWebKit/ArkWebClipboard/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..bf2232a36fceb6a9da8e4cd4024843d0c2f0d350 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/module.json5 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start web_clipboard_permissions] +{ + "module": { + // [StartExclude web_clipboard_permissions] + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "ohos.want.action.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ], + // [EndExclude web_clipboard_permissions] + "requestPermissions": [ + { + "name" : "ohos.permission.READ_PASTEBOARD", + "reason": "$string:module_desc", + "usedScene": { + "abilities": [ + "FormAbility" + ], + "when":"inuse" + } + } + ] + } +} +// [End web_clipboard_permissions] diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/color.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/float.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..33ea22304f9b1485b5f22d811023701b5d4e35b6 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/string.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/background.png b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/background.png differ diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/foreground.png b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/layered_image.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/startIcon.png b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/profile/backup_config.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/profile/main_pages.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..736d40597dfae42e8bb635f5f2fd79ed6a1d309a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,8 @@ +{ + "src": [ + "pages/Index", + "pages/WebClipboard", + "pages/WebClipboardEvent", + "pages/WebCopyOptions" + ] +} diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/dark/element/color.json b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/clipboard.html b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/clipboard.html new file mode 100644 index 0000000000000000000000000000000000000000..25186b819703006c41cfc8767ccbb8baeabec14f --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/clipboard.html @@ -0,0 +1,83 @@ + + + + + + + Clipboard API demo + + + +

Clipboard API demo

+
+ + +
+ +
+ + + +
+ +
+
+ + + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/clipboard_event.html b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/clipboard_event.html new file mode 100644 index 0000000000000000000000000000000000000000..049db4bd4dcdace5f913cf6cd7bf75619a8c2ea8 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/clipboard_event.html @@ -0,0 +1,53 @@ + + + + + + + Clipboard Event demo + + + +

Clipboard Event监听示例

+ + +
+

输出内容:

+

没有复制或粘贴内容。

+
+ + + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/copyOptions.html b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/copyOptions.html new file mode 100644 index 0000000000000000000000000000000000000000..ee1725aa05ae4e10ea931af54dd05baadd33b6cd --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/main/resources/rawfile/copyOptions.html @@ -0,0 +1,13 @@ + + + + + + + Clipboard CopyOption demo + + +

Clipboard CopyOption示例

+ + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/mock/mock-config.json5 b/ArkWebKit/ArkWebClipboard/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..323d1d611fecf4ecb751976e3a71500b3712a445 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/mock/mock-config.json5 @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..da05f0bb17de49d63edbff51149439d2d7f96336 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { abilityDelegatorRegistry, Driver, ON } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +//Delay of 1000 milliseconds +const DELAY_1000: number = 1000; +//Delay of 3000 milliseconds +const DELAY_3000: number = 3000; +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(async (done: Function) => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + const want: Want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + done(); + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(async (done: Function) => { + const driver = Driver.create(); + await driver.pressBack(); + await driver.delayMs(DELAY_3000); + done(); + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('testClipboard001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('clipboard')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('clipboard.html'); + done(); + }) + it('testClipboardEvent001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('clipboard event')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('clipboard_event.html'); + done(); + }) + + it('testCopyOptions001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('copy Options')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('copyOptions.html'); + done(); + }) + + }) +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/ets/test/List.test.ets b/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/module.json5 b/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..59667117c86b64ab9863f7b382c435ae4a3c32fa --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/ohosTest/module.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkWebKit/ArkWebClipboard/entry/src/test/List.test.ets b/ArkWebKit/ArkWebClipboard/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/entry/src/test/LocalUnit.test.ets b/ArkWebKit/ArkWebClipboard/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/hvigor/hvigor-config.json5 b/ArkWebKit/ArkWebClipboard/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3b057578a1bb4d591ee53054e39ab0154fc2e43a --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "6.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + // "optimizationStrategy": "memory" /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/ArkWebKit/ArkWebClipboard/hvigorfile.ts b/ArkWebKit/ArkWebClipboard/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae9086af35844176c08f1be3772d081d95d267c6 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebClipboard/oh-package.json5 b/ArkWebKit/ArkWebClipboard/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..837c0ff9f35a6bb9eea849fead7955c19bcdec8d --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "6.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.24", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkWebKit/ArkWebClipboard/ohosTest.md b/ArkWebKit/ArkWebClipboard/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..571efcd0461620ef1a5681d26bbeefdfb0422fd9 --- /dev/null +++ b/ArkWebKit/ArkWebClipboard/ohosTest.md @@ -0,0 +1,11 @@ +## 通过W3C异步剪贴板接口与系统剪贴板交互 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|------| ------------ | ------------ |----------------------| -------- | -------- | +| 通过W3C异步剪贴板接口与系统剪贴板交互 | 设备运转正常 | 应用启动成功 | 可以正常加载网页并且可以和系统剪切板互动 | Yes | Pass | + +## 通过W3C剪贴板事件接口与系统剪贴板交互 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ----------------- | ------------ | ------------ |----------------------| -------- | -------- | +| 通过W3C剪贴板事件接口与系统剪贴板交互 | 设备运转正常 | 应用启动成功 | 可以正常加载网页并且可以监听到对应的事件 | Yes | Pass | diff --git a/ArkWebKit/ArkWebClipboard/screenshots/webClipboard.gif b/ArkWebKit/ArkWebClipboard/screenshots/webClipboard.gif new file mode 100644 index 0000000000000000000000000000000000000000..f6d68ff1d8757926ce1210715ddfcdc7fdfa5466 Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/screenshots/webClipboard.gif differ diff --git a/ArkWebKit/ArkWebClipboard/screenshots/webClipboardEvent.gif b/ArkWebKit/ArkWebClipboard/screenshots/webClipboardEvent.gif new file mode 100644 index 0000000000000000000000000000000000000000..e037639260f70f4a7469bd26cd646cf3c6bd08d6 Binary files /dev/null and b/ArkWebKit/ArkWebClipboard/screenshots/webClipboardEvent.gif differ diff --git a/ArkWebKit/ArkWebMenu/.gitignore b/ArkWebKit/ArkWebMenu/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkWebKit/ArkWebMenu/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/AppScope/app.json5 b/ArkWebKit/ArkWebMenu/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3296a0d495d8790e18468853a67e7bda18336c3f --- /dev/null +++ b/ArkWebKit/ArkWebMenu/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "bundleName": "com.samples.webmenu", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkWebKit/ArkWebMenu/AppScope/resources/base/element/string.json b/ArkWebKit/ArkWebMenu/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..03b648c1addf05b3738428a44d586b5746ecbba8 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ArkWebMenu" + } + ] +} diff --git a/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/background.png b/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/background.png differ diff --git a/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/foreground.png b/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9427585b36d14b12477435b6419d1f07b3e0bb Binary files /dev/null and b/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/foreground.png differ diff --git a/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/layered_image.json b/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkWebKit/ArkWebMenu/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/README.md b/ArkWebKit/ArkWebMenu/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3b683d521f0a3b295a1053be15c3eb371d7c6521 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/README.md @@ -0,0 +1,239 @@ +# 使用Web组件菜单处理网页内容 + +### 介绍 + +1. 菜单作为用户交互的关键组件,其作用是构建清晰的导航体系,通过结构化布局展示功能入口,使用户能够迅速找到目标内容或执行操作。作为人机交互的重要枢纽,它显著提升了Web组件的可访问性和用户体验,是应用设计中必不可少的部分。Web组件菜单类型包括文本选中菜单、上下文菜单和自定义菜单,应用可根据具体需求灵活选择。 +2. 本工程主要实现了对以下指南文档中[使用Web组件菜单处理网页内容](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/web/web_menu.md)示例代码片段的工程化,主要目标是帮助开发者快速了解如何在Web组件中使用菜单。 + +### 文本选中菜单 + +#### 介绍 + +1. Web组件的文本选中菜单是一种通过自定义元素实现的上下文交互组件,当用户选中文本时会动态显示,提供复制、分享、标注等语义化操作,具备标准化功能与可扩展性,是移动端文本操作的核心功能。文本选中菜单在用户长按选中文本或编辑状态下长按出现单手柄时弹出,菜单项横向排列。系统提供默认的菜单实现。应用可通过[editMenuOptions](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkweb/arkts-basic-components-web-attributes.md#editmenuoptions12)接口对文本选中菜单进行自定义操作。 + +#### 效果预览 + +| 文本选中菜单 | +|----------------------------------------------------------------| +| | + +##### 使用说明 + +* 通过onCreateMenu方法自定义菜单项,通过操作Array数组可对显示菜单项进行增减操作,在TextMenuItem中定义菜单项名称、图标、ID等内容。 +* 通过onMenuItemClick方法处理菜单项点击事件,当返回false时会执行系统默认逻辑。 +* 创建一个EditMenuOptions对象,包含onCreateMenu和onMenuItemClick两个方法,通过Web组件的editMenuOptions方法与Web组件绑定。 + +#### 工程目录 + +``` +├── entry +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── EntryAbility.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### 上下文菜单 + +#### 介绍 + +上下文菜单是用户通过特定操作(如右键点击或长按富文本)触发的快捷菜单,用于提供与当前操作对象或界面元素相关的功能选项。菜单项纵向排列。系统未提供默认实现,若应用未实现,则不显示上下文菜单。应用需要创建一个Menu组件并与Web绑定,在菜单弹出时可通过Web组件的onContextMenuShow回调接口获取上下文菜单的详细信息,包括点击位置的HTML元素信息及点击位置信息。 + +#### 效果预览 + +| 上下文菜单 | +|--------------------------------------------------------------------| +| | + +##### 使用说明 + +* Menu组件作为弹出的菜单,包含所有菜单项行为与样式。 +* 使用bindPopup方法将Menu组件与Web组件绑定。当上下文菜单弹出时,将显示创建的Menu组件。 +* 在onContextMenuShow回调中获取上下文菜单事件信息onContextMenuShowEvent。其中param为WebContextMenuParam类型,包含点击位置对应HTML元素信息和位置信息,result为WebContextMenuResult类型,提供常见的菜单能力。 + + +#### 工程目录 + +``` +├── entry2 +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── Entry2Ability.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### 自定义菜单 + +#### 介绍 + +自定义菜单赋予开发者调整菜单触发时机与视觉展现的能力,使应用能够依据用户操作场景动态匹配功能入口,简化开发流程中的界面适配工作,同时使应用交互更符合用户直觉。应用可通过bindSelectionMenu接口,实现自定义菜单。目前已额外支持通过长按图片和链接响应自定义菜单。 + +#### 效果预览 + +|自定义菜单 | +|--------------------------------------------------------------------| +| | + +##### 使用说明 +* 创建Menu组件作为菜单弹窗。 +* 通过Web组件的bindSelectionMenu方法绑定MenuBuilder菜单弹窗。将WebElementType设置为WebElementType.IMAGE,responseType设置为WebResponseType.LONG_PRESS,表示长按图片时弹出菜单。在options中定义菜单显示回调onAppear、菜单消失回调onDisappear、预览窗口preview和菜单类型menuType。 + +#### 工程目录 +``` +├── entry3 +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── Entry3Ability.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### Web菜单保存图片 + +#### 介绍 + +使用安全组件SaveButton保存web图片到图库。 + +#### 效果预览 + +|Web菜单保存图片 | +|--------------------------------------------------------------------| +| | + +##### 使用说明 +* 创建MenuBuilder组件作为菜单弹窗,使用[SaveButton](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-security-components-savebutton.md)组件实现图片保存,通过bindContextMenu将MenuBuilder与Web绑定。 +* 在onContextMenuShow中获取图片url,通过copyLocalPicToDir或copyUrlPicToDir将图片保存至应用沙箱。 +* 通过photoAccessHelper将应用沙箱中的图片保存至图库。 + +#### 工程目录 +``` +├── entry5 +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── Entry5Ability.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` +### Web菜单获取选中文本 + +#### 介绍 + +Web组件的editMenuOptions接口中没有提供获取选中文本的方式。开发者可通过javaScriptProxy获取到JavaScript的选中文本,实现自定义菜单的逻辑。 +#### 效果预览 + +|Web菜单获取选中文本 | +|----------------------------------------------------------------| +| | + +##### 使用说明 +* 创建SelectClass类,通过javaScriptProxy将SelectClass对象注册到Web组件中。 +* 在Html侧注册选区变更监听器,在选区变更时通过SelectClass对象将选区设置到ArkTS侧。 + +#### 工程目录 +``` +├── entry6 +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── Entry6Ability.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### Web菜单识别图片二维码 + +#### 介绍 + +在二维码跳转页面或者付款场景中,开发者可通过实现上下文菜单,获取到onContextMenuShow接口中的二维码图片信息进行处理,提供给用户扫描二维码入口。 + +#### 效果预览 + +|Web菜单识别图片二维码 | +|--------------------------------------------------------------------| +| | + +##### 使用说明 +* 创建MenuBuilder组件作为菜单弹窗,通过bindContextMenu将MenuBuilder与Web绑定。 +* 在onContextMenuShow中获取图片url,通过copyLocalPicToDir或copyUrlPicToDir将图片保存至应用沙箱。 +* 通过detectBarcode.decode解析保存在沙箱中的图片,获取到结果。 + +#### 工程目录 +``` +├── entry7 +│ └── src +│ └── main +│ ├── ets // ArkTS代码区 +│ │ ├── entryability +│ │ │ └── Entry7Ability.ets // 入口类 +│ │ ├── entrybackupability +│ │ │ └── EntryBackupAbility.ets // 备份恢复框架 +│ │ └── pages +│ │ └── Index.ets // 主页 +│ └── resources // 应用资源文件 +``` + +### 具体实现 +* 使用Web组件菜单处理网页内容 +* 文本选中菜单实现:自定义菜单项与点击逻辑 + * 通过 editMenuOptions 接口自定义文本选中时弹出的菜单,支持增减菜单项、控制系统默认行为。 +* 上下文菜单实现:绑定自定义弹窗与元素交互 + * 针对超链接、图片等元素,通过 bindPopup 绑定自定义 Menu 组件,实现右键 / 长按触发的上下文菜单。 +* 自定义菜单实现:按元素类型绑定长按菜单(图片 / 链接) + * 通过 bindSelectionMenu 接口,为特定元素(图片 / 超链接)绑定专属长按菜单,支持预览窗口与菜单生命周期控制。 +* 菜单保存图片实现:沙箱暂存 + 图库持久化 + * 通过上下文菜单结合文件操作、图库接口,实现 Web 组件中图片的保存功能。 +* 菜单获取选中文本实现:JS 与 ArkTS 通信 + * 利用 javaScriptProxy 建立 Web 侧 JS 与 ArkTS 侧的通信,解决 editMenuOptions 无法直接获取选中文本的问题。 +* 菜单识别图片二维码实现:长按触发 + 图片解析 + * 通过上下文菜单结合图片处理、二维码解析接口,实现 Web 组件中图片二维码的识 +### 相关权限 + +不涉及 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行。 +2. 本示例支持API14版本SDK,SDK版本号(API Version 20 Release)。 +3. 本示例需要使用DevEco Studio 版本号(6.0.0Release)才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/ArkWeb/ArkWebMenu > .git/info/sparse-checkout +git remote add origin https://gitcode.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/build-profile.json5 b/ArkWebKit/ArkWebMenu/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..70fc5f86211a744ec7361750f6a908d602dc32f8 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/build-profile.json5 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "signingConfigs": [ + { + "name": "default", + "type": "HarmonyOS", + "material": { + "certpath": "C:\\Users\\wangrongfei.ICS-VTBAFCLMWDF\\.ohos\\config\\default_ArkWebMenu_mN1lMyhK4or8rqJmJzZvt0CbnulWUSLLyCZjJsM3rlw=.cer", + "keyAlias": "debugKey", + "keyPassword": "0000001BA6AF5182E25A93202A2142E9736634290FDA501A303E00AC8607BC4242688724B061EECB8C6052", + "profile": "C:\\Users\\wangrongfei.ICS-VTBAFCLMWDF\\.ohos\\config\\default_ArkWebMenu_mN1lMyhK4or8rqJmJzZvt0CbnulWUSLLyCZjJsM3rlw=.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\wangrongfei.ICS-VTBAFCLMWDF\\.ohos\\config\\default_ArkWebMenu_mN1lMyhK4or8rqJmJzZvt0CbnulWUSLLyCZjJsM3rlw=.p12", + "storePassword": "0000001B3DAF6136BEDAE121DB8581EB341431D522D7D21282DE76B8159625CA00702B1088D4263D0CC7CB" + } + } + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "targetSdkVersion": "6.0.0(20)", + "compatibleSdkVersion": "6.0.0(20)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/code-linter.json5 b/ArkWebKit/ArkWebMenu/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5c4682f8164874ec7e9cb8f99ff8b3228ffbc126 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/code-linter.json5 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@security/no-unsafe-aes": "error", + "@security/no-unsafe-hash": "error", + "@security/no-unsafe-mac": "warn", + "@security/no-unsafe-dh": "error", + "@security/no-unsafe-dsa": "error", + "@security/no-unsafe-ecdsa": "error", + "@security/no-unsafe-rsa-encrypt": "error", + "@security/no-unsafe-rsa-sign": "error", + "@security/no-unsafe-rsa-key": "error", + "@security/no-unsafe-dsa-key": "error", + "@security/no-unsafe-dh-key": "error", + "@security/no-unsafe-3des": "error" + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/build-profile.json5 b/ArkWebKit/ArkWebMenu/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9016faf39f8a65cf648bae246a53575510fe8b9f --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/build-profile.json5 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "resOptions": { + "copyCodeResource": { + "enable": false + } + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/hvigorfile.ts b/ArkWebKit/ArkWebMenu/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8b117a17af3b2d7cb87a7680e29e2bb8ccd5b46 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/obfuscation-rules.txt b/ArkWebKit/ArkWebMenu/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/oh-package.json5 b/ArkWebKit/ArkWebMenu/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..10cda399b0aec3099b257299a57d284393e4e55a --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/entryability/EntryAbility.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..98182799de1294d4c21194646a0c30eff08aea33 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + try { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + } catch (err) { + hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err)); + } + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ce6449f0e91914e73d4502c9f2e8e9a395ea4b1 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/Index.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..8261d4161a29bdf3b9ba471a201d3eaeaf4bfe0c --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,111 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { BusinessError } from '@kit.BasicServicesKit'; +import { common } from '@kit.AbilityKit'; +import hilog from '@ohos.hilog'; + +const TAG = '[Sample_WebMenu]' +const DOMAIN = 0xF811 +const BUNDLE = 'WebMenu_' +//Column space +const COLUMN_SPACE: Length = 10; +@Entry +@Component +struct Index { + build() { + Column({ space: COLUMN_SPACE }) { + Button('textMenuItem') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebTextMenuItem', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`) + }) + }) + Button('contextMenu') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebContextMenu', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('bindSelectionMenu') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebBindSelectionMenu', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('previewBuilder') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebPreviewBuilder', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('saveImage') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebSaveImage', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('editMenuOptions') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebEditMenuOptions', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('scanQRCode') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebScanQRCode', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + + Button('disableLongPress') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/WebDisableLongPress', + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, TAG, BUNDLE + `pushUrl failed, code is ${error.code}, message is ${error.message}`); + }) + }) + }.height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebBindSelectionMenu.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebBindSelectionMenu.ets new file mode 100644 index 0000000000000000000000000000000000000000..82dfa701e2d096aefd60bed022530baadf3e4abb --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebBindSelectionMenu.ets @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_BindSelectionMenu] +import { webview } from '@kit.ArkWeb'; + +//substring index +const SUBSTRING_INDEX: number = 19; + +interface PreviewBuilderParam { + previewImage: Resource | string | undefined; + width: number; + height: number; +} + +@Builder function previewBuilderGlobal($$: PreviewBuilderParam) { + Column() { + Image($$.previewImage) + .objectFit(ImageFit.Fill) + .autoResize(true) + }.width($$.width).height($$.height) +} + +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + + private result: WebContextMenuResult | undefined = undefined; + @State previewImage: Resource | string | undefined = undefined; + @State previewWidth: number = 0; + @State previewHeight: number = 0; + uiContext: UIContext = this.getUIContext(); + + @Builder + MenuBuilder() { + Menu() { + MenuItem({ content: $r('app.string.copy'), }) + .onClick(() => { + this.result?.copy(); + this.result?.closeContextMenu(); + }) + MenuItem({ content: $r('app.string.all'), }) + .onClick(() => { + this.result?.selectAll(); + this.result?.closeContextMenu(); + }) + } + } + build() { + Column() { + Web({ src: $rawfile('index2.html'), controller: this.controller }) + .bindSelectionMenu(WebElementType.IMAGE, this.MenuBuilder, WebResponseType.LONG_PRESS, + { + onAppear: () => {}, + onDisappear: () => { + this.result?.closeContextMenu(); + }, + preview: previewBuilderGlobal({ + previewImage: this.previewImage, + width: this.previewWidth, + height: this.previewHeight + }), + menuType: MenuType.PREVIEW_MENU + }) + .onContextMenuShow((event) => { + if (event) { + this.result = event.result; + if (event.param.getLinkUrl()) { + return false; + } + this.previewWidth = this.uiContext!.px2vp(event.param.getPreviewWidth()); + this.previewHeight = this.uiContext!.px2vp(event.param.getPreviewHeight()); + if (event.param.getSourceUrl().indexOf('resource://rawfile/') == 0) { + this.previewImage = $rawfile(event.param.getSourceUrl().substr(SUBSTRING_INDEX)); + } else { + this.previewImage = event.param.getSourceUrl(); + } + return true; + } + return false; + }) + } + } +} +// [End web_BindSelectionMenu] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebContextMenu.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebContextMenu.ets new file mode 100644 index 0000000000000000000000000000000000000000..374346d415c85a8554e33f675154941e6137fa58 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebContextMenu.ets @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_ContextMenu] +import { webview } from '@kit.ArkWeb'; +import { pasteboard } from '@kit.BasicServicesKit'; +import hilog from '@ohos.hilog'; + +const TAG = '[Sample_ContextMenu]' +const DOMAIN = 0xF811 +const BUNDLE = 'ContextMenu_' + +//MenuItem width +const MENUITEM_WIDTH: number = 100; +//MenuItem height +const MENUITEM_HEIGHT: number = 50; +//MenuBuilder width +const MENUBUILDER_WIDTH: number = 150; +//MenuBuilder height +const MENUBUILDER_HEIGHT: number = 300; + +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + private result: WebContextMenuResult | undefined = undefined; + @State linkUrl: string = ''; + @State offsetX: number = 0; + @State offsetY: number = 0; + @State showMenu: boolean = false; + uiContext: UIContext = this.getUIContext(); + + @Builder + // 构建自定义菜单及触发功能接口 + MenuBuilder() { + // 以垂直列表形式显示的菜单。 + Menu() { + // 展示菜单Menu中具体的item菜单项。 + MenuItem({ + content: $r('app.string.copy_image'), + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(() => { + this.result?.copyImage(); + this.showMenu = false; + }) + MenuItem({ + content: $r('app.string.cut'), + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(() => { + this.result?.cut(); + this.showMenu = false; + }) + MenuItem({ + content: $r('app.string.copy'), + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(() => { + this.result?.copy(); + this.showMenu = false; + }) + MenuItem({ + content: $r('app.string.paste'), + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(() => { + this.result?.paste(); + this.showMenu = false; + }) + MenuItem({ + content: $r('app.string.copy_url'), + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(() => { + let pasteData = pasteboard.createData('text/plain', this.linkUrl); + pasteboard.getSystemPasteboard().setData(pasteData, (error) => { + if (error) { + return; + } + }) + this.showMenu = false; + }) + MenuItem({ + content: $r('app.string.all'), + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(() => { + this.result?.selectAll(); + this.showMenu = false; + }) + } + .width(MENUBUILDER_WIDTH) + .height(MENUBUILDER_HEIGHT) + } + + build() { + Column() { + Web({ src: $rawfile('index1.html'), controller: this.controller }) + // 触发自定义弹窗 + .onContextMenuShow((event) => { + if (event) { + this.result = event.result + hilog.info(DOMAIN, TAG, BUNDLE + 'x coord = ' + event.param.x()); + hilog.info(DOMAIN, TAG, BUNDLE + 'link url = ' + event.param.getLinkUrl()); + this.linkUrl = event.param.getLinkUrl(); + } + hilog.info(DOMAIN, TAG, BUNDLE + `x: ${this.offsetX}, y: ${this.offsetY}`); + this.showMenu = true; + this.offsetX = 0; + this.offsetY = Math.max(this.uiContext!.px2vp(event?.param.y() ?? 0) - 0, 0); + return true; + }) + .bindPopup(this.showMenu, + { + builder: this.MenuBuilder(), + enableArrow: false, + placement: Placement.LeftTop, + offset: { x: this.offsetX, y: this.offsetY }, + mask: false, + onStateChange: (e) => { + if (!e.isVisible) { + this.showMenu = false; + this.result!.closeContextMenu(); + } + } + }) + } + } +} +// [End web_ContextMenu] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebDisableLongPress.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebDisableLongPress.ets new file mode 100644 index 0000000000000000000000000000000000000000..d6996667f03bab5a2eed0915b1c7e257bf4fe728 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebDisableLongPress.ets @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_Disable_long_press] +import { webview } from '@kit.ArkWeb'; +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + + onCreateMenu(menuItems: Array): Array { + let items = menuItems.filter((menuItem) => { + // 过滤用户需要的系统按键 + return false; + }); + return items; + } + + onMenuItemClick(menuItem: TextMenuItem, textRange: TextRange): boolean { + return false;// 返回默认值false + } + + @State editMenuOptions: EditMenuOptions = { onCreateMenu: this.onCreateMenu, onMenuItemClick: this.onMenuItemClick } + + build() { + Column() { + Web({ src: $rawfile('index7.html'), controller: this.controller }) + .editMenuOptions(this.editMenuOptions) + } + } +} +// [End web_Disable_long_press] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebEditMenuOptions.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebEditMenuOptions.ets new file mode 100644 index 0000000000000000000000000000000000000000..3f3338bd2873c221280d4601230fd561b690ffb4 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebEditMenuOptions.ets @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_EditMenuOptions] +import { webview } from '@kit.ArkWeb'; +let selectText = ''; +//font Size +const FONT_SIZE: number = 20; + +class SelectClass { + constructor() { + } + + setSelectText(param: String) { + selectText = param.toString(); + } +} + +@Entry +@Component +struct WebComponent { + webController: webview.WebviewController = new webview.WebviewController(); + @State selectObj: SelectClass = new SelectClass(); + @State textStr: string = ''; + + build() { + Column() { + Web({ src: $rawfile('index5.html'), controller: this.webController}) + .javaScriptProxy({ + object: this.selectObj, + name: 'selectObjName', + methodList: ['setSelectText'], + controller: this.webController + }) + .height('40%') + Text('Click here to get the selected text.') + .fontSize(FONT_SIZE) + .onClick(() => { + this.textStr = selectText; + }) + .height('10%') + Text('Selected text is ' + this.textStr) + .fontSize(FONT_SIZE) + .height('10%') + } + } +} +// [End web_EditMenuOptions] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebPreviewBuilder.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebPreviewBuilder.ets new file mode 100644 index 0000000000000000000000000000000000000000..13450aa5d2e3abfdbec3b91d0489834bf7c1a069 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebPreviewBuilder.ets @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_PreviewBuilder] +import { webview } from '@kit.ArkWeb'; +import { pasteboard } from '@kit.BasicServicesKit'; + +//text padding +const TEXT_PADDING: Length = 5; +//progress total +const PROGRESS_TOTAL:number = 100; +//progress stroke width +const PROGRESS_STROKE_WIDTH:number = 3; +//substring index +const SUBSTRING_INDEX:number = 19; +//preview width +const PREVIEW_WIDTH:number = 500; +//preview height +const PREVIEW_HEIGHT:number = 400; + +interface PreviewBuilderParam { + width: number; + height: number; + url: Resource | string | undefined; +} + +interface PreviewBuilderParamForImage { + previewImage: Resource | string | undefined; + width: number; + height: number; +} + + +@Builder +function previewBuilderGlobalForImage($$: PreviewBuilderParamForImage) { + Column() { + Image($$.previewImage) + .objectFit(ImageFit.Fill) + .autoResize(true) + }.width($$.width).height($$.height) +} + +@Entry +@Component +struct SelectionMenuLongPress { + controller: webview.WebviewController = new webview.WebviewController(); + previewController: webview.WebviewController = new webview.WebviewController(); + @Builder PreviewBuilder($$: PreviewBuilderParam){ + Column() { + Stack(){ + Text('') // 可选择是否展示url + .padding(TEXT_PADDING) + .width('100%') + .textAlign(TextAlign.Start) + .backgroundColor(Color.White) + .copyOption(CopyOptions.LocalDevice) + .maxLines(1) + .textOverflow({overflow:TextOverflow.Ellipsis}) + Progress({ value: this.progressValue, total: PROGRESS_TOTAL, type: ProgressType.Linear }) // 展示进度条 + .style({ strokeWidth: PROGRESS_STROKE_WIDTH, enableSmoothEffect: true }) + .backgroundColor(Color.White) + .opacity(this.progressVisible ? 1 : 0) + .backgroundColor(Color.White) + }.alignContent(Alignment.Bottom) + Web({src:$$.url,controller: new webview.WebviewController()}) + .javaScriptAccess(true) + .fileAccess(true) + .onlineImageAccess(true) + .imageAccess(true) + .domStorageAccess(true) + .onPageBegin(()=>{ + this.progressValue = 0; + this.progressVisible = true; + }) + .onProgressChange((event)=>{ + this.progressValue = event.newProgress; + }) + .onPageEnd(()=>{ + this.progressVisible = false; + }) + .hitTestBehavior(HitTestMode.None) // 使预览Web不响应手势 + }.width($$.width).height($$.height) // 设置预览宽高 + } + + private result: WebContextMenuResult | undefined = undefined; + @State previewImage: Resource | string | undefined = undefined; + @State previewWidth: number = 1; + @State previewHeight: number = 1; + @State previewWidthImage: number = 1; + @State previewHeightImage: number = 1; + @State linkURL:string = ''; + @State progressValue:number = 0; + @State progressVisible:boolean = true; + uiContext: UIContext = this.getUIContext(); + + @Builder + LinkMenuBuilder() { + Menu() { + MenuItem({ content: $r('app.string.copy_url'), }) + .onClick(() => { + const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.linkURL); + const systemPasteboard = pasteboard.getSystemPasteboard(); + systemPasteboard.setData(pasteboardData); + }) + MenuItem({ content: $r('app.string.open_url') }) + .onClick(()=>{ + this.controller.loadUrl(this.linkURL); + }) + } + } + @Builder + ImageMenuBuilder() { + Menu() { + MenuItem({ content: $r('app.string.copy_image'), }) + .onClick(() => { + this.result?.copyImage(); + this.result?.closeContextMenu(); + }) + } + } + build() { + Column() { + Web({ src: $rawfile('index3.html'), controller: this.controller }) + .javaScriptAccess(true) + .fileAccess(true) + .onlineImageAccess(true) + .imageAccess(true) + .domStorageAccess(true) + .bindSelectionMenu(WebElementType.LINK, this.LinkMenuBuilder, WebResponseType.LONG_PRESS, + { + onAppear: () => {}, + onDisappear: () => { + this.result?.closeContextMenu(); + }, + preview: this.PreviewBuilder({ + width: PREVIEW_WIDTH, + height: PREVIEW_HEIGHT, + url:this.linkURL + }), + menuType: MenuType.PREVIEW_MENU, + }) + .bindSelectionMenu(WebElementType.IMAGE, this.ImageMenuBuilder, WebResponseType.LONG_PRESS, + { + onAppear: () => {}, + onDisappear: () => { + this.result?.closeContextMenu(); + }, + preview: previewBuilderGlobalForImage({ + previewImage: this.previewImage, + width: this.previewWidthImage, + height: this.previewHeightImage, + }), + menuType: MenuType.PREVIEW_MENU, + }) + .zoomAccess(true) + .onContextMenuShow((event) => { + if (event) { + this.result = event.result; + this.previewWidthImage = this.uiContext!.px2vp(event.param.getPreviewWidth()); + this.previewHeightImage = this.uiContext!.px2vp(event.param.getPreviewHeight()); + if (event.param.getSourceUrl().indexOf('resource://rawfile/') == 0) { + this.previewImage = $rawfile(event.param.getSourceUrl().substring(SUBSTRING_INDEX)); + } else { + this.previewImage = event.param.getSourceUrl(); + } + this.linkURL = event.param.getLinkUrl() + return true; + } + return false; + }) + } + + } + // 侧滑返回 + onBackPress(): boolean | void { + if (this.controller.accessStep(-1)) { + this.controller.backward(); + return true; + } else { + return false; + } + } +} +// [End web_PreviewBuilder] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebSaveImage.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebSaveImage.ets new file mode 100644 index 0000000000000000000000000000000000000000..12b46a864c94ca677d1b56c736a500be8a9a0ff8 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebSaveImage.ets @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_Save_Image] +import { webview } from '@kit.ArkWeb'; +import { common } from '@kit.AbilityKit'; +import { fileIo as fs} from '@kit.CoreFileKit'; +import { systemDateTime } from '@kit.BasicServicesKit'; +import { http } from '@kit.NetworkKit'; +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import hilog from '@ohos.hilog'; + +//margin top +const MARGIN_TOP: number = 20; +//margin bottom +const MARGIN_BOTTOM: number = 20; +//buffer size +const BUFSIZE: number = 4096; +//border radius +const BORDER_RADIUS: number = 10; +const TAG = '[Sample_WebSaveImage]' +const DOMAIN = 0xF811 +const BUNDLE = 'WebSaveImage_' + +@Entry +@Component +struct WebComponent { + saveButtonOptions: SaveButtonOptions = { + icon: SaveIconStyle.FULL_FILLED, + text: SaveDescription.SAVE_IMAGE, + buttonType: ButtonType.Capsule + } + controller: webview.WebviewController = new webview.WebviewController(); + @State showMenu: boolean = false; + @State imgUrl: string = ''; + context = this.getUIContext().getHostContext() as common.UIAbilityContext; + + copyLocalPicToDir(rawfilePath: string, newFileName: string): string { + let srcFileDes = this.context.resourceManager.getRawFdSync(rawfilePath); + let dstPath = this.context.filesDir + '/' +newFileName; + let dest: fs.File = fs.openSync(dstPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); + let bufsize = BUFSIZE; + let buf = new ArrayBuffer(bufsize); + let off = 0; + let len = 0; + let readedLen = 0; + while ((len = fs.readSync(srcFileDes.fd, buf, { offset: srcFileDes.offset + off, length: bufsize })) != 0) { + readedLen += len; + fs.writeSync(dest.fd, buf, { offset: off, length: len }); + off = off + len; + if ((srcFileDes.length - readedLen) < bufsize) { + bufsize = srcFileDes.length - readedLen; + } + } + fs.close(dest.fd); + return dest.path; + } + + async copyUrlPicToDir(picUrl: string, newFileName: string): Promise { + let uri = ''; + let httpRequest = http.createHttp(); + let data: http.HttpResponse = await(httpRequest.request(picUrl) as Promise); + if (data?.responseCode == http.ResponseCode.OK) { + let dstPath = this.context.filesDir + '/' + newFileName; + let dest: fs.File = fs.openSync(dstPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); + let writeLen: number = fs.writeSync(dest.fd, data.result as ArrayBuffer); + uri = dest.path; + } + return uri; + } + + @Builder + MenuBuilder() { + Column() { + Row() { + SaveButton(this.saveButtonOptions) + .onClick(async (event, result: SaveButtonOnClickResult) => { + if (result == SaveButtonOnClickResult.SUCCESS) { + try { + let context = this.context; + let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); + let uri = ''; + if (this.imgUrl?.includes('rawfile')) { + let rawFileName: string = this.imgUrl.substring(this.imgUrl.lastIndexOf('/') + 1); + uri = this.copyLocalPicToDir(rawFileName, 'copyFile.png'); + } else if (this.imgUrl?.includes('http') || this.imgUrl?.includes('https')) { + uri = await this.copyUrlPicToDir(this.imgUrl, `onlinePic${systemDateTime.getTime()}.png`); + } + let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = + photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(context, uri); + await phAccessHelper.applyChanges(assetChangeRequest); + } catch (err) { + hilog.error(DOMAIN, TAG, BUNDLE + `create asset failed with error: ${err.code}, ${err.message}`); + } + } else { + hilog.error(DOMAIN, TAG, BUNDLE + `SaveButtonOnClickResult create asset failed`); + } + this.showMenu = false; + }) + } + .margin({ top: MARGIN_TOP, bottom: MARGIN_BOTTOM }) + .justifyContent(FlexAlign.Center) + } + .width('80') + .backgroundColor(Color.White) + .borderRadius(BORDER_RADIUS) + } + + build() { + Column() { + Web({src: $rawfile('index4.html'), controller: this.controller}) + .onContextMenuShow((event) => { + if (event) { + let hitValue = this.controller.getLastHitTest(); + this.imgUrl = hitValue.extra; + } + this.showMenu = true; + return true; + }) + .bindContextMenu(this.MenuBuilder, ResponseType.LongPress) + .fileAccess(true) + .javaScriptAccess(true) + .domStorageAccess(true) + } + } +} +// [End web_Save_Image] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebScanQRCode.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebScanQRCode.ets new file mode 100644 index 0000000000000000000000000000000000000000..4c2e180701fc28afa7777214d493e98a1f6d72ba --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebScanQRCode.ets @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_Scan_QR_code] +import { webview } from '@kit.ArkWeb'; +import { common } from '@kit.AbilityKit'; +import { fileIo as fs } from '@kit.CoreFileKit'; +import { systemDateTime } from '@kit.BasicServicesKit'; +import { http } from '@kit.NetworkKit'; +import { scanCore, scanBarcode, detectBarcode } from '@kit.ScanKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +//font size +const FONT_SIZE: number = 20; +//buffer size +const BUFSIZE: number = 4096; +//MenuItem width +const MENUITEM_WIDTH: number = 200; +//MenuItem height +const MENUITEM_HEIGHT: number = 50; + +@Entry +@Component +struct WebComponent { + saveButtonOptions: SaveButtonOptions = { + icon: SaveIconStyle.FULL_FILLED, + text: SaveDescription.SAVE_IMAGE, + buttonType: ButtonType.Capsule + } + controller: webview.WebviewController = new webview.WebviewController(); + private result: WebContextMenuResult | undefined = undefined; + @State showMenu: boolean = false; + @State imgUrl: string = ''; + @State decodeResult: string = ''; + context = this.getUIContext().getHostContext() as common.UIAbilityContext; + + copyLocalPicToDir(rawfilePath: string, newFileName: string): string { + let srcFileDes = this.context.resourceManager.getRawFdSync(rawfilePath); + let dstPath = this.context.filesDir + '/' +newFileName; + let dest: fs.File = fs.openSync(dstPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); + let bufsize = BUFSIZE; + let buf = new ArrayBuffer(bufsize); + let off = 0; + let len = 0; + let readedLen = 0; + while ((len = fs.readSync(srcFileDes.fd, buf, { offset: srcFileDes.offset + off, length: bufsize })) != 0) { + readedLen += len; + fs.writeSync(dest.fd, buf, { offset: off, length: len }); + off = off + len; + if ((srcFileDes.length - readedLen) < bufsize) { + bufsize = srcFileDes.length - readedLen; + } + } + fs.close(dest.fd); + return dest.path; + } + + async copyUrlPicToDir(picUrl: string, newFileName: string): Promise { + let uri = ''; + let httpRequest = http.createHttp(); + let data: http.HttpResponse = await(httpRequest.request(picUrl) as Promise); + if (data?.responseCode == http.ResponseCode.OK) { + let dstPath = this.context.filesDir + '/' + newFileName; + let dest: fs.File = fs.openSync(dstPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); + let writeLen: number = fs.writeSync(dest.fd, data.result as ArrayBuffer); + uri = dest.path; + } + return uri; + } + + @Builder + MenuBuilder() { + Menu() { + MenuItem({ + content: 'Scan QR Code', + }) + .width(MENUITEM_WIDTH) + .height(MENUITEM_HEIGHT) + .onClick(async () => { + try { + let uri = ''; + if (this.imgUrl?.includes('rawfile')) { + let rawFileName: string = this.imgUrl.substring(this.imgUrl.lastIndexOf('/') + 1); + uri = this.copyLocalPicToDir(rawFileName, 'copyFile.png'); + } else if (this.imgUrl?.includes('http') || this.imgUrl?.includes('https')) { + uri = await this.copyUrlPicToDir(this.imgUrl, `onlinePic${systemDateTime.getTime()}.png`); + } + let options: scanBarcode.ScanOptions = + { scanTypes: [scanCore.ScanType.ALL], enableMultiMode: true, enableAlbum: true } + let inputImage: detectBarcode.InputImage = { uri: uri }; + try { + // 调用图片识码接口 + detectBarcode.decode(inputImage, options, + (error: BusinessError, result: Array) => { + if (error && error.code) { + console.error(`create asset failed with error: ${error.code}, ${error.message}`); + return; + } + this.decodeResult = JSON.stringify(result); + }); + } catch (err) { + console.error(`Failed to detect Barcode. Code: ${err.code}, ${err.message}`); + } + } catch (err) { + console.error(`create asset failed with error: ${err.code}, ${err.message}`); + } + }) + } + } + + build() { + Column() { + Web({src: $rawfile('index6.html'), controller: this.controller}) + .onContextMenuShow((event) => { + if (event) { + let hitValue = this.controller.getLastHitTest(); + this.imgUrl = hitValue.extra; + } + this.showMenu = true; + return true; + }) + .bindContextMenu(this.MenuBuilder, ResponseType.LongPress) + .fileAccess(true) + .javaScriptAccess(true) + .domStorageAccess(true) + .height('40%') + Text('Decode result is ' + this.decodeResult) + .fontSize(FONT_SIZE) + .height('10%') + } + } +} +// [End web_Scan_QR_code] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebTextMenuItem.ets b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebTextMenuItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..494a2a12176ed8a490046e45264b0d40dc29eda0 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/ets/pages/WebTextMenuItem.ets @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start web_textMenuItem] +import { webview } from '@kit.ArkWeb'; +import hilog from '@ohos.hilog'; + +const TAG = '[Sample_TextMenuItem]' +const DOMAIN = 0xF811 +const BUNDLE = 'TextMenuItem_' + +@Entry +@Component +struct WebComponent { + controller: webview.WebviewController = new webview.WebviewController(); + + onCreateMenu(menuItems: Array): Array { + let items = menuItems.filter((menuItem) => { + // 过滤用户需要的系统按键 + return ( + menuItem.id.equals(TextMenuItemId.CUT) || + menuItem.id.equals(TextMenuItemId.COPY) || + menuItem.id.equals(TextMenuItemId.PASTE) + ); + }); + let customItem1: TextMenuItem = { + content: 'customItem1', + id: TextMenuItemId.of('customItem1'), + icon: $r('app.media.startIcon') + }; + let customItem2: TextMenuItem = { + content: $r('app.string.EntryAbility_label'), + id: TextMenuItemId.of('customItem2'), + icon: $r('app.media.startIcon') + }; + items.push(customItem1); // 在选项列表后添加新选项 + items.unshift(customItem2); // 在选项列表前添加选项 + items.push(customItem1); + items.push(customItem1); + items.push(customItem1); + items.push(customItem1); + items.push(customItem1); + return items; + } + + onMenuItemClick(menuItem: TextMenuItem, textRange: TextRange): boolean { + if (menuItem.id.equals(TextMenuItemId.CUT)) { + // 用户自定义行为 + hilog.info(DOMAIN, TAG, BUNDLE + 'intercept id:CUT') + return true; // 返回true不执行系统回调 + } else if (menuItem.id.equals(TextMenuItemId.COPY)) { + // 用户自定义行为 + hilog.info(DOMAIN, TAG, BUNDLE + 'Do not intercept id:COPY') + return false; // 返回false执行系统回调 + } else if (menuItem.id.equals(TextMenuItemId.of('customItem1'))) { + // 用户自定义行为 + hilog.info(DOMAIN, TAG, BUNDLE + 'intercept id:customItem1') + return true;// 用户自定义菜单选项返回true时点击后不关闭菜单,返回false时关闭菜单 + } else if (menuItem.id.equals(TextMenuItemId.of('customItem2'))){ + // 用户自定义行为 + hilog.info(DOMAIN, TAG, BUNDLE + 'intercept id:customItem2') + return true; + } + return false;// 返回默认值false + } + + @State editMenuOptions: EditMenuOptions = { onCreateMenu: this.onCreateMenu, onMenuItemClick: this.onMenuItemClick } + + build() { + Column() { + Web({ src: $rawfile('index.html'), controller: this.controller }) + .editMenuOptions(this.editMenuOptions) + } + } +} +// [End web_textMenuItem] \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/module.json5 b/ArkWebKit/ArkWebMenu/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..476f4f508edb44dc9edfe115808545c33b284e0b --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/module.json5 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "ohos.want.action.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ] + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/color.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/float.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..33ea22304f9b1485b5f22d811023701b5d4e35b6 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/string.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..1051cd6f5919f73ba39724f8962186f071983985 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/element/string.json @@ -0,0 +1,46 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + }, + { + "name": "copy_image", + "value": "复制图片" + }, + { + "name": "cut", + "value": "剪切" + }, + { + "name": "copy", + "value": "复制" + }, + { + "name": "paste", + "value": "粘贴" + }, + { + "name": "copy_url", + "value": "复制链接" + } + , + { + "name": "all", + "value": "全选" + }, + { + "name": "open_url", + "value": "打开链接" + } + + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/background.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/background.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/foreground.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/layered_image.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/startIcon.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/profile/backup_config.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/profile/main_pages.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..61eec987b87fa75b8f74de308f666c30b0ebcf77 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,13 @@ +{ + "src": [ + "pages/Index", + "pages/WebTextMenuItem", + "pages/WebContextMenu", + "pages/WebBindSelectionMenu", + "pages/WebPreviewBuilder", + "pages/WebSaveImage", + "pages/WebEditMenuOptions", + "pages/WebScanQRCode", + "pages/WebDisableLongPress" + ] +} diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/dark/element/color.json b/ArkWebKit/ArkWebMenu/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/example.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/example.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/example.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/img.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/img.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/img.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/imgCode.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/imgCode.png new file mode 100644 index 0000000000000000000000000000000000000000..01e34a3bc5bc2903f0665c31211c41b9aa9b698a Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/imgCode.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index.html new file mode 100644 index 0000000000000000000000000000000000000000..b97483aa41a95c609d25fa58cc77a3454af01e1d --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index.html @@ -0,0 +1,11 @@ + + + + + 测试网页 + + +

editMenuOptions Demo

+edit menu options + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index1.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index1.html new file mode 100644 index 0000000000000000000000000000000000000000..7610bca8caef18b82fc9103d927f1feeeac01aac --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index1.html @@ -0,0 +1,11 @@ + + + + +

onContextMenuShow

+超链接www.example.com + +
+

选中文字鼠标右键弹出菜单

+ + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index2.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index2.html new file mode 100644 index 0000000000000000000000000000000000000000..9088b78dac25f4e36c882d54edff39bb229d52d6 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index2.html @@ -0,0 +1,12 @@ + + + + + 测试网页 + + +

bindSelectionMenu Demo

+ + + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index3.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index3.html new file mode 100644 index 0000000000000000000000000000000000000000..d6ff0978094a73010c7136a628269e8a52571a3d --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index3.html @@ -0,0 +1,19 @@ + + + + 综合信息页面 + + +
+

综合信息与联系详情

+
+ EXAMPLE +
+ EXAMPLE1 +
+
+
+

请注意,以上提供的所有网址仅供演示之用。

+
+ + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index4.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index4.html new file mode 100644 index 0000000000000000000000000000000000000000..b95d42ba99e38ea7da3aed0cfea80253cd74a162 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index4.html @@ -0,0 +1,17 @@ + + + + + SavePicture + + +

SavePicture

+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index5.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index5.html new file mode 100644 index 0000000000000000000000000000000000000000..f5b06994fbb88578b3db0eaf9d348c5ef11a0ca8 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index5.html @@ -0,0 +1,41 @@ + + + + Test Get Select + + + +
+ +
+ + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index6.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index6.html new file mode 100644 index 0000000000000000000000000000000000000000..61f849e4edc7141aa970ea6270d608db6ffdba75 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index6.html @@ -0,0 +1,12 @@ + + + + + test QR code + + +

Long press and click to scan the QR code

+ + + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index7.html b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index7.html new file mode 100644 index 0000000000000000000000000000000000000000..b97483aa41a95c609d25fa58cc77a3454af01e1d --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/index7.html @@ -0,0 +1,11 @@ + + + + + 测试网页 + + +

editMenuOptions Demo

+edit menu options + + \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/startIcon.png b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/entry/src/main/resources/rawfile/startIcon.png differ diff --git a/ArkWebKit/ArkWebMenu/entry/src/mock/mock-config.json5 b/ArkWebKit/ArkWebMenu/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..323d1d611fecf4ecb751976e3a71500b3712a445 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/mock/mock-config.json5 @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkWebKit/ArkWebMenu/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b244772b2810f0138f461722c12817c12125b7f3 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { abilityDelegatorRegistry, Driver, ON } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +//Delay of 1000 milliseconds +const DELAY_1000: number = 1000; +//Delay of 3000 milliseconds +const DELAY_3000: number = 3000; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(async (done: Function) => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + const want: Want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + done(); + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(async (done: Function) => { + const driver = Driver.create(); + await driver.pressBack(); + await driver.delayMs(DELAY_3000); + done(); + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('testWebTextMenuItem001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('textMenuItem')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index.html'); + done(); + }) + + it('testContextMenu001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('contextMenu')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index1.html'); + done(); + }) + + it('testBindSelectionMenu001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('bindSelectionMenu')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index2.html'); + done(); + }) + + it('testWebPreviewBuilder001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('previewBuilder')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index3.html'); + done(); + }) + + it('testWebSaveImage001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('saveImage')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index4.html'); + done(); + }) + + it('testWebEditMenuOptions001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('editMenuOptions')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index5.html'); + done(); + }) + + it('testWebScanQRCode001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('scanQRCode')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index6.html'); + done(); + }) + + it('testWebDisableLongPress001', 0, async (done: Function) => { + const driver = Driver.create(); + await driver.delayMs(DELAY_1000); + + const button1 = await driver.findComponent(ON.text('disableLongPress')); + await button1.click(); + await driver.delayMs(DELAY_3000); + + const web1 = await driver.findComponent(ON.type('Web')); + let src: string = await web1.getText(); + expect(src).assertContain('index7.html'); + done(); + }) + + }) +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/ohosTest/ets/test/List.test.ets b/ArkWebKit/ArkWebMenu/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c64e0b06938d246ce044186d4b2d02b500a89e14 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/ohosTest/module.json5 b/ArkWebKit/ArkWebMenu/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..59667117c86b64ab9863f7b382c435ae4a3c32fa --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/ohosTest/module.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkWebKit/ArkWebMenu/entry/src/test/List.test.ets b/ArkWebKit/ArkWebMenu/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a60c87c5cbb0badf7c3fd8975034590e6fafa992 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/entry/src/test/LocalUnit.test.ets b/ArkWebKit/ArkWebMenu/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..841bfd77e56060e50ec0924302a5ae624e76e3aa --- /dev/null +++ b/ArkWebKit/ArkWebMenu/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/hvigor/hvigor-config.json5 b/ArkWebKit/ArkWebMenu/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3b057578a1bb4d591ee53054e39ab0154fc2e43a --- /dev/null +++ b/ArkWebKit/ArkWebMenu/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "6.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + // "optimizationStrategy": "memory" /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/ArkWebKit/ArkWebMenu/hvigorfile.ts b/ArkWebKit/ArkWebMenu/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae9086af35844176c08f1be3772d081d95d267c6 --- /dev/null +++ b/ArkWebKit/ArkWebMenu/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/ArkWebKit/ArkWebMenu/oh-package.json5 b/ArkWebKit/ArkWebMenu/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..837c0ff9f35a6bb9eea849fead7955c19bcdec8d --- /dev/null +++ b/ArkWebKit/ArkWebMenu/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "6.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.24", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkWebKit/ArkWebMenu/ohosTest.md b/ArkWebKit/ArkWebMenu/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..3db9d0210b137ce3a72f28a49d16669593142b0a --- /dev/null +++ b/ArkWebKit/ArkWebMenu/ohosTest.md @@ -0,0 +1,35 @@ +## 文本选中菜单 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|----------| ------------ | ------------ |-----------------------| -------- | -------- | +| 自定义Web组件的文本选中菜单 | 设备运转正常 | 应用启动成功 | 加载网页正常;文字的长按内容为自定义的内容 | Yes | Pass | + +## 上下文菜单 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ---------------- | ------------ | ------------ | ---------------- | -------- | -------- | +| 长按富文本触发的快捷菜单 | 设备运转正常 | 应用启动成功 | 加载网页正常;长按富文本触发的快捷菜单 | Yes | Pass | + +## 自定义菜单 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ---------------- | ------------ | ------------ |--------------------| -------- | -------- | +| 长按图片响应自定义菜单 | 设备运转正常 | 应用启动成功 | 加载网页正常;长按图片响应自定义菜单 | Yes | Pass | + +## Web菜单保存图片 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|-----------| ------------ | ------------ |-------------------| -------- | -------- | +| 保存web上的图片 | 设备运转正常 | 应用启动成功 | 加载网页正常;保存图片到沙箱和图库 | Yes | Pass | + +## Web菜单获取选中文本 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|---------------------| ------------ | ------------ |--------------------------| -------- | -------- | +| web上复制内容可以在Ark侧正常使用 | 设备运转正常 | 应用启动成功 | 加载网页正常;Ark侧能获取到web上复制的文本 | Yes | Pass | + +## Web菜单识别图片二维码 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|------------| ------------ | ------------ |------------------| -------- | -------- | +| 识别web上的二维码 | 设备运转正常 | 应用启动成功 | 加载网页正常;正确识别二维码信息 | Yes | Pass | diff --git a/ArkWebKit/ArkWebMenu/screenshots/web_bindSelectionMenu.gif b/ArkWebKit/ArkWebMenu/screenshots/web_bindSelectionMenu.gif new file mode 100644 index 0000000000000000000000000000000000000000..ab89a94318438260eab9beb7daac9d211e215318 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/screenshots/web_bindSelectionMenu.gif differ diff --git a/ArkWebKit/ArkWebMenu/screenshots/web_context_Menu_Show.gif b/ArkWebKit/ArkWebMenu/screenshots/web_context_Menu_Show.gif new file mode 100644 index 0000000000000000000000000000000000000000..e78cb0f3204d0759531e9b116579833b34271356 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/screenshots/web_context_Menu_Show.gif differ diff --git a/ArkWebKit/ArkWebMenu/screenshots/web_saveImage.gif b/ArkWebKit/ArkWebMenu/screenshots/web_saveImage.gif new file mode 100644 index 0000000000000000000000000000000000000000..0e7a7c270a78a9103c0fd22951e5926cd1a0b2ac Binary files /dev/null and b/ArkWebKit/ArkWebMenu/screenshots/web_saveImage.gif differ diff --git a/ArkWebKit/ArkWebMenu/screenshots/web_scanQRCode.gif b/ArkWebKit/ArkWebMenu/screenshots/web_scanQRCode.gif new file mode 100644 index 0000000000000000000000000000000000000000..2faef202c3ae862eddc05387893888031d8faeeb Binary files /dev/null and b/ArkWebKit/ArkWebMenu/screenshots/web_scanQRCode.gif differ diff --git a/ArkWebKit/ArkWebMenu/screenshots/web_select_text.gif b/ArkWebKit/ArkWebMenu/screenshots/web_select_text.gif new file mode 100644 index 0000000000000000000000000000000000000000..6bfb1973939f96469cf4222197c0cd845ffb4903 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/screenshots/web_select_text.gif differ diff --git a/ArkWebKit/ArkWebMenu/screenshots/web_text_menuItem.gif b/ArkWebKit/ArkWebMenu/screenshots/web_text_menuItem.gif new file mode 100644 index 0000000000000000000000000000000000000000..5513e8d81dab8d827a7314e2393b6dba6e86ce55 Binary files /dev/null and b/ArkWebKit/ArkWebMenu/screenshots/web_text_menuItem.gif differ