diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..4120e63 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Normalize line endings to LF for all text files (abapGit + tooling expect LF) +* text=auto eol=lf +*.abap text eol=lf +*.xml text eol=lf +*.json text eol=lf +*.jsonc text eol=lf +*.md text eol=lf +*.mjs text eol=lf +*.js text eol=lf +*.yaml text eol=lf +*.yml text eol=lf diff --git a/.github/abaplint/abap_cloud.jsonc b/.github/abaplint/abap_cloud.jsonc new file mode 100644 index 0000000..b1c006e --- /dev/null +++ b/.github/abaplint/abap_cloud.jsonc @@ -0,0 +1,46 @@ +{ + "global": { + "files": "/../../src/**/*.*" + }, + "dependencies": [ + { + "url": "https://github.com/abapedia/steampunk-2305-api-intersect-702", + "folder": "/deps", + "files": "/src/**/*.*" + }, + { + "url": "https://github.com/abap2UI5/abap2UI5", + "folder": "/abap2UI5", + "files": "/src/**/*.*" + }, + { + "url": "https://github.com/abap2UI5-addons/popups", + "folder": "/popups", + "files": "/src/**/*.*" + }, + { + "url": "https://github.com/abap2xlsx/abap2xlsx", + "folder": "/abap2xlsx", + "files": "/src/**/*.*" + } + ], + "syntax": { + "version": "Cloud", + "errorNamespace": "." + }, + "rules": { + "downport": true, + "begin_end_names": true, + "check_ddic": true, + "check_include": true, + "check_syntax": true, + "global_class": true, + "definitions_top": false, + "implement_methods": true, + "method_implemented_twice": true, + "parser_error": true, + "superclass_final": true, + "unknown_types": true, + "xml_consistency": true + } +} diff --git a/.github/abaplint/rename.json b/.github/abaplint/rename.json new file mode 100644 index 0000000..f430ae9 --- /dev/null +++ b/.github/abaplint/rename.json @@ -0,0 +1,63 @@ +{ + "global": { + "files": "/../../src/**/*.*" + }, + "dependencies": [ + { + "url": "https://github.com/abapedia/steampunk-2305-api-intersect-702", + "folder": "/deps", + "files": "/src/**/*.*" + }, + { + "url": "https://github.com/abap2UI5/abap2UI5", + "folder": "/abap2UI5", + "files": "/src/**/*.*" + }, + { + "url": "https://github.com/abap2UI5-addons/popups", + "folder": "/popups", + "files": "/src/**/*.*" + }, + { + "url": "https://github.com/abap2xlsx/abap2xlsx", + "folder": "/abap2xlsx", + "files": "/src/**/*.*" + } + ], + "rename": { + "output": "output", + "patterns": [ + { + "type": "CLAS|INTF|TABL", + "oldName": "z2ui5_(.*)", + "newName": "zabap2ui5_$1" + } + ] + }, + "syntax": { + "version": "v750", + "errorNamespace": "." + }, + "rules": { + "allowed_object_types": { + "allowed": [ + "CLAS", + "DEVC", + "INTF", + "TABL" + ] + }, + "allowed_object_naming": true, + "begin_end_names": true, + "check_ddic": true, + "check_include": true, + "check_syntax": true, + "global_class": true, + "implement_methods": true, + "method_implemented_twice": true, + "parser_error": true, + "superclass_final": true, + "unknown_types": true, + "xml_consistency": true + } +} diff --git a/.github/workflows/ABAP_CLOUD.yaml b/.github/workflows/ABAP_CLOUD.yaml new file mode 100644 index 0000000..b5bdebd --- /dev/null +++ b/.github/workflows/ABAP_CLOUD.yaml @@ -0,0 +1,26 @@ +name: ABAP_CLOUD + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: ABAP_CLOUD-${{ github.ref }} + cancel-in-progress: true + +jobs: + ABAP_CLOUD: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: '22' + cache: 'npm' + - run: npm ci + - run: npx abaplint .github/abaplint/abap_cloud.jsonc diff --git a/.github/workflows/ABAP_STANDARD.yaml b/.github/workflows/ABAP_STANDARD.yaml new file mode 100644 index 0000000..68dec42 --- /dev/null +++ b/.github/workflows/ABAP_STANDARD.yaml @@ -0,0 +1,26 @@ +name: ABAP_STANDARD + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: ABAP_STANDARD-${{ github.ref }} + cancel-in-progress: true + +jobs: + ABAP_STANDARD: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: '22' + cache: 'npm' + - run: npm ci + - run: npx abaplint ./abaplint.jsonc diff --git a/.github/workflows/build_rename.yaml b/.github/workflows/build_rename.yaml new file mode 100644 index 0000000..ad80cf3 --- /dev/null +++ b/.github/workflows/build_rename.yaml @@ -0,0 +1,101 @@ +name: build_rename + +# Renames all artifacts to a chosen namespace and pushes the result to +# the branch rename_, e.g. rename_zmyui5 - ready to pull with +# abapGit for a parallel installation in the same SAP system. The +# renaming itself is the plain abaplint rename with the checked-in +# config .github/abaplint/rename.json (placeholder "zabap2ui5"); this +# workflow only sets the chosen name in the config and stores the +# result. Re-running with the same name updates the branch to the +# current main state; without content changes nothing is pushed. The +# main commit is carried as second parent so GitHub shows the branch as +# "ahead" instead of "behind" main. + +on: + workflow_dispatch: + inputs: + namespace: + description: "New namespace (max. 9 characters), e.g. ZMYUI5" + required: true + type: string + default: zabap2ui5 + +permissions: + contents: write + +concurrency: + group: build_rename-${{ inputs.namespace }} + cancel-in-progress: false + +jobs: + build_rename: + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + NAMESPACE: ${{ inputs.namespace }} + steps: + # validate the input and derive the branch name before building + - name: Derive branch name + run: | + if ! printf '%s' "$NAMESPACE" | grep -Eq '^[A-Za-z][A-Za-z0-9_]{0,8}$'; then + echo "::error::Invalid namespace '$NAMESPACE' (letter + letters/digits/underscore, max. 9 characters)" + exit 1 + fi + ns=$(printf '%s' "$NAMESPACE" | tr '[:upper:]' '[:lower:]') + if [ "$ns" = "z2ui5" ]; then + echo "::error::Namespace '$NAMESPACE' is the original namespace - nothing to rename" + exit 1 + fi + echo "NS=$ns" >> "$GITHUB_ENV" + echo "BRANCH=rename_$ns" >> "$GITHUB_ENV" + echo "Building branch: rename_$ns" + + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: '22' + cache: 'npm' + - run: npm ci + + # set the chosen name in the rename config and run the abaplint + # rename; it writes the renamed sources to + # .github/abaplint/output//src + - name: Rename to ${{ inputs.namespace }} + run: | + sed "s/zabap2ui5/$NS/g" .github/abaplint/rename.json > .github/abaplint/rename_run.json + npx abaplint .github/abaplint/rename_run.json --rename + + # branch content: the renamed src tree plus the abapGit descriptor + # and the license + - name: Assemble branch content + run: | + src=$(find .github/abaplint/output -type d -name src | head -n 1) + if [ -z "$src" ]; then + echo "::error::no renamed src folder found under .github/abaplint/output" + exit 1 + fi + out=".github/out/$BRANCH" + rm -rf "$out" + mkdir -p "$out" + cp -r "$src" "$out/src" + cp LICENSE "$out/" + cp .abapgit.xml "$out/" + + - name: Push renamed branch + run: | + b="$BRANCH" + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + git fetch origin "$b" --depth 1 2>/dev/null || true + parent=$(git rev-parse -q --verify "refs/remotes/origin/$b" || true) + index="$RUNNER_TEMP/index-$b" + rm -f "$index" + (cd ".github/out/$b" && GIT_DIR="$GITHUB_WORKSPACE/.git" GIT_WORK_TREE=. GIT_INDEX_FILE="$index" git add -A) + tree=$(GIT_INDEX_FILE="$index" git write-tree) + if [ -n "$parent" ] && [ "$(git rev-parse "$parent^{tree}")" = "$tree" ]; then + echo "$b: no changes" + exit 0 + fi + commit=$(git commit-tree "$tree" ${parent:+-p "$parent"} -p "$GITHUB_SHA" -m "build: $b from $GITHUB_SHA") + git push origin "$commit:refs/heads/$b" + echo "$b: pushed $commit" diff --git a/.github/workflows/rename_test.yaml b/.github/workflows/rename_test.yaml new file mode 100644 index 0000000..d063063 --- /dev/null +++ b/.github/workflows/rename_test.yaml @@ -0,0 +1,26 @@ +name: renaming + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: rename_test-${{ github.ref }} + cancel-in-progress: true + +jobs: + rename_test: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: '22' + cache: 'npm' + - run: npm ci + - run: npm run rename diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..970868c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +output +.github/out/ +.github/abaplint/output/ +.github/abaplint/rename_run.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..29dda86 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,67 @@ +# AGENTS.md — AI Assistant Guide for abap2UI5 table-content-loader + +> This file follows the cross-tool AGENTS.md convention and is the single +> agent instruction file of this repository — Claude Code reads `AGENTS.md` +> natively, there is no separate `CLAUDE.md`. + +## Project Overview + +Upload, edit and download table content (JSON, CSV, XLSX) for +[abap2UI5](https://github.com/abap2UI5/abap2UI5) (`z2ui5_cl_tcl_*`). + +**Language:** English — all code, comments, commit messages, PRs, issues and +documentation must be in English. + +## Package Structure + +| Package | Content | +|---|---| +| `src/` | App classes `z2ui5_cl_tcl_app_00` … `_06` | +| `src/01/z2ui5_cl_tcl_xlsx_api` | XLSX helper | +| `src/z2ui5_cl_tcl_context` | Vendored utility copy — **see below** | + +## The Utility Copy Principle + +`z2ui5_cl_tcl_context` is a **trimmed, renamed copy** of the abap2UI5 utility +class (`z2ui5_cl_util` in the core), carrying only the methods this addon uses +(conv/itab/json/xml/rtti helpers) plus the private helpers and char constants +those need. The app calls `z2ui5_cl_tcl_context=>…`, never `z2ui5_cl_util=>…` +directly. This keeps the install dependency-free (abapGit has no dependency +management). The core and the other addons use the same pattern. When a new +utility method is needed, copy it from the core utility class (with its private +helpers) into the context copy rather than adding a dependency. + +## Dependencies + +Installed alongside via abapGit; declared in the abaplint configs: + +* [abap2UI5](https://github.com/abap2UI5/abap2UI5) +* [popups](https://github.com/abap2UI5-addons/popups) +* [abap2xlsx](https://github.com/abap2xlsx/abap2xlsx) + +## Security + +This is a developer tool. It reads from and writes to any table the user names, +without an authorization check of its own (the Z/Y namespace hint on write is +only a warning, not enforced). Before using it beyond a development system, add +your own `AUTHORITY-CHECK`s and restrict who may run the app. + +## Coding Style + +Follows the abap2UI5 core conventions (see its +[AGENTS.md](https://github.com/abap2UI5/abap2UI5/blob/main/AGENTS.md)): Clean +ABAP with Hungarian prefixes, backtick string literals, string templates +(`|…{ }…|`) instead of `&&`. + +## Validation + +Run `npx abaplint` before considering changes complete (config `abaplint.jsonc`, +0 issues expected). CI: + +* `ABAP_STANDARD` / `ABAP_CLOUD` — lint against Standard ABAP and ABAP Cloud +* `renaming` (`rename_test.yaml`) — namespace-rename check +* `build_rename` — manual workflow that pushes a namespace-renamed branch + `rename_` for a parallel install + +There is no 702 downport: the abap2xlsx dependency has no `702` branch. +All `.abap`/`.xml`/config files are LF-only (`.gitattributes` enforces it). diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..464b9ee --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement by opening a +private report via the repository's [Security Advisory form](https://github.com/abap2UI5-addons/table-content-loader/security/advisories/new). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/LICENSE b/LICENSE index fd08f21..2a60ede 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 oblomov +Copyright (c) 2024 abap2UI5 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 11c54a1..688f8fe 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +[![ABAP_STANDARD](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/ABAP_STANDARD.yaml/badge.svg)](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/ABAP_STANDARD.yaml) +[![ABAP_CLOUD](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/ABAP_CLOUD.yaml/badge.svg)](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/ABAP_CLOUD.yaml) +[![ABAP_702](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/ABAP_702.yaml/badge.svg)](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/ABAP_702.yaml) +
+[![auto_cloud](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/auto_cloud.yaml/badge.svg)](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/auto_cloud.yaml) +[![auto_downport](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/auto_downport.yaml/badge.svg)](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/auto_downport.yaml) +
+[![renaming](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/rename_test.yaml/badge.svg)](https://github.com/abap2UI5-addons/table-content-loader/actions/workflows/rename_test.yaml) + # Table Content Loader Upload, Edit & Download Table Content

_Supported Formats: JSON, CSV, XLSX..._ @@ -8,10 +17,13 @@ _Supported Formats: JSON, CSV, XLSX..._ * Data Preview #### Compatibility -* S/4 Public Cloud ABAP and BTP ABAP Environment (ABAP for Cloud) +* S/4 Public Cloud and BTP ABAP Environment (ABAP for Cloud) * S/4 Private Cloud or On-Premise (ABAP for Cloud, Standard ABAP) * SAP NetWeaver AS ABAP 7.50 or higher (Standard ABAP) +#### Security +This is a developer tool. It reads from and writes to any table the user names, without an authorization check of its own (the Z/Y namespace hint on write is only a warning, not an enforced restriction). Before using it beyond a development system, add your own authorization checks (e.g. `AUTHORITY-CHECK` on `S_TABU_DIS`/`S_TABU_NAM`) and restrict who may run the app. + #### Dependencies * [abap2UI5](https://github.com/abap2UI5/abap2UI5) * [popups](https://github.com/abap2UI5-addons/popups) @@ -23,7 +35,7 @@ _Supported Formats: JSON, CSV, XLSX..._ * XLSX Upload/Download for ABAP Cloud #### Demo -Table Content Loader start page with tiles for JSON, CSV and XLSX upload and download +Table Content Loader start page with tiles for JSON, CSV and XLSX upload and download #### Contribution & Support -Pull Requests are welcome! Whether you're fixing a bug, adding new functionality, or improving the documentation, your contributions are always appreciated. If you run into problems, feel free to open an issue. +Pull requests are welcome! Whether you're fixing bugs, adding new functionality, or improving documentation, your contributions are highly appreciated. If you encounter any issues, feel free to open an issue. diff --git a/abaplint.jsonc b/abaplint.jsonc index 5770d75..4516ff5 100644 --- a/abaplint.jsonc +++ b/abaplint.jsonc @@ -41,6 +41,9 @@ "parser_error": true, "superclass_final": true, "unknown_types": true, - "xml_consistency": true + "xml_consistency": true, + "exporting": true, + "omit_parameter_name": true, + "prefix_is_current_class": true } } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2cfa04e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,35 @@ +{ + "name": "abap2ui5-table-content-loader", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "abap2ui5-table-content-loader", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@abaplint/cli": "^2.119.66" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@abaplint/cli": { + "version": "2.119.66", + "resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.119.66.tgz", + "integrity": "sha512-Anjsm5G0jUnWwEAZrk2Ckm0we+VCrwjc/MOMSSk+774VJ6ka1ovkj981Y8BJdbxcKgKzIvn+D/ddap/tdxMFbw==", + "dev": true, + "license": "MIT", + "bin": { + "abaplint": "abaplint" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/larshp" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9c24ff3 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "abap2ui5-table-content-loader", + "private": true, + "version": "1.0.0", + "description": "Upload, edit and download table content (JSON, CSV, XLSX), built with abap2UI5.", + "scripts": { + "rename": "abaplint .github/abaplint/rename.json --rename" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/abap2UI5-addons/table-content-loader.git" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/abap2UI5-addons/table-content-loader/issues" + }, + "homepage": "https://github.com/abap2UI5-addons/table-content-loader#readme", + "devDependencies": { + "@abaplint/cli": "^2.119.66" + }, + "engines": { + "node": ">=22" + } +} diff --git a/src/01/z2ui5_cl_tcl_xlsx_api.clas.abap b/src/01/z2ui5_cl_tcl_xlsx_api.clas.abap index 57ac78b..bbff0e9 100644 --- a/src/01/z2ui5_cl_tcl_xlsx_api.clas.abap +++ b/src/01/z2ui5_cl_tcl_xlsx_api.clas.abap @@ -51,7 +51,7 @@ CLASS z2ui5_cl_tcl_xlsx_api IMPLEMENTATION. lt_field_catalog = fieldcatalog. IF lt_field_catalog IS INITIAL. - lt_field_catalog = zcl_excel_common=>get_fieldcatalog( ip_table = val ). + lt_field_catalog = zcl_excel_common=>get_fieldcatalog( val ). ENDIF. ls_table_settings = settings. diff --git a/src/z2ui5_cl_tcl_app_01.clas.abap b/src/z2ui5_cl_tcl_app_01.clas.abap index a887a8a..b34552f 100644 --- a/src/z2ui5_cl_tcl_app_01.clas.abap +++ b/src/z2ui5_cl_tcl_app_01.clas.abap @@ -9,7 +9,6 @@ CLASS z2ui5_cl_tcl_app_01 DEFINITION DATA: BEGIN OF ms_app, check_initialized TYPE abap_bool, - max_rows TYPE string, file TYPE string, file_size TYPE string, file_entries TYPE string, @@ -85,7 +84,7 @@ CLASS Z2UI5_CL_TCL_APP_01 IMPLEMENTATION. CASE client->get( )-event. - WHEN 'DB_CHECK'. + WHEN `DB_CHECK`. TRY. ms_app-db_table = to_upper( ms_app-db_table ). @@ -94,13 +93,13 @@ CLASS Z2UI5_CL_TCL_APP_01 IMPLEMENTATION. FROM (ms_app-db_table) INTO ms_app-db_table_entries. - IF to_upper( ms_app-db_table(1) ) <> `Z` AND to_upper( ms_app-db_table(1) ) <> `Y`. + IF to_upper( ms_app-db_table(1) ) <> `Z` AND to_upper( ms_app-db_table(1) ) <> `Y`. client->message_box_display( `Only Tables in namespace Z or Y allowed` ). ENDIF. client->view_model_update( ). CATCH cx_root. - client->message_box_display( `DB Table not found, check input: ` && ms_app-db_table ). + client->message_box_display( |DB Table not found, check input: { ms_app-db_table }| ). ENDTRY. WHEN `PROCESS`. @@ -110,7 +109,7 @@ CLASS Z2UI5_CL_TCL_APP_01 IMPLEMENTATION. CREATE DATA mt_tab TYPE STANDARD TABLE OF (ms_app-db_table). ASSIGN mt_tab->* TO . - z2ui5_cl_util=>json_parse( + z2ui5_cl_tcl_context=>json_parse( EXPORTING val = ms_app-file CHANGING @@ -127,29 +126,24 @@ CLASS Z2UI5_CL_TCL_APP_01 IMPLEMENTATION. WHEN `PREVIEW`. DATA lr_tab TYPE REF TO data. - DATA lr_dummy TYPE REF TO data. - lr_tab = z2ui5_cl_util=>conv_copy_ref_data( mt_tab ). + lr_tab = z2ui5_cl_tcl_context=>conv_copy_ref_data( mt_tab ). ASSIGN lr_tab->* TO . - LOOP AT REFERENCE INTO lr_dummy. - IF sy-tabix > 5. - DELETE . - ENDIF. - ENDLOOP. + DELETE FROM 6. client->nav_app_call( z2ui5_cl_popup_table=>factory( ) ). - WHEN 'DB_SAVE'. + WHEN `DB_SAVE`. client->nav_app_call( z2ui5_cl_popup_to_confirm=>factory( `Database will be deleted and new entries filled. Are you sure?` ) ). - WHEN 'UPLOAD'. + WHEN `UPLOAD`. client->nav_app_call( z2ui5_cl_popup_file_ul=>factory( ) ). - WHEN 'BUTTON_CANCEL'. - client->message_toast_display( |cancel| ). + WHEN `BUTTON_CANCEL`. + client->message_toast_display( `Cancelled` ). - WHEN 'BACK'. + WHEN `BACK`. client->nav_app_leave( client->get_app( client->get( )-s_draft-id_prev_app_stack ) ). ENDCASE. @@ -170,7 +164,7 @@ CLASS Z2UI5_CL_TCL_APP_01 IMPLEMENTATION. DATA(page) = view->shell( appwidthlimited = client->_bind_edit( ms_app-check_appwidthlimited ) )->page( title = 'abap2UI5 - JSON File Upload' - navbuttonpress = client->_event( 'BACK' ) + navbuttonpress = client->_event( `BACK` ) shownavbutton = xsdbool( client->get( )-s_draft-id_prev_app_stack IS NOT INITIAL ) )->header_content( )->overflow_toolbar( @@ -202,7 +196,7 @@ CLASS Z2UI5_CL_TCL_APP_01 IMPLEMENTATION. )->label( `(4) Preview Rows` )->button( text = `Go` width = `10%` press = client->_event( `PREVIEW` ) )->label( `(5) Save Database` - )->text( `Attention - Database Content will be deleted!!!` + )->text( `Attention - Database Content will be deleted!` )->label( )->button( text = `Run` width = `10%` press = client->_event( `DB_SAVE` ) ). diff --git a/src/z2ui5_cl_tcl_app_01.clas.testclasses.abap b/src/z2ui5_cl_tcl_app_01.clas.testclasses.abap index a2ac6a6..0cf7fa7 100644 --- a/src/z2ui5_cl_tcl_app_01.clas.testclasses.abap +++ b/src/z2ui5_cl_tcl_app_01.clas.testclasses.abap @@ -17,11 +17,11 @@ CLASS ltcl_unit_test IMPLEMENTATION. DATA(lv_csv_base64) = `VXNlcm5hbWUsIElkZW50aWZpZXIsRmlyc3QgbmFtZSxMYXN0IG5hbWUNCmJvb2tlcjEyLDkwMTIsUmFjaGVsLEJvb2tlcg0KZ3JleTA3LDIwNzAsTGF1cmEsR3JleQ0Kam9obnNvbjgxLDQwODEsQ3JhaWcsSm9obnNvbg0KamVua2luczQ2LDkzNDYsTWFyeSxKZW5raW5zDQpzbWl0aDc5LDUwNzksSmFtaWUsU21pdGg=`. - DATA(lv_data) = z2ui5_cl_util=>conv_decode_x_base64( lv_csv_base64 ). - DATA(lv_ready) = z2ui5_cl_util=>conv_get_string_by_xstring( lv_data ). + DATA(lv_data) = z2ui5_cl_tcl_context=>conv_decode_x_base64( lv_csv_base64 ). + DATA(lv_ready) = z2ui5_cl_tcl_context=>conv_get_string_by_xstring( lv_data ). - DATA(lv_readyx) = z2ui5_cl_util=>conv_get_xstring_by_string( lv_ready ). - DATA(lv_data2) = z2ui5_cl_util=>conv_encode_x_base64( lv_readyx ). + DATA(lv_readyx) = z2ui5_cl_tcl_context=>conv_get_xstring_by_string( lv_ready ). + DATA(lv_data2) = z2ui5_cl_tcl_context=>conv_encode_x_base64( lv_readyx ). IF lv_data2 <> lv_csv_base64. ASSERT 1 = 0. diff --git a/src/z2ui5_cl_tcl_app_02.clas.abap b/src/z2ui5_cl_tcl_app_02.clas.abap index a4d8f47..7cbda52 100644 --- a/src/z2ui5_cl_tcl_app_02.clas.abap +++ b/src/z2ui5_cl_tcl_app_02.clas.abap @@ -335,8 +335,8 @@ CLASS Z2UI5_CL_TCL_APP_02 IMPLEMENTATION. )->label( 'Table' )->input( 'SPFLI' )->label( 'Format' - )->segmented_button( client->_bind_edit( ms_import-segment_key ) )->get( - )->items( )->get( + )->segmented_button( client->_bind_edit( ms_import-segment_key ) + )->items( )->segmented_button_item( key = 'json' text = 'json' )->segmented_button_item( key = 'csv' text = 'csv' )->segmented_button_item( key = 'xml' text = 'xml' ). diff --git a/src/z2ui5_cl_tcl_app_02.clas.locals_imp.abap b/src/z2ui5_cl_tcl_app_02.clas.locals_imp.abap index 4e33db1..067cda6 100644 --- a/src/z2ui5_cl_tcl_app_02.clas.locals_imp.abap +++ b/src/z2ui5_cl_tcl_app_02.clas.locals_imp.abap @@ -70,7 +70,7 @@ CLASS lcl_db IMPLEMENTATION. METHOD get_table_by_json. - z2ui5_cl_util=>json_parse( EXPORTING val = val + z2ui5_cl_tcl_context=>json_parse( EXPORTING val = val CHANGING data = result ). ENDMETHOD. @@ -78,7 +78,7 @@ CLASS lcl_db IMPLEMENTATION. METHOD get_table_by_xml. - z2ui5_cl_util=>xml_parse( EXPORTING xml = val + z2ui5_cl_tcl_context=>xml_parse( EXPORTING xml = val IMPORTING any = result ). ENDMETHOD. @@ -87,10 +87,10 @@ CLASS lcl_db IMPLEMENTATION. FIELD-SYMBOLS TYPE STANDARD TABLE. - DATA(lr_tab) = z2ui5_cl_util=>itab_get_itab_by_csv( val ). + DATA(lr_tab) = z2ui5_cl_tcl_context=>itab_get_itab_by_csv( val ). ASSIGN lr_tab->* TO . - z2ui5_cl_util=>itab_corresponding( EXPORTING val = + z2ui5_cl_tcl_context=>itab_corresponding( EXPORTING val = CHANGING tab = result ). ENDMETHOD. @@ -116,25 +116,25 @@ CLASS lcl_db IMPLEMENTATION. METHOD get_csv_by_table. - result = z2ui5_cl_util=>itab_get_csv_by_itab( val ). + result = z2ui5_cl_tcl_context=>itab_get_csv_by_itab( val ). ENDMETHOD. METHOD get_json_by_table. - result = z2ui5_cl_util=>json_stringify( val ). + result = z2ui5_cl_tcl_context=>json_stringify( val ). ENDMETHOD. METHOD get_xml_by_table. - result = z2ui5_cl_util=>xml_stringify( val ). + result = z2ui5_cl_tcl_context=>xml_stringify( val ). ENDMETHOD. METHOD get_fieldlist_by_table. - LOOP AT z2ui5_cl_util=>rtti_get_t_attri_by_any( it_table ) REFERENCE INTO DATA(lr_attri). + LOOP AT z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( it_table ) REFERENCE INTO DATA(lr_attri). INSERT CONV #( lr_attri->name ) INTO TABLE result. ENDLOOP. diff --git a/src/z2ui5_cl_tcl_app_03.clas.abap b/src/z2ui5_cl_tcl_app_03.clas.abap index bb44ab5..f4044c2 100644 --- a/src/z2ui5_cl_tcl_app_03.clas.abap +++ b/src/z2ui5_cl_tcl_app_03.clas.abap @@ -17,10 +17,7 @@ CLASS z2ui5_cl_tcl_app_03 DEFINITION check_initialized TYPE abap_bool, check_popup TYPE abap_bool, itab TYPE REF TO data, - max_rows TYPE string, file TYPE string, - file_size TYPE string, - file_entries TYPE string, check_appwidthlimited TYPE abap_bool VALUE abap_true, db_table TYPE string VALUE 'SPFLI', db_table_entries TYPE string, @@ -46,7 +43,7 @@ CLASS z2ui5_cl_tcl_app_03 IMPLEMENTATION. METHOD factory_popup_by_itab. result = NEW #( ). - result->ms_app-itab = z2ui5_cl_util=>conv_copy_ref_data( itab ). + result->ms_app-itab = z2ui5_cl_tcl_context=>conv_copy_ref_data( itab ). result->ms_app-check_popup = abap_true. ENDMETHOD. @@ -88,14 +85,14 @@ CLASS z2ui5_cl_tcl_app_03 IMPLEMENTATION. client->view_model_update( ). CATCH cx_root. - client->message_box_display( `DB Table not found, check input: ` && ms_app-db_table ). + client->message_box_display( |DB Table not found, check input: { ms_app-db_table }| ). ENDTRY. WHEN `PROCESS`. FIELD-SYMBOLS TYPE STANDARD TABLE. - mt_tab = z2ui5_cl_util=>rtti_create_tab_by_name( ms_app-db_table ). + mt_tab = z2ui5_cl_tcl_context=>rtti_create_tab_by_name( ms_app-db_table ). ASSIGN mt_tab->* TO . SELECT * @@ -104,7 +101,7 @@ CLASS z2ui5_cl_tcl_app_03 IMPLEMENTATION. TRY. - ms_app-file = z2ui5_cl_util=>json_stringify( ). + ms_app-file = z2ui5_cl_tcl_context=>json_stringify( ). client->message_toast_display( |JSON created| ). CATCH cx_root INTO DATA(x). @@ -113,7 +110,7 @@ CLASS z2ui5_cl_tcl_app_03 IMPLEMENTATION. WHEN `PREVIEW`. - mt_tab = z2ui5_cl_util=>rtti_create_tab_by_name( ms_app-db_table ). + mt_tab = z2ui5_cl_tcl_context=>rtti_create_tab_by_name( ms_app-db_table ). ASSIGN mt_tab->* TO . SELECT * @@ -121,14 +118,14 @@ CLASS z2ui5_cl_tcl_app_03 IMPLEMENTATION. INTO CORRESPONDING FIELDS OF TABLE UP TO 10 ROWS. - DATA(lv_prev_json) = z2ui5_cl_util=>json_stringify( ). + DATA(lv_prev_json) = z2ui5_cl_tcl_context=>json_stringify( ). client->nav_app_call( z2ui5_cl_popup_textedit=>factory( lv_prev_json ) ). WHEN 'DOWNLOAD'. client->nav_app_call( z2ui5_cl_popup_file_dl=>factory( ms_app-file ) ). WHEN 'BUTTON_CANCEL'. - client->message_toast_display( |cancel| ). + client->message_toast_display( `Cancelled` ). WHEN 'BACK'. client->nav_app_leave( client->get_app( client->get( )-s_draft-id_prev_app_stack ) ). diff --git a/src/z2ui5_cl_tcl_app_04.clas.abap b/src/z2ui5_cl_tcl_app_04.clas.abap index a9d7d78..b13b56d 100644 --- a/src/z2ui5_cl_tcl_app_04.clas.abap +++ b/src/z2ui5_cl_tcl_app_04.clas.abap @@ -43,10 +43,10 @@ CLASS Z2UI5_CL_TCL_APP_04 IMPLEMENTATION. WHEN 'UPLOAD'. - DATA(lv_data) = z2ui5_cl_util=>conv_get_xstring_by_data_uri( mv_value ). - DATA(lv_ready) = z2ui5_cl_util=>conv_get_string_by_xstring( lv_data ). + DATA(lv_data) = z2ui5_cl_tcl_context=>conv_get_xstring_by_data_uri( mv_value ). + DATA(lv_ready) = z2ui5_cl_tcl_context=>conv_get_string_by_xstring( lv_data ). - mr_table = z2ui5_cl_util=>itab_get_itab_by_csv( lv_ready ). + mr_table = z2ui5_cl_tcl_context=>itab_get_itab_by_csv( lv_ready ). client->message_box_display( `CSV loaded to table` ). ui5_view_main_display( ). @@ -96,9 +96,9 @@ CLASS Z2UI5_CL_TCL_APP_04 IMPLEMENTATION. FIELD-SYMBOLS TYPE table. ASSIGN mr_table->* TO . mv_check_download = abap_false. - DATA(lv_csv) = z2ui5_cl_util=>itab_get_csv_by_itab( ). - DATA(lv_xcsv) = z2ui5_cl_util=>conv_get_xstring_by_string( lv_csv ). - DATA(lv_base) = z2ui5_cl_util=>conv_encode_x_base64( lv_xcsv ). + DATA(lv_csv) = z2ui5_cl_tcl_context=>itab_get_csv_by_itab( ). + DATA(lv_xcsv) = z2ui5_cl_tcl_context=>conv_get_xstring_by_string( lv_csv ). + DATA(lv_base) = z2ui5_cl_tcl_context=>conv_encode_x_base64( lv_xcsv ). view->_cc_plain_xml( '' ). ENDIF. @@ -106,7 +106,7 @@ CLASS Z2UI5_CL_TCL_APP_04 IMPLEMENTATION. ASSIGN mr_table->* TO . DATA(tab) = page->table( - items = client->_bind_edit( ) + client->_bind_edit( ) )->header_toolbar( )->overflow_toolbar( )->title( 'CSV Content' @@ -119,7 +119,7 @@ CLASS Z2UI5_CL_TCL_APP_04 IMPLEMENTATION. )->get_parent( )->get_parent( ). - DATA(lr_fields) = VALUE string_table( FOR row IN z2ui5_cl_util=>rtti_get_t_attri_by_any( ) ( row-name ) ). + DATA(lr_fields) = VALUE string_table( FOR row IN z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( ) ( row-name ) ). DATA(lo_cols) = tab->columns( ). LOOP AT lr_fields REFERENCE INTO DATA(lr_col). lo_cols->column( )->text( lr_col->* ). @@ -139,7 +139,7 @@ CLASS Z2UI5_CL_TCL_APP_04 IMPLEMENTATION. footer->_z2ui5( )->file_uploader( value = client->_bind_edit( mv_value ) path = client->_bind_edit( mv_path ) - placeholder = 'filepath here...' + placeholder = `File path here...` upload = client->_event( 'UPLOAD' ) ). footer->toolbar_spacer( diff --git a/src/z2ui5_cl_tcl_app_05.clas.abap b/src/z2ui5_cl_tcl_app_05.clas.abap index 93847c3..d16f18f 100644 --- a/src/z2ui5_cl_tcl_app_05.clas.abap +++ b/src/z2ui5_cl_tcl_app_05.clas.abap @@ -40,7 +40,7 @@ CLASS Z2UI5_CL_TCL_APP_05 IMPLEMENTATION. WHEN 'UPLOAD'. - DATA(lv_xdata) = z2ui5_cl_util=>conv_get_xstring_by_data_uri( mv_value ). + DATA(lv_xdata) = z2ui5_cl_tcl_context=>conv_get_xstring_by_data_uri( mv_value ). mr_table = z2ui5_cl_tcl_xlsx_api=>get_table_by_xlsx( lv_xdata ). client->message_box_display( `XLSX loaded to table` ). @@ -83,15 +83,15 @@ CLASS Z2UI5_CL_TCL_APP_05 IMPLEMENTATION. ASSIGN mr_table->* TO . mv_check_download = abap_false. DATA(lv_xlsx) = z2ui5_cl_tcl_xlsx_api=>get_xlsx_by_table( ). - DATA(lv_base) = z2ui5_cl_util=>conv_encode_x_base64( lv_xlsx ). - view->_generic( ns = `html` name = `iframe` t_prop = VALUE #( ( n = `src` v = `data:text/csv;base64,` && lv_base ) ( n = `hidden` v = `hidden` ) ) ). + DATA(lv_base) = z2ui5_cl_tcl_context=>conv_encode_x_base64( lv_xlsx ). + view->_generic( ns = `html` name = `iframe` t_prop = VALUE #( ( n = `src` v = `data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,` && lv_base ) ( n = `hidden` v = `hidden` ) ) ). ENDIF. IF mr_table IS NOT INITIAL. ASSIGN mr_table->* TO . DATA(tab) = page->table( - items = client->_bind_edit( ) + client->_bind_edit( ) )->header_toolbar( )->overflow_toolbar( )->title( 'XLSX Content' @@ -103,7 +103,7 @@ CLASS Z2UI5_CL_TCL_APP_05 IMPLEMENTATION. customtextoff = 'View' )->get_parent( )->get_parent( ). - DATA(lr_fields) = z2ui5_cl_util=>rtti_get_t_attri_by_any( ). + DATA(lr_fields) = z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( ). DATA(lo_cols) = tab->columns( ). LOOP AT lr_fields REFERENCE INTO DATA(lr_col). lo_cols->column( )->text( lr_col->name ). @@ -123,7 +123,7 @@ CLASS Z2UI5_CL_TCL_APP_05 IMPLEMENTATION. footer->_z2ui5( )->file_uploader( value = client->_bind_edit( mv_value ) path = client->_bind_edit( mv_path ) - placeholder = 'filepath here...' + placeholder = `File path here...` upload = client->_event( 'UPLOAD' ) ). footer->toolbar_spacer( diff --git a/src/z2ui5_cl_tcl_app_06.clas.abap b/src/z2ui5_cl_tcl_app_06.clas.abap index 263912b..d9ac017 100644 --- a/src/z2ui5_cl_tcl_app_06.clas.abap +++ b/src/z2ui5_cl_tcl_app_06.clas.abap @@ -70,7 +70,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. TRY. - DATA(lr_tab) = z2ui5_cl_util=>rtti_create_tab_by_name( ms_draft-table_name ). + DATA(lr_tab) = z2ui5_cl_tcl_context=>rtti_create_tab_by_name( ms_draft-table_name ). FIELD-SYMBOLS TYPE table. ASSIGN lr_tab->* TO . @@ -93,7 +93,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. title = ms_draft-t_config_head[ 1 ]-title settings = ms_draft-t_config[ 1 ] fieldcatalog = ms_draft-t_fcat ). - mv_file = z2ui5_cl_util=>conv_encode_x_base64( lv_result ). + mv_file = z2ui5_cl_tcl_context=>conv_encode_x_base64( lv_result ). ms_draft-file_rows = lines( ). ms_draft-file_size = xstrlen( lv_result ) / 1000. @@ -126,11 +126,11 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. ms_draft-table_name = CAST z2ui5_cl_popup_input_val( lo_prev )->result( )-value. ms_draft-check_load_pressed = abap_true. - ms_draft-t_tab = z2ui5_cl_util=>rtti_create_tab_by_name( ms_draft-table_name ). + ms_draft-t_tab = z2ui5_cl_tcl_context=>rtti_create_tab_by_name( ms_draft-table_name ). FIELD-SYMBOLS TYPE table. ASSIGN ms_draft-t_tab->* TO . - ms_draft-t_fcat = zcl_excel_common=>get_fieldcatalog( ip_table = ). + ms_draft-t_fcat = zcl_excel_common=>get_fieldcatalog( ). DATA ls_table_settings TYPE zexcel_s_table_settings. ls_table_settings-table_style = zcl_excel_table=>builtinstyle_medium5. INSERT ls_table_settings INTO TABLE ms_draft-t_config. @@ -222,7 +222,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. IF ms_draft-t_tab IS BOUND. FIELD-SYMBOLS TYPE table. ASSIGN ms_draft-t_tab->* TO . - ms_draft-t_fcat = zcl_excel_common=>get_fieldcatalog( ip_table = ). + ms_draft-t_fcat = zcl_excel_common=>get_fieldcatalog( ). ENDIF. set_view( ). @@ -332,7 +332,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. ). DATA(tab) = cont->table( - items = client->_bind_edit( ms_draft-t_config ) + client->_bind_edit( ms_draft-t_config ) )->header_toolbar( )->overflow_toolbar( )->title( `Excel Configuration` @@ -340,7 +340,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. )->button( text = `Reset` press = client->_event( `RESET_CONFIG` ) icon = `sap-icon://refresh` type = `Emphasized` )->get_parent( )->get_parent( ). - DATA(lt_fields) = z2ui5_cl_util=>rtti_get_t_attri_by_any( ms_draft-t_config ). + DATA(lt_fields) = z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( ms_draft-t_config ). DATA(lo_columns) = tab->columns( ). LOOP AT lt_fields INTO DATA(lv_field) FROM 1. @@ -360,7 +360,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. ). tab = cont->table( - items = client->_bind_edit( ms_draft-t_config_head ) + client->_bind_edit( ms_draft-t_config_head ) )->header_toolbar( )->overflow_toolbar( )->title( `Parameter` @@ -368,7 +368,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. )->button( text = `Reset` press = client->_event( `RESET_CONFIG` ) icon = `sap-icon://refresh` type = `Emphasized` )->get_parent( )->get_parent( ). - lt_fields = z2ui5_cl_util=>rtti_get_t_attri_by_any( ms_draft-t_config_head ). + lt_fields = z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( ms_draft-t_config_head ). lo_columns = tab->columns( ). LOOP AT lt_fields INTO lv_field FROM 1. @@ -393,7 +393,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. ). DATA(tab) = cont->table( - items = client->_bind_edit( ms_draft-t_fcat ) + client->_bind_edit( ms_draft-t_fcat ) )->header_toolbar( )->overflow_toolbar( )->title( `Excel Fieldcatalog` @@ -401,7 +401,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. )->button( text = `Reset` press = client->_event( `RESET_FCAT` ) icon = `sap-icon://refresh` type = `Emphasized` )->get_parent( )->get_parent( ). - DATA(lt_fields) = z2ui5_cl_util=>rtti_get_t_attri_by_any( ms_draft-t_fcat ). + DATA(lt_fields) = z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( ms_draft-t_fcat ). DATA(lo_columns) = tab->columns( ). LOOP AT lt_fields INTO DATA(lv_field) FROM 1. @@ -421,7 +421,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. IF mv_check_download_file = abap_true. mv_check_download_file = abap_false. - page->_generic( ns = `html` name = `iframe` t_prop = VALUE #( ( n = `src` v = `data:text/csv;base64,` && mv_file ) ( n = `hidden` v = `hidden` ) ) ). + page->_generic( ns = `html` name = `iframe` t_prop = VALUE #( ( n = `src` v = `data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,` && mv_file ) ( n = `hidden` v = `hidden` ) ) ). ENDIF. @@ -430,7 +430,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. editable = `true` ). content->label( `Activate Row Limitation` - )->checkbox( selected = client->_bind_edit( ms_draft-check_file_row_limit ) + )->checkbox( client->_bind_edit( ms_draft-check_file_row_limit ) )->label( `Rows` )->input( value = client->_bind_edit( ms_draft-file_max_rows ) enabled = client->_bind_edit( ms_draft-check_file_row_limit ) width = `10%` )->label( `Prepare File with abap2xlsx` @@ -460,7 +460,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. ). DATA(tab) = cont->table( - items = client->_bind( ) + client->_bind( ) )->header_toolbar( )->overflow_toolbar( )->title( `(1) Data Preview - ` && ms_draft-table_name @@ -469,7 +469,7 @@ CLASS Z2UI5_CL_TCL_APP_06 IMPLEMENTATION. )->button( text = `Reset` press = client->_event( `LOAD` ) icon = `sap-icon://refresh` type = `Emphasized` )->get_parent( )->get_parent( ). - DATA(lt_fields) = z2ui5_cl_util=>rtti_get_t_attri_by_any( ). + DATA(lt_fields) = z2ui5_cl_tcl_context=>rtti_get_t_attri_by_any( ). DATA(lo_columns) = tab->columns( ). LOOP AT lt_fields INTO DATA(lv_field) FROM 1. diff --git a/src/z2ui5_cl_tcl_context.clas.abap b/src/z2ui5_cl_tcl_context.clas.abap new file mode 100644 index 0000000..c7f712c --- /dev/null +++ b/src/z2ui5_cl_tcl_context.clas.abap @@ -0,0 +1,562 @@ +CLASS z2ui5_cl_tcl_context DEFINITION + PUBLIC + CREATE PUBLIC. + + PUBLIC SECTION. + + "! Vendored copy of the abap2UI5 utility methods this app uses, so the + "! app carries its own context instead of depending on z2ui5_cl_util. + CLASS-DATA cv_char_util_newline TYPE c LENGTH 1 READ-ONLY. + CLASS-DATA cv_char_util_cr_lf TYPE c LENGTH 2 READ-ONLY. + CLASS-DATA cv_char_util_horizontal_tab TYPE c LENGTH 1 READ-ONLY. + + CLASS-METHODS class_constructor. + + CLASS-METHODS conv_copy_ref_data + IMPORTING + !from TYPE any + RETURNING + VALUE(result) TYPE REF TO data. + + CLASS-METHODS conv_decode_x_base64 + IMPORTING + val TYPE string + RETURNING + VALUE(result) TYPE xstring. + + CLASS-METHODS conv_encode_x_base64 + IMPORTING + val TYPE xstring + RETURNING + VALUE(result) TYPE string. + + CLASS-METHODS conv_get_string_by_xstring + IMPORTING + val TYPE xstring + RETURNING + VALUE(result) TYPE string. + + CLASS-METHODS conv_get_xstring_by_data_uri + IMPORTING + val TYPE clike + RETURNING + VALUE(result) TYPE xstring. + + CLASS-METHODS conv_get_xstring_by_string + IMPORTING + val TYPE string + RETURNING + VALUE(result) TYPE xstring. + + CLASS-METHODS itab_corresponding + IMPORTING + val TYPE STANDARD TABLE + CHANGING + !tab TYPE STANDARD TABLE. + + CLASS-METHODS itab_get_csv_by_itab + IMPORTING + val TYPE any + RETURNING + VALUE(result) TYPE string. + + CLASS-METHODS itab_get_itab_by_csv + IMPORTING + val TYPE string + RETURNING + VALUE(result) TYPE REF TO data. + + CLASS-METHODS json_parse + IMPORTING + val TYPE any + CHANGING + !data TYPE any. + + CLASS-METHODS json_stringify + IMPORTING + !any TYPE any + RETURNING + VALUE(result) TYPE string. + + CLASS-METHODS rtti_create_tab_by_name + IMPORTING + val TYPE clike + RETURNING + VALUE(result) TYPE REF TO data. + + CLASS-METHODS rtti_get_t_attri_by_any + IMPORTING + val TYPE any + RETURNING + VALUE(result) TYPE cl_abap_structdescr=>component_table. + + CLASS-METHODS xml_parse + IMPORTING + !xml TYPE clike + EXPORTING + !any TYPE any. + + CLASS-METHODS xml_stringify + IMPORTING + !any TYPE any + RETURNING + VALUE(result) TYPE string + RAISING + cx_xslt_serialization_error. + + PROTECTED SECTION. + + CLASS-METHODS c_trim + IMPORTING + val TYPE any + RETURNING + VALUE(result) TYPE string. + + CLASS-METHODS c_trim_upper + IMPORTING + val TYPE clike + RETURNING + VALUE(result) TYPE string. + + CLASS-METHODS rtti_check_ref_data + IMPORTING + val TYPE any + RETURNING + VALUE(result) TYPE abap_bool. + + CLASS-METHODS rtti_get_t_attri_by_include + IMPORTING + !type TYPE REF TO cl_abap_datadescr + RETURNING + VALUE(result) TYPE abap_component_tab. + + PRIVATE SECTION. +ENDCLASS. + + +CLASS z2ui5_cl_tcl_context IMPLEMENTATION. + + METHOD class_constructor. + + cv_char_util_newline = cl_abap_char_utilities=>newline. + cv_char_util_cr_lf = cl_abap_char_utilities=>cr_lf. + cv_char_util_horizontal_tab = cl_abap_char_utilities=>horizontal_tab. + + ENDMETHOD. + + METHOD conv_copy_ref_data. + + FIELD-SYMBOLS TYPE data. + FIELD-SYMBOLS TYPE data. + + IF rtti_check_ref_data( from ). + ASSIGN from->* TO . + ELSE. + ASSIGN from TO . + ENDIF. + CREATE DATA result LIKE . + ASSIGN result->* TO . + + = . + + ENDMETHOD. + + METHOD conv_decode_x_base64. + DATA lv_web_http_name TYPE c LENGTH 19. + DATA classname TYPE c LENGTH 15. + + TRY. + + lv_web_http_name = `CL_WEB_HTTP_UTILITY`. + CALL METHOD (lv_web_http_name)=>(`DECODE_X_BASE64`) + EXPORTING + encoded = val + RECEIVING + decoded = result. + + CATCH cx_root. + + classname = `CL_HTTP_UTILITY`. + CALL METHOD (classname)=>(`DECODE_X_BASE64`) + EXPORTING + encoded = val + RECEIVING + decoded = result. + + ENDTRY. + + ENDMETHOD. + + METHOD conv_encode_x_base64. + DATA lv_web_http_name TYPE c LENGTH 19. + DATA classname TYPE c LENGTH 15. + + TRY. + + lv_web_http_name = `CL_WEB_HTTP_UTILITY`. + CALL METHOD (lv_web_http_name)=>(`ENCODE_X_BASE64`) + EXPORTING + unencoded = val + RECEIVING + encoded = result. + + CATCH cx_root. + + classname = `CL_HTTP_UTILITY`. + CALL METHOD (classname)=>(`ENCODE_X_BASE64`) + EXPORTING + unencoded = val + RECEIVING + encoded = result. + + ENDTRY. + + ENDMETHOD. + + METHOD conv_get_string_by_xstring. + + DATA conv TYPE REF TO object. + DATA conv_codepage TYPE c LENGTH 21. + DATA conv_in_class TYPE c LENGTH 18. + + TRY. + + conv_codepage = `CL_ABAP_CONV_CODEPAGE`. + CALL METHOD (conv_codepage)=>create_in + RECEIVING + instance = conv. + + CALL METHOD conv->(`IF_ABAP_CONV_IN~CONVERT`) + EXPORTING + source = val + RECEIVING + result = result. + + CATCH cx_root. + + conv_in_class = `CL_ABAP_CONV_IN_CE`. + CALL METHOD (conv_in_class)=>create + EXPORTING + encoding = `UTF-8` + RECEIVING + conv = conv. + + CALL METHOD conv->(`CONVERT`) + EXPORTING + input = val + IMPORTING + data = result. + ENDTRY. + + ENDMETHOD. + + METHOD conv_get_xstring_by_data_uri. + + DATA lv_metadata TYPE string ##NEEDED. + DATA lv_base64 TYPE string. + + SPLIT val AT `,` INTO lv_metadata lv_base64. + result = conv_decode_x_base64( lv_base64 ). + + ENDMETHOD. + + METHOD conv_get_xstring_by_string. + + DATA conv TYPE REF TO object. + DATA conv_codepage TYPE c LENGTH 21. + DATA conv_out_class TYPE c LENGTH 19. + + TRY. + + conv_codepage = `CL_ABAP_CONV_CODEPAGE`. + CALL METHOD (conv_codepage)=>create_out + RECEIVING + instance = conv. + + CALL METHOD conv->(`IF_ABAP_CONV_OUT~CONVERT`) + EXPORTING + source = val + RECEIVING + result = result. + + CATCH cx_root. + + conv_out_class = `CL_ABAP_CONV_OUT_CE`. + CALL METHOD (conv_out_class)=>create + EXPORTING + encoding = `UTF-8` + RECEIVING + conv = conv. + + CALL METHOD conv->(`CONVERT`) + EXPORTING + data = val + IMPORTING + buffer = result. + ENDTRY. + + ENDMETHOD. + + METHOD itab_corresponding. + + FIELD-SYMBOLS TYPE any. + FIELD-SYMBOLS TYPE any. + + LOOP AT val ASSIGNING . + APPEND INITIAL LINE TO tab ASSIGNING . + MOVE-CORRESPONDING TO . + ENDLOOP. + + ENDMETHOD. + + METHOD itab_get_csv_by_itab. + + FIELD-SYMBOLS TYPE table. + DATA lt_lines TYPE string_table. + DATA lv_line TYPE string. + + ASSIGN val TO . + DATA(tab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( ) ). + + DATA(struc) = CAST cl_abap_structdescr( tab->get_table_line_type( ) ). + + CLEAR lv_line. + LOOP AT struc->get_components( ) REFERENCE INTO DATA(lr_comp). + lv_line = |{ lv_line }{ lr_comp->name };|. + ENDLOOP. + INSERT lv_line INTO TABLE lt_lines. + + DATA lr_row TYPE REF TO data. + LOOP AT REFERENCE INTO lr_row. + + CLEAR lv_line. + DATA(lv_index) = 1. + DO. + ASSIGN lr_row->* TO FIELD-SYMBOL(). + ASSIGN COMPONENT lv_index OF STRUCTURE TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + EXIT. + ENDIF. + lv_index = lv_index + 1. + DATA(lv_field_val) = |{ }|. + REPLACE ALL OCCURRENCES OF `;` IN lv_field_val WITH `,`. + lv_line = |{ lv_line }{ lv_field_val };|. + ENDDO. + INSERT lv_line INTO TABLE lt_lines. + ENDLOOP. + + result = concat_lines_of( table = lt_lines sep = cv_char_util_cr_lf ). + + ENDMETHOD. + + METHOD itab_get_itab_by_csv. + + DATA lt_comp TYPE cl_abap_structdescr=>component_table. + FIELD-SYMBOLS TYPE STANDARD TABLE. + DATA lr_row TYPE REF TO data. + + SPLIT val AT cv_char_util_newline INTO TABLE DATA(lt_rows). + SPLIT lt_rows[ 1 ] AT `;` INTO TABLE DATA(lt_cols). + + LOOP AT lt_cols REFERENCE INTO DATA(lr_col). + + DATA(lv_name) = c_trim_upper( lr_col->* ). + REPLACE ALL OCCURRENCES OF ` ` IN lv_name WITH `_`. + + INSERT VALUE #( name = lv_name + type = cl_abap_elemdescr=>get_c( 40 ) ) INTO TABLE lt_comp. + ENDLOOP. + + DATA(struc) = cl_abap_structdescr=>get( lt_comp ). + DATA(data) = CAST cl_abap_datadescr( struc ). + DATA(o_table_desc) = cl_abap_tabledescr=>create( p_line_type = data + p_table_kind = cl_abap_tabledescr=>tablekind_std + p_unique = abap_false ). + + CREATE DATA result TYPE HANDLE o_table_desc. + ASSIGN result->* TO . + DELETE lt_rows WHERE table_line IS INITIAL. + + LOOP AT lt_rows REFERENCE INTO DATA(lr_rows) FROM 2. + + SPLIT lr_rows->* AT `;` INTO TABLE lt_cols. + CREATE DATA lr_row TYPE HANDLE struc. + + LOOP AT lt_cols REFERENCE INTO lr_col. + ASSIGN lr_row->* TO FIELD-SYMBOL(). + ASSIGN COMPONENT sy-tabix OF STRUCTURE TO FIELD-SYMBOL(). + IF sy-subrc <> 0. + EXIT. + ENDIF. + = lr_col->*. + ENDLOOP. + + INSERT INTO TABLE . + ENDLOOP. + + ENDMETHOD. + + METHOD json_parse. + TRY. + + z2ui5_cl_ajson=>parse( val )->to_abap( EXPORTING iv_corresponding = abap_true + IMPORTING ev_container = data ). + + CATCH cx_root INTO DATA(x). + RAISE EXCEPTION TYPE z2ui5_cx_util_error + EXPORTING + val = x. + ENDTRY. + ENDMETHOD. + + METHOD json_stringify. + TRY. + + DATA(li_ajson) = CAST z2ui5_if_ajson( z2ui5_cl_ajson=>create_empty( ) ). + result = li_ajson->set( iv_path = `/` + iv_val = any )->stringify( ). + + CATCH cx_root INTO DATA(x). + RAISE EXCEPTION TYPE z2ui5_cx_util_error + EXPORTING + val = x. + ENDTRY. + ENDMETHOD. + + METHOD rtti_create_tab_by_name. + + DATA(struct_desc) = cl_abap_structdescr=>describe_by_name( val ). + DATA(data_desc) = CAST cl_abap_datadescr( struct_desc ). + DATA(gr_dyntable_typ) = cl_abap_tabledescr=>create( data_desc ). + CREATE DATA result TYPE HANDLE gr_dyntable_typ. + + ENDMETHOD. + + METHOD rtti_get_t_attri_by_any. + + DATA lo_struct TYPE REF TO cl_abap_structdescr. + DATA lo_type TYPE REF TO cl_abap_typedescr. + + TRY. + lo_type = cl_abap_typedescr=>describe_by_data( val ). + IF lo_type->kind = cl_abap_typedescr=>kind_ref. + lo_type = cl_abap_typedescr=>describe_by_data_ref( val ). + ENDIF. + CATCH cx_root. + TRY. + lo_type = cl_abap_typedescr=>describe_by_data_ref( val ). + CATCH cx_root. + lo_type = cl_abap_structdescr=>describe_by_name( val ). + ENDTRY. + ENDTRY. + + CASE lo_type->kind. + WHEN cl_abap_typedescr=>kind_struct. + lo_struct = CAST #( lo_type ). + WHEN cl_abap_typedescr=>kind_table. + lo_struct = CAST #( CAST cl_abap_tabledescr( lo_type )->get_table_line_type( ) ). + WHEN OTHERS. + lo_struct ?= lo_type. + ENDCASE. + + DATA(comps) = lo_struct->get_components( ). + + LOOP AT comps REFERENCE INTO DATA(lr_comp). + + IF lr_comp->as_include = abap_false. + APPEND lr_comp->* TO result. + ELSE. + DATA(lt_attri) = rtti_get_t_attri_by_include( lr_comp->type ). + APPEND LINES OF lt_attri TO result. + ENDIF. + ENDLOOP. + + ENDMETHOD. + + METHOD rtti_get_t_attri_by_include. + + TRY. + + cl_abap_typedescr=>describe_by_name( EXPORTING p_name = type->absolute_name + RECEIVING p_descr_ref = DATA(type_desc) + EXCEPTIONS type_not_found = 1 ). + + CATCH cx_root INTO DATA(x). + RAISE EXCEPTION TYPE z2ui5_cx_util_error + EXPORTING + previous = x. + ENDTRY. + DATA(sdescr) = CAST cl_abap_structdescr( type_desc ). + DATA(comps) = sdescr->get_components( ). + + LOOP AT comps REFERENCE INTO DATA(lr_comp). + + IF lr_comp->as_include = abap_true. + + DATA(incl_comps) = rtti_get_t_attri_by_include( lr_comp->type ). + + LOOP AT incl_comps REFERENCE INTO DATA(lr_incl_comp). + APPEND lr_incl_comp->* TO result. + ENDLOOP. + + ELSE. + + APPEND lr_comp->* TO result. + + ENDIF. + + ENDLOOP. + + ENDMETHOD. + + METHOD rtti_check_ref_data. + + TRY. + DATA(lo_typdescr) = cl_abap_typedescr=>describe_by_data( val ). + DATA(lo_ref) = CAST cl_abap_refdescr( lo_typdescr ) ##NEEDED. + result = abap_true. + CATCH cx_root ##NO_HANDLER. + ENDTRY. + + ENDMETHOD. + + METHOD c_trim. + + result = shift_left( shift_right( CONV string( val ) ) ). + result = shift_right( val = result + sub = cv_char_util_horizontal_tab ). + result = shift_left( val = result + sub = cv_char_util_horizontal_tab ). + result = shift_left( shift_right( result ) ). + + ENDMETHOD. + + METHOD c_trim_upper. + + result = to_upper( c_trim( CONV string( val ) ) ). + + ENDMETHOD. + + METHOD xml_parse. + + IF xml IS INITIAL. + CLEAR any. + RETURN. + ENDIF. + + CALL TRANSFORMATION id + SOURCE XML xml + RESULT data = any. + + ENDMETHOD. + + METHOD xml_stringify. + + CALL TRANSFORMATION id + SOURCE data = any + RESULT XML result + OPTIONS data_refs = `heap-or-create`. + + ENDMETHOD. + +ENDCLASS. diff --git a/src/z2ui5_cl_tcl_context.clas.xml b/src/z2ui5_cl_tcl_context.clas.xml new file mode 100644 index 0000000..321d714 --- /dev/null +++ b/src/z2ui5_cl_tcl_context.clas.xml @@ -0,0 +1,16 @@ + + + + + + Z2UI5_CL_TCL_CONTEXT + E + Table Content Loader - vendored utility context + 1 + X + X + X + + + +