├── .gitattributes
├── .github
└── workflows
│ ├── codeql-analysis.yml
│ ├── linux.yml
│ ├── macos.yml
│ └── windows.yml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── docs
├── dochack.js
├── globals.html
├── httpRenderer.html
├── nimdoc.out.css
├── nimview_tmp.html
├── requestMap.html
├── sharedTypes.html
├── storage.html
├── theindex.html
└── webviewRenderer.html
├── examples
├── .gitignore
├── android
│ ├── .gitattributes
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── app
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── cpp
│ │ │ ├── CMakeLists.txt
│ │ │ ├── native-lib.cpp
│ │ │ └── nimbase.h
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── nimviewAndroid
│ │ │ │ ├── CppWrapper.kt
│ │ │ │ └── MainActivity.kt
│ │ │ ├── nim
│ │ │ ├── .gitignore
│ │ │ ├── App.nimble
│ │ │ ├── dist
│ │ │ │ ├── favicon.png
│ │ │ │ ├── global.css
│ │ │ │ └── index.html
│ │ │ ├── nakefile.nim
│ │ │ ├── package-lock.json
│ │ │ ├── package.json
│ │ │ ├── readme.md
│ │ │ ├── rollup.config.js
│ │ │ └── src
│ │ │ │ ├── App.nim
│ │ │ │ ├── App.svelte
│ │ │ │ ├── main.js
│ │ │ │ └── nim.cfg
│ │ │ └── res
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ │ ├── layout
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── c_cpp
│ ├── App.nimble
│ ├── App.sln
│ ├── App.vcxproj
│ ├── dist
│ │ ├── index.html
│ │ ├── nimview.iife.js
│ │ └── nimview.iife.js.map
│ ├── nakefile.nim
│ ├── readme.md
│ └── src
│ │ ├── c_sample.c
│ │ ├── cpp_sample.cpp
│ │ ├── library.nim
│ │ └── nim.cfg
├── minimal
│ ├── App.nim
│ ├── dist
│ │ ├── index.html
│ │ ├── nimview.iife.js
│ │ └── nimview.iife.js.map
│ └── nim.cfg
├── minimal2
│ ├── App.nim
│ ├── dist
│ │ ├── index.html
│ │ ├── nimview.iife.js
│ │ └── nimview.iife.js.map
│ └── nim.cfg
├── python
│ ├── MANIFEST.in
│ ├── README.md
│ ├── bdist_wheel.py
│ ├── nakefile.nim
│ ├── pySample.py
│ ├── setup.cfg
│ ├── setup.py
│ └── src
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── library.nim
│ │ ├── nim.cfg
│ │ └── pyTest.py
├── react
│ ├── .env
│ ├── .gitignore
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── robots.txt
│ └── src
│ │ ├── App.jsx
│ │ ├── App.nim
│ │ ├── components
│ │ ├── Navbar.jsx
│ │ └── Sample.jsx
│ │ ├── index.js
│ │ └── nim.cfg
├── svelte
│ ├── .gitignore
│ ├── dist
│ │ ├── favicon.png
│ │ ├── global.css
│ │ └── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── readme.md
│ ├── rollup.config.js
│ └── src
│ │ ├── App.nim
│ │ ├── App.svelte
│ │ ├── components
│ │ ├── Navbar.svelte
│ │ └── Sample.svelte
│ │ ├── main.js
│ │ └── nim.cfg
├── svelte_todo
│ ├── .gitignore
│ ├── dist
│ │ ├── favicon.png
│ │ ├── global.css
│ │ └── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── readme.md
│ ├── rollup.config.js
│ └── src
│ │ ├── App.nim
│ │ ├── App.svelte
│ │ ├── main.js
│ │ └── nim.cfg
└── vue
│ ├── README.md
│ ├── babel.config.js
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ └── index.html
│ ├── src
│ ├── App.nim
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ ├── Navbar.vue
│ │ └── Sample.vue
│ ├── main.js
│ └── nim.cfg
│ └── vue.config.js
├── nimview.nimble
├── src
├── js
│ ├── LICENSE
│ ├── README.md
│ ├── nimview.cjs.js
│ ├── nimview.cjs.js.map
│ ├── nimview.esm.js
│ ├── nimview.esm.js.map
│ ├── nimview.iife.js
│ ├── nimview.iife.js.map
│ ├── nimview.js
│ ├── package-lock.json
│ ├── package.json
│ └── rollup.config.js
├── nimview.hpp
├── nimview.nim
├── nimview.nim.cfg
└── nimview
│ ├── dispatchJsonRequest.nim
│ ├── globalToken.nim
│ ├── globals.nim
│ ├── httpRenderer.nim
│ ├── readme.md
│ ├── requestMap.nim
│ ├── sharedTypes.nim
│ ├── std
│ ├── readme.md
│ └── sysrand.nim
│ ├── storage.nim
│ ├── webview
│ ├── .gitattributes
│ ├── .gitignore
│ ├── docs
│ │ └── webview.html
│ ├── readme.md
│ ├── tests
│ │ ├── bindEx.nim
│ │ ├── config.nims
│ │ ├── minimal.nim
│ │ └── scopeTest.nim
│ ├── webview.nim
│ ├── webview.nimble
│ └── webview
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── webview.go
│ │ └── webview.h
│ └── webviewRenderer.nim
└── tests
├── __init__.py
├── c_test.c
├── desktopSample.nim
├── httpSample.nim
├── icon.ico
├── nim.cfg
├── pyTest.py
├── pyWebViewSample.py
├── requestsFail.nim
├── requestsSuccess.nim
└── test.dump
/.gitattributes:
--------------------------------------------------------------------------------
1 | docs/** linguist-documentation
2 | src/js/*map linguist-generated
3 | src/js/*.cjs.js linguist-generated
4 | src/js/*.iife.js linguist-generated
5 | src/js/*.esm.js linguist-generated
6 | src/nimview/std/** linguist-vendored
7 | src/nimview/webview/** linguist-vendored
8 | src/nimview/webview2/** linguist-vendored
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ main ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ main ]
20 | schedule:
21 | - cron: '34 13 * * 6'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 |
28 | strategy:
29 | fail-fast: false
30 | matrix:
31 | language: [ 'javascript', 'python' ]
32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
33 | # Learn more:
34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
35 |
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 |
40 | # Initializes the CodeQL tools for scanning.
41 | - name: Initialize CodeQL
42 | uses: github/codeql-action/init@v1
43 | with:
44 | languages: ${{ matrix.language }}
45 | # If you wish to specify custom queries, you can do so here or in a config file.
46 | # By default, queries listed here will override any specified in a config file.
47 | # Prefix the list here with "+" to use these queries and those in the config file.
48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
49 |
50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
51 | # If this step fails, then you should remove it and run the build manually (see below)
52 | # - name: Autobuild
53 | # uses: github/codeql-action/autobuild@v1
54 |
55 | # ℹ️ Command-line programs to run using the OS shell.
56 | # 📚 https://git.io/JvXDl
57 |
58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
59 | # and modify them (or add more) to build your code if your project
60 | # uses a compiled language
61 |
62 | #- run: |
63 | # make bootstrap
64 | # make release
65 |
66 | - name: Perform CodeQL Analysis
67 | uses: github/codeql-action/analyze@v1
68 |
--------------------------------------------------------------------------------
/.github/workflows/linux.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI linux
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [ main ]
10 | pull_request:
11 | branches: [ main ]
12 |
13 |
14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
15 | jobs:
16 | # This workflow contains a single job called "build"
17 | build:
18 | # The type of runner that the job will run on
19 | runs-on: ubuntu-latest
20 | # Steps represent a sequence of tasks that will be executed as part of the job
21 | steps:
22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
23 | - uses: actions/checkout@v2
24 | - uses: iffy/install-nim@v3.2.2
25 | - name: InstallLinuxDependencies
26 | if: runner.os == 'Linux'
27 | run: |
28 | sudo apt-get update && sudo apt install -y gcc npm libwebkit2gtk-4.0-dev curl python3
29 |
30 | - name: InstallMacOSDependencies
31 | if: runner.os == 'macOS'
32 | run: |
33 | brew install gcc python && pip install pathlib
34 | # Runs a set of commands using the runners shell
35 | - name: Test
36 | run: |
37 | nim --version
38 | nimble install -d -y --noSSLCheck --verbose
39 | nimble test -y
40 |
41 | - name: Release
42 | uses: softprops/action-gh-release@v1
43 | if: startsWith(github.ref, 'refs/tags/')
44 | with:
45 | files: |
46 | build/*.exe
47 | build/*.dll
48 | build/*.a
49 | build/*.pyd
50 | build/*.so
51 | env:
52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53 |
54 | # uses: actions/upload-artifact@v2
55 | # with:
56 | # name: binaries
57 | # retention-days: 5
58 | # path: |
59 |
--------------------------------------------------------------------------------
/.github/workflows/macos.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI MacOS
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [ main ]
10 | pull_request:
11 | branches: [ main ]
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 | # This workflow contains a single job called "build"
16 | build:
17 | # The type of runner that the job will run on
18 | runs-on: macOS-latest
19 | # Steps represent a sequence of tasks that will be executed as part of the job
20 | steps:
21 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
22 | - uses: actions/checkout@v2
23 | - uses: iffy/install-nim@v3.2.2
24 | - name: InstallLinuxDependencies
25 | if: runner.os == 'Linux'
26 | run: |
27 | sudo apt-get update && sudo apt install -y gcc npm libwebkit2gtk-4.0-dev curl python3
28 |
29 | - name: InstallMacOSDependencies
30 | if: runner.os == 'macOS'
31 | run: |
32 | brew install gcc python && pip install pathlib
33 | # Runs a set of commands using the runners shell
34 | - name: Test
35 | run: |
36 | nim --version
37 | nimble install -d -y --noSSLCheck --verbose
38 | nimble test -y
39 |
40 | - name: Release
41 | uses: softprops/action-gh-release@v1
42 | if: startsWith(github.ref, 'refs/tags/')
43 | with:
44 | files: |
45 | build/*.exe
46 | build/*.dll
47 | build/*.a
48 | build/*.pyd
49 | build/*.so
50 | env:
51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52 |
53 | # uses: actions/upload-artifact@v2
54 | # with:
55 | # name: binaries
56 | # retention-days: 5
57 | # path: |
58 |
--------------------------------------------------------------------------------
/.github/workflows/windows.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI Windows
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [ main ]
10 | pull_request:
11 | branches: [ main ]
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 | # This workflow contains a single job called "build"
16 | build:
17 | # The type of runner that the job will run on
18 | runs-on: windows-latest
19 | # Steps represent a sequence of tasks that will be executed as part of the job
20 | steps:
21 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
22 | - uses: actions/checkout@v2
23 | - uses: iffy/install-nim@v3.2.2
24 | - name: InstallLinuxDependencies
25 | if: runner.os == 'Linux'
26 | run: |
27 | sudo apt-get update && sudo apt install -y gcc npm libwebkit2gtk-4.0-dev curl python3
28 |
29 | - name: InstallMacOSDependencies
30 | if: runner.os == 'macOS'
31 | run: |
32 | brew install gcc python && pip install pathlib
33 | # Runs a set of commands using the runners shell
34 | - name: Test
35 | run: |
36 | nim --version
37 | nimble install -d -y --noSSLCheck --verbose
38 | nimble test -y
39 |
40 | - name: Release
41 | uses: softprops/action-gh-release@v1
42 | if: startsWith(github.ref, 'refs/tags/')
43 | with:
44 | files: |
45 | build/*.exe
46 | build/*.dll
47 | build/*.a
48 | build/*.pyd
49 | build/*.so
50 | env:
51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52 |
53 | # uses: actions/upload-artifact@v2
54 | # with:
55 | # name: binaries
56 | # retention-days: 5
57 | # path: |
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | **/dist
3 | **/node_modules
4 | tmp_c*
5 | **/x64/*
6 | debug.log
7 |
8 | nimcache/
9 | nimblecache/
10 | htmldocs/
11 |
12 | # local env files
13 | .env.local
14 | .env.*.local
15 |
16 | # Log files
17 | npm-debug.log*
18 | yarn-debug.log*
19 | yarn-error.log*
20 | pnpm-debug.log*
21 |
22 | # Editor directories and files
23 | .idea
24 | *.suo
25 | *.ntvs*
26 | *.njsproj
27 | *.sln
28 | *.sw?
29 | *.pdb
30 | *.ipch
31 | *.ipdb
32 | *.iobj
33 | *.ilk
34 | *.user
35 | *.VC.db
36 | *.bak
37 |
38 | # binaries
39 | *.o
40 | *.obj
41 | *.a
42 | *.dll
43 | *.lib
44 | *.so
45 | *.pyd
46 | *.pyc
47 |
48 | # Executables
49 | *.exe
50 | *.app
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["ms-vscode.cpptools", "damiankoper.gdb-debug", "kosz78.nim", "xaver.clang-format"]
3 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 |
8 | {
9 | "name": "(gdb) Anfügen",
10 | "type": "cppdbg",
11 | "request": "attach",
12 | "program": "${workspaceFolder}/out/nimview.pyd",
13 | "processId": "${command:pickProcess}",
14 | "MIMode": "gdb",
15 | // "miDebuggerPath": "/path/to/gdb",
16 | "setupCommands": [
17 | {
18 | "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren",
19 | "text": "-enable-pretty-printing",
20 | "ignoreFailures": true
21 | }
22 | ]
23 | },
24 | {
25 | "name": "nim debug (gdb) ",
26 | "type": "cppdbg",
27 | "request": "launch",
28 | "program": "${workspaceFolder}/nimview_debug.exe",
29 | "args": ["dir"],
30 | "stopAtEntry": false,
31 | "cwd": "${workspaceFolder}",
32 | "environment": [],
33 | "externalConsole": false,
34 | "MIMode": "gdb",
35 | "includePath": ["src/tmp_c"],
36 | // "miDebuggerPath": "C:/nim-1.2.6/dist/mingw64/bin/gdb.exe",
37 | "setupCommands": [
38 | {
39 | "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren",
40 | "text": "-enable-pretty-printing",
41 | "ignoreFailures": true
42 | }
43 | ],
44 | "preLaunchTask": "nimble debug"
45 | }
46 |
47 |
48 | ]
49 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "iostream": "c",
4 | "xlocale": "c",
5 | "xstring": "cpp",
6 | "variant": "cpp",
7 | "nimview.h": "c",
8 | "functional": "cpp",
9 | "atomic": "cpp",
10 | "bit": "cpp",
11 | "cctype": "cpp",
12 | "clocale": "cpp",
13 | "cmath": "cpp",
14 | "compare": "cpp",
15 | "concepts": "cpp",
16 | "cstddef": "cpp",
17 | "cstdint": "cpp",
18 | "cstdio": "cpp",
19 | "cstdlib": "cpp",
20 | "cstring": "cpp",
21 | "ctime": "cpp",
22 | "cwchar": "cpp",
23 | "exception": "cpp",
24 | "initializer_list": "cpp",
25 | "ios": "cpp",
26 | "iosfwd": "cpp",
27 | "istream": "cpp",
28 | "iterator": "cpp",
29 | "limits": "cpp",
30 | "list": "cpp",
31 | "memory": "cpp",
32 | "new": "cpp",
33 | "ostream": "cpp",
34 | "stdexcept": "cpp",
35 | "streambuf": "cpp",
36 | "string": "cpp",
37 | "system_error": "cpp",
38 | "tuple": "cpp",
39 | "type_traits": "cpp",
40 | "typeinfo": "cpp",
41 | "unordered_map": "cpp",
42 | "utility": "cpp",
43 | "vector": "cpp",
44 | "xfacet": "cpp",
45 | "xhash": "cpp",
46 | "xiosbase": "cpp",
47 | "xlocinfo": "cpp",
48 | "xlocnum": "cpp",
49 | "xmemory": "cpp",
50 | "xstddef": "cpp",
51 | "xtr1common": "cpp",
52 | "xutility": "cpp",
53 | "map": "cpp",
54 | "xtree": "cpp",
55 | "sstream": "cpp",
56 | "stdio.h": "c",
57 | "*.idl": "cpp"
58 | }
59 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "2.0.0",
6 | "tasks": [
7 | {
8 | "label": "nimble debug",
9 | "command": "nimble debug --threads:on --debugger:native",
10 | "options": {
11 | "cwd": "${workspaceRoot}"
12 | },
13 | "type": "shell",
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 marcomq
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/dochack.js:
--------------------------------------------------------------------------------
1 |
2 | function main() {
3 | var pragmaDots = document.getElementsByClassName("pragmadots");
4 | for (var i = 0; i < pragmaDots.length; i++) {
5 | pragmaDots[i].onclick = function(event) {
6 | // Hide tease
7 | event.target.parentNode.style.display = "none";
8 | // Show actual
9 | event.target.parentNode.nextElementSibling.style.display = "inline";
10 | }
11 | }
12 |
13 | const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
14 | function switchTheme(e) {
15 | if (e.target.checked) {
16 | document.documentElement.setAttribute('data-theme', 'dark');
17 | localStorage.setItem('theme', 'dark');
18 | } else {
19 | document.documentElement.setAttribute('data-theme', 'light');
20 | localStorage.setItem('theme', 'light');
21 | }
22 | }
23 |
24 | toggleSwitch.addEventListener('change', switchTheme, false);
25 |
26 | const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
27 | if (currentTheme) {
28 | document.documentElement.setAttribute('data-theme', currentTheme);
29 |
30 | if (currentTheme === 'dark') {
31 | toggleSwitch.checked = true;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/docs/sharedTypes.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | src/nimview/sharedTypes
21 |
22 |
23 |
24 |
25 |
67 |
68 |
69 |
70 |
71 |
72 |
src/nimview/sharedTypes
73 |
74 |
75 |
76 |
80 |
Dark Mode
81 |
82 |
83 |
84 | -
85 | Index
86 |
87 |
88 |
89 |
90 | Search:
92 |
93 |
94 | Group by:
95 |
99 |
100 |
101 | -
102 | Types
103 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
133 |
141 |
142 |
ServerException = object of CatchableError
143 |
-
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | Made with Nim. Generated: 2021-10-30 10:42:55 UTC
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/storage.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | src/nimview/storage
21 |
22 |
23 |
24 |
25 |
67 |
68 |
69 |
70 |
71 |
72 |
src/nimview/storage
73 |
74 |
75 |
76 |
80 |
Dark Mode
81 |
82 |
83 |
84 | -
85 | Index
86 |
87 |
88 |
89 |
90 | Search:
92 |
93 |
94 | Group by:
95 |
99 |
100 |
101 | -
102 | Procs
103 |
104 |
109 |
114 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
Implements a simple key / value store that can be used to store preferences
131 |
132 |
133 |
134 |
135 |
proc getStoredVal(key: string): string {....raises: [], tags: [].}
136 |
-
137 |
138 |
139 |
140 |
141 |
142 |
143 |
proc initStorage(fileName: string = "") {....raises: [],
144 | tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect].}
145 |
-
146 |
147 |
148 |
149 |
150 |
151 |
152 |
proc setStoredVal(key, value: string): string {....raises: [],
153 | tags: [WriteIOEffect].}
154 |
-
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | Made with Nim. Generated: 2021-10-30 10:42:55 UTC
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /public/build/
3 | /public/vendor/
4 |
5 | .DS_Store
6 | storage.json
--------------------------------------------------------------------------------
/examples/android/.gitattributes:
--------------------------------------------------------------------------------
1 | app/src/nimview/* linguist-vendored=true
--------------------------------------------------------------------------------
/examples/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /app/.cxx
13 | /captures
14 | .externalNativeBuild
15 | .cxx*
16 | .cxx
17 | *.exe
18 | app/src/main/cpp/x86*
19 | app/src/main/cpp/x86_64*
20 | app/src/main/cpp/armeabi-v7a*
21 | app/src/main/cpp/arm64-v8a*
22 | app/src/main/node_modules*
23 | */build*
24 | app/src/main/assets/*
--------------------------------------------------------------------------------
/examples/android/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 marcomq
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/android/README.md:
--------------------------------------------------------------------------------
1 | # nimview_android
2 | A Nim/Webview based helper to create Android applications with Nim/C/C++ and HTML/CSS
3 |
4 | Android Studio implementation of [Nimview](https://github.com/marcomq/nimview)
5 |
6 | This project uses Android Webview as UI layer. The back-end is supposed to be written in Nim, C/C++
7 | or - if it doesn't need to be ported to other platforms - Kotlin or Java.
8 | As Android Webview doesn't has as much debugging capabilities as Chrome or Firefox, it would be recommended to write most of the UI in a web application
9 | with nimview in debug mode + npm autoreload first and then test these changes on Android later.
10 |
11 | The Nimview folder is in android/app/src/main/nim
12 |
13 | The recommended workflow would be:
14 | ```
15 | (installation)
16 | npx degit marcomq/nimview/examples/android myAndroid
17 | cd app/src/main/nim
18 | nimble install -d -y
19 | npm install
20 |
21 |
22 | (development)
23 | (open two terminals/shells, t1 and t2)
24 | t1: nim cpp -r -d:useServer src/App.nim
25 | t2: npm run dev
26 | open browser at http://localhost:5000
27 | (optional) modify nim / html / js code in VSCode
28 | restart nim server to apply changes on nim code
29 | press F5 if browser doesn't refresh automatically after js changes
30 |
31 | (release and testing)
32 | compile project with android studio, test, perform changes if required
33 |
34 | ```
--------------------------------------------------------------------------------
/examples/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 | android {
6 | compileSdkVersion 29
7 |
8 | defaultConfig {
9 | applicationId "com.nimviewAndroid"
10 | minSdkVersion 21
11 | targetSdkVersion 29
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | externalNativeBuild {
17 | cmake {
18 | cppFlags "-std=c++17"
19 | }
20 | }
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 |
29 | debug {
30 | applicationIdSuffix ".debug"
31 | debuggable true
32 | }
33 | }
34 | externalNativeBuild {
35 | cmake {
36 | path "src/main/cpp/CMakeLists.txt"
37 | version "3.10.2"
38 | }
39 | }
40 | ndkVersion '21.0.6113669'
41 |
42 | sourceSets {
43 | main {
44 | assets.srcDirs = ['src/main/nim/dist']
45 | }
46 | }
47 | }
48 |
49 | dependencies {
50 | implementation fileTree(dir: "libs", include: ["*.jar"])
51 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
52 | implementation 'androidx.core:core-ktx:1.3.1'
53 | implementation 'androidx.appcompat:appcompat:1.2.0'
54 | implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
55 | testImplementation 'junit:junit:4.12'
56 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
57 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
58 | }
59 |
--------------------------------------------------------------------------------
/examples/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 | -keepattributes SetJavaScriptEnabled
15 | -keepattributes JavascriptInterface
16 | -keepclassmembers class **.*$NativeCpp {
17 | *;
18 | }
19 |
20 | -keepclassmembers class com.nimviewAndroid.CppWrapper {
21 | public *;
22 | }
23 |
24 | # Uncomment this to preserve the line number information for
25 | # debugging stack traces.
26 | #-keepattributes SourceFile,LineNumberTable
27 |
28 | # If you keep the line number information, uncomment this to
29 | # hide the original source file name.
30 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/examples/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # For more information about using CMake with Android Studio, read the
2 | # documentation: https://d.android.com/studio/projects/add-native-code.html
3 |
4 | # Sets the minimum version of CMake required to build the native library.
5 |
6 | cmake_minimum_required(VERSION 3.5)
7 |
8 | include_directories(. ${ANDROID_ABI} )
9 |
10 | add_custom_target (nimToCAndJs ALL
11 | COMMAND nake
12 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../nim/)
13 |
14 | add_definitions(-DNIMVIEW_CUSTOM_LIB -DJUST_CORE -funsigned-char)
15 |
16 | aux_source_directory(${ANDROID_ABI} ALL_NIM_C_FILES)
17 |
18 | # Creates and names a library, sets it as either STATIC
19 | # or SHARED, and provides the relative paths to its source code.
20 | # You can define multiple libraries, and CMake builds them for you.
21 | # Gradle automatically packages shared libraries with your APK.
22 | add_library( # Sets the name of the library.
23 | native-lib
24 | # Sets the library as a shared library.
25 | SHARED
26 | # Provides a relative path to your source file(s).
27 | native-lib.cpp ${ALL_NIM_C_FILES})
28 |
29 | add_dependencies(native-lib nimToCAndJs)
30 |
31 | find_library( # Sets the name of the path variable.
32 | log-lib
33 | # Specifies the name of the NDK library that
34 | # you want CMake to locate.
35 | log )
36 |
37 | # Specifies libraries CMake should link to your target library. You
38 | # can link multiple libraries, such as libraries you define in this
39 | # build script, prebuilt third-party libraries, or system libraries.
40 |
41 | target_link_libraries( # Specifies the target library.
42 | native-lib
43 | # Links the target library to the log library
44 | # included in the NDK.
45 | ${log-lib} )
--------------------------------------------------------------------------------
/examples/android/app/src/main/cpp/native-lib.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "App.h"
5 | #include "nimview.hpp"
6 | #include
7 |
8 | jint myJniVersion;
9 | JavaVM* myJvm = NULL;
10 | jobject* myCppWrapper = NULL;
11 | jmethodID myEvaljsFunc;
12 |
13 | void webviewEvalJs(char* js) {
14 | // this doesn't seem to call javascript for some reason and crashes on 2nd call
15 | JNIEnv* env = NULL;
16 | jint rs = myJvm->GetEnv((void **)&env, myJniVersion);
17 | assert (rs == JNI_OK);
18 | jstring jstr = env->NewStringUTF(js);
19 | env->CallVoidMethod(*myCppWrapper, myEvaljsFunc, jstr);
20 | env->DeleteLocalRef(jstr);
21 | };
22 |
23 | #define THIS_PROJECT_PREFIX Java_com_nimviewAndroid
24 | extern "C" JNIEXPORT jstring JNICALL
25 | Java_com_nimviewAndroid_CppWrapper_callNim(
26 | JNIEnv* env,
27 | jobject self,
28 | jstring request, jstring value) {
29 | myCppWrapper = &self;
30 | const char* cRequest = env->GetStringUTFChars(request, nullptr);
31 | const char* cValue = env->GetStringUTFChars(value, nullptr);
32 | std::string result;
33 | try {
34 | result = nimview::dispatchRequest(std::string(cRequest), std::string(cValue));
35 | }
36 | catch(...) {
37 | __android_log_write(ANDROID_LOG_ERROR, "Nimview", ("Exception during request " + std::string(cRequest)).c_str());
38 | }
39 | env->ReleaseStringUTFChars(request, cRequest);
40 | env->ReleaseStringUTFChars(value, cValue);
41 | return env->NewStringUTF(result.c_str());
42 | }
43 |
44 | extern "C" JNIEXPORT void JNICALL
45 | Java_com_nimviewAndroid_CppWrapper_initCallFrontentJs(JNIEnv* env, jobject self) {
46 | nimview::setCustomJsEval(webviewEvalJs);
47 | myCppWrapper = &self;
48 | myJniVersion = env->GetVersion();
49 | jclass javaClass = env->FindClass("com/nimviewAndroid/CppWrapper");
50 | myEvaljsFunc = env->GetMethodID(javaClass, "evaluateJavascript",
51 | "(Ljava/lang/String;)V");
52 | jint rs = env->GetJavaVM(&myJvm);
53 | assert (rs == JNI_OK);
54 | }
55 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/java/com/nimviewAndroid/CppWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.nimviewAndroid
2 | import android.webkit.WebView
3 | import androidx.appcompat.app.AppCompatActivity
4 | import java.util.concurrent.Executors
5 | import org.json.JSONObject
6 |
7 | public class CppWrapper {
8 | private
9 | var myWebview: WebView
10 | var myMainActivity: AppCompatActivity
11 | val myNimThread = Executors.newFixedThreadPool(1) // always use the same thread for nim
12 | constructor(appView: WebView, mainActivity: AppCompatActivity) {
13 | this.myWebview = appView
14 | this.myMainActivity = mainActivity
15 | this.myNimThread.execute({
16 | this.initCallFrontentJs()
17 | })
18 | }
19 | /**
20 | * A native method that is implemented by the 'native-lib' native library,
21 | * which is packaged with this application.
22 | */
23 | @SuppressWarnings("unused")
24 | external fun callNim(request: String, value: String): String
25 |
26 | external fun initCallFrontentJs()
27 |
28 | @SuppressWarnings("unused")
29 | fun evaluateJavascript(command: String) {
30 | this.myMainActivity.runOnUiThread(Runnable {
31 | this.myWebview.evaluateJavascript(command, null)
32 | })
33 | }
34 |
35 | @SuppressWarnings("unused")
36 | @android.webkit.JavascriptInterface
37 | fun call(command: String) {
38 | try {
39 | val jsonMessage = JSONObject(command)
40 | val request = jsonMessage.getString("request")
41 | var data = jsonMessage.getString("data")
42 | var requestId = jsonMessage.getInt("requestId")
43 | this.myNimThread.execute({
44 | var result = this.callNim(request, data)
45 | this.evaluateJavascript("window.ui.applyResponse(" + requestId.toString() + ",'"
46 | + result.replace("\\", "\\\\").replace("\'", "\\'")
47 | + "');")
48 | })
49 | }
50 | catch (e: Exception) {
51 | println(e.toString())
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/java/com/nimviewAndroid/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nimviewAndroid
2 |
3 | import android.os.Bundle
4 | import android.view.Window
5 | import android.webkit.JsResult
6 | import android.webkit.WebChromeClient
7 | import android.webkit.WebView
8 | import androidx.appcompat.app.AppCompatActivity
9 |
10 |
11 | class MainActivity : AppCompatActivity() {
12 |
13 | private lateinit var webView: WebView
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | this.requestWindowFeature(Window.FEATURE_NO_TITLE)
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_main)
18 | this.getSupportActionBar()?.hide()
19 |
20 | webView = findViewById(R.id.webview)
21 | val settings = webView.getSettings()
22 | settings.setJavaScriptEnabled(true)
23 | settings.setDomStorageEnabled(true)
24 | settings.setAppCacheEnabled(true)
25 | var cppWrapper = CppWrapper(webView, this)
26 | webView.addJavascriptInterface(cppWrapper, "nimview")
27 | webView.webChromeClient = object : WebChromeClient() {
28 | // WebChromeClient needs workaround for "alert"
29 | override fun onJsAlert(
30 | view: WebView,
31 | url: String,
32 | message: String,
33 | result: JsResult
34 | ): Boolean {
35 | return super.onJsAlert(view, url, message, result)
36 | }
37 | }
38 | webView.loadUrl("file:///android_asset/index.html");
39 |
40 | }
41 |
42 | companion object {
43 | // Used to load the 'native-lib' library on application startup.
44 | init {
45 | System.loadLibrary("native-lib")
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /public/build/
3 | /public/vendor/
4 | /dist/
5 |
6 | .DS_Store
7 | storage.json
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/App.nimble:
--------------------------------------------------------------------------------
1 | version = "0.2.0"
2 | author = "Marco Mengelkoch"
3 | description = "Nim / C library to run webview with HTML/JS as UI"
4 | license = "MIT"
5 | srcDir = "src"
6 |
7 | # Dependencies
8 | # you may skip jester, nimpy and webview when compiling with nim c -d:just_core
9 | # alternatively, you still can just skip webkit by compiling with -d:useServer
10 |
11 | # Currently, Webview requires gcc and doesn't work with vcc or clang
12 |
13 | requires "nimview >= 0.3.0", "nake >= 1.9.0"
14 |
15 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/dist/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/nim/dist/favicon.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/dist/global.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/nim/dist/global.css
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Todo app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/nakefile.nim:
--------------------------------------------------------------------------------
1 | import nake
2 | import os, strutils, system, osproc
3 |
4 | const application = "App"
5 | const uiDir = "src"
6 | const mainApp = "src" / application & ".nim"
7 | const libraryFile = mainApp
8 |
9 |
10 | let thisDir = system.currentSourcePath().parentDir()
11 | let nimbleDir = parentDir(parentDir(os.findExe("nimble")))
12 | var nimbaseDir = parentDir(nimbleDir) & "/lib"
13 | if (not os.fileExists(nimbaseDir & "/nimbase.h")):
14 | nimbaseDir = parentDir(parentDir(os.findExe("makelink"))) & "/lib"
15 | if (not os.fileExists(nimbaseDir & "/nimbase.h")):
16 | nimbaseDir = parentDir(parentDir(parentDir(parentDir(os.findExe("gcc"))))) & "/lib"
17 | if (not os.fileExists(nimbaseDir & "/nimbase.h")):
18 | nimbaseDir = parentDir(nimbleDir) & "/.choosenim/toolchains/nim-" & system.NimVersion & "/lib"
19 |
20 | var nimviewPath = thisDir.parentDir().parentDir().parentDir().parentDir().parentDir().parentDir() / "src" # only used for nimview.hpp
21 | if not os.dirExists(nimviewPath):
22 | var nimviewPathTmp = $ osproc.execProcess "nimble path nimview"
23 | nimviewPathTmp = nimviewPathTmp.replace("\n", "").replace("\\", "/").replace("//", "/")
24 | if (nimviewPathTmp != "" and os.dirExists(nimviewPathTmp)):
25 | nimviewPath = nimviewPathTmp
26 |
27 | proc execShCmd(command: string) =
28 | echo "running: " & command
29 | doAssert 0 == os.execShellCmd(command)
30 |
31 | proc buildCForArch(cpu, path: string) =
32 | let cppPath = "../cpp" / path
33 | let headerFile = cppPath / application & ".h"
34 | if (headerfile.needsRefresh(mainApp)):
35 | os.removeDir(cppPath)
36 | var stdOptions = "--header:" & application & ".h --app:staticlib -d:just_core -d:noSignalHandler -d:release -d:androidNDK -d:noMain --os:android --threads:on --debuginfo:on " # TODO: turn off debug infos
37 | execShCmd(nimexe & " cpp -c " & stdOptions & "--cpu:" & cpu & " --nimcache:" & cppPath & " " & mainApp)
38 |
39 | proc buildC() =
40 | ## creates python and C/C++ libraries
41 | buildCForArch("arm64", "arm64-v8a")
42 | buildCForArch("arm", "armeabi-v7a")
43 | buildCForArch("i386", "x86")
44 | buildCForArch("amd64", "x86_64")
45 |
46 | proc buildJs() =
47 | var src: seq[string] = @[]
48 | for path in walkDirRec(uiDir):
49 | if path.endsWith("js") or path.endsWith("svelte") or path.endsWith("jsx") or path.endsWith("vue"):
50 | src.add(path)
51 | if ((thisDir / "dist/build/bundle.js").needsRefresh(src)):
52 | execShCmd("npm install")
53 | execShCmd("npm run build")
54 |
55 | task "serve", "Serve NPM":
56 | doAssert 0 == os.execShellCmd("npm run serve")
57 |
58 | task "clean", "cleanup files":
59 | os.removeFile(thisDir / "dist/build/bundle.js")
60 | os.removeDir("../assets")
61 | os.removeDir("../cpp/arm64-v8a")
62 | os.removeDir("../cpp/armeabi-v7a")
63 | os.removeDir("../cpp/x86")
64 | os.removeDir("../cpp/x86_64")
65 |
66 | task defaultTask, "Compiles to C":
67 | os.copyFile(nimbaseDir / "nimbase.h", thisDir / "../cpp" / "nimbase.h")
68 | os.copyFile(nimviewPath / "nimview.hpp", thisDir / "../cpp" / "nimview.hpp")
69 | buildJs()
70 | buildC()
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-todo",
3 | "version": "1.0.1",
4 | "description": "Sample application for Nimview",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/marcomq/nimview.git"
9 | },
10 | "scripts": {
11 | "build": "rollup -c",
12 | "devbuild": "rollup -c",
13 | "dev": "rollup -c -w",
14 | "dev-ie": "(set USE_BABEL=1 || export USE_BABEL=1) && rollup -c -w",
15 | "start": "sirv public --no-clear"
16 | },
17 | "devDependencies": {
18 | "@babel/core": "^7.15.5",
19 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
20 | "@babel/plugin-transform-runtime": "^7.15.0",
21 | "@babel/preset-env": "^7.15.4",
22 | "@babel/runtime": "^7.15.4",
23 | "@rollup/plugin-babel": "^5.3.0",
24 | "@rollup/plugin-commonjs": "^20.0.0",
25 | "@rollup/plugin-node-resolve": "^13.0.4",
26 | "@tauri-apps/tauri-inliner": "^1.13.2",
27 | "rollup": "^2.56.3",
28 | "rollup-plugin-css-only": "^3.1.0",
29 | "rollup-plugin-livereload": "^2.0.5",
30 | "rollup-plugin-svelte": "^7.1.0",
31 | "rollup-plugin-terser": "^7.0.2",
32 | "sirv-cli": "^1.0.14",
33 | "svelte": "^3.42.4"
34 | },
35 | "dependencies": {
36 | "bootstrap": "^4.6.0",
37 | "core-js": "^3.17.2",
38 | "jquery": "^3.6.0",
39 | "nimview": "^1.1.3"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/readme.md:
--------------------------------------------------------------------------------
1 | # nimview Android Svelte Todo-list Application
2 |
3 | This is the source code for the demo app on the Nimview page.
4 | To compile your code, you need nake
5 | - npm install
6 | - npm run build
7 | - nimble install nake
8 | - nake
9 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte'
2 | import resolve from '@rollup/plugin-node-resolve'
3 | import commonjs from '@rollup/plugin-commonjs'
4 | import { babel } from '@rollup/plugin-babel'
5 | import livereload from 'rollup-plugin-livereload'
6 | import { terser } from 'rollup-plugin-terser'
7 | import css from 'rollup-plugin-css-only'
8 |
9 |
10 | const production = !process.env.ROLLUP_WATCH
11 | const useBabel = production || process.env.USE_BABEL
12 |
13 | export default {
14 | input: 'src/main.js',
15 | output: {
16 | sourcemap: true,
17 | format: 'iife',
18 | name: 'app',
19 | file: 'dist/build/bundle.js'
20 | },
21 | plugins: [
22 | svelte({
23 | compilerOptions: {
24 | // enable run-time checks when not in production
25 | dev: !production
26 | }
27 | }),
28 | css({ output: 'bundle.css' }),
29 | // If you have external dependencies installed from
30 | // npm, you'll most likely need these plugins. In
31 | // some cases you'll need additional configuration
32 | // consult the documentation for details:
33 | // https://github.com/rollup/rollup-plugin-commonjs
34 | resolve({
35 | browser: true,
36 | dedupe: ['svelte']
37 | }),
38 | commonjs(),
39 |
40 | // Watch the `dist` directory and refresh the
41 | // browser on changes when not in production
42 | !production && livereload('dist'),
43 | // added by angelo
44 | // compile to good old IE11 compatible ES5
45 | useBabel && babel({
46 | extensions: [ '.js', '.mjs', '.html', '.svelte' ],
47 | babelHelpers: 'runtime',
48 | exclude: [ 'node_modules/@babel/**', 'node_modules/core-js/**' ],
49 | presets: [
50 | [
51 | '@babel/preset-env',
52 | {
53 | targets: {
54 | ie: '11'
55 | },
56 | useBuiltIns: 'usage',
57 | corejs: 3
58 | }
59 | ]
60 | ],
61 | plugins: [
62 | '@babel/plugin-syntax-dynamic-import',
63 | [
64 | '@babel/plugin-transform-runtime',
65 | {
66 | useESModules: true
67 | }
68 | ]
69 | ]
70 | }),
71 |
72 | // If we're building for production (npm run build
73 | // instead of npm run dev), minify
74 | production && terser()
75 | ],
76 | watch: {
77 | clearScreen: false
78 | }
79 | }
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/src/App.nim:
--------------------------------------------------------------------------------
1 | import nimview, os
2 |
3 | var storageFile = "storage.json"
4 | var sdCard = os.getenv("EXTERNAL_STORAGE", "/sdcard")
5 |
6 | enableStorage(sdCard / storageFile) # adds getStoredVal and setStoredVal
7 |
8 | proc countDown() =
9 | callFrontendJs("alert", "waiting 6 seconds")
10 | sleep(2000)
11 | callFrontendJs("alert", "4")
12 | sleep(3000)
13 | callFrontendJs("alert", "1")
14 | sleep(1000)
15 |
16 | add("countDown", countDown)
17 |
18 | when not defined(just_core):
19 | start()
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/src/App.svelte:
--------------------------------------------------------------------------------
1 |
48 |
49 |
54 |
55 |
56 |
57 |
65 |
66 | {#if items.length > 0}
67 |
82 |
96 | {/if}
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte'
2 | import 'jquery/dist/jquery.js'
3 | import 'bootstrap/dist/js/bootstrap.bundle.js'
4 | import 'bootstrap/dist/css/bootstrap.css'
5 |
6 | var app
7 | document.addEventListener("DOMContentLoaded", function() {
8 | app = new App({
9 | target: document.body,
10 | })
11 | })
12 |
13 | export default app
--------------------------------------------------------------------------------
/examples/android/app/src/main/nim/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../../../../../src/"
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
17 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #000000
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Nimview
3 |
--------------------------------------------------------------------------------
/examples/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = "1.4.10"
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.0.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
--------------------------------------------------------------------------------
/examples/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/examples/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Sep 13 14:49:58 CEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/examples/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "nimviewAndroid"
--------------------------------------------------------------------------------
/examples/c_cpp/App.nimble:
--------------------------------------------------------------------------------
1 | version = "0.2.0"
2 | author = "Marco Mengelkoch"
3 | description = "Nim / Python / C library to run webview with HTML/JS as UI"
4 | license = "MIT"
5 | bin = @["App"]
6 | srcDir = "src"
7 |
8 | import os, strutils
9 | # Dependencies
10 |
11 | requires "nimview >= 0.2.0", "nake >= 1.9.0"
12 |
13 | task test, "Run tests":
14 | let nake = system.findExe("nake")
15 | exec nake & " test"
--------------------------------------------------------------------------------
/examples/c_cpp/App.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31205.134
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "App", "App.vcxproj", "{2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | DebuggableRelease|x64 = DebuggableRelease|x64
12 | Release|x64 = Release|x64
13 | EndGlobalSection
14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
15 | {2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}.Debug|x64.ActiveCfg = Debug|x64
16 | {2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}.Debug|x64.Build.0 = Debug|x64
17 | {2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}.DebuggableRelease|x64.ActiveCfg = DebuggableRelease|x64
18 | {2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}.DebuggableRelease|x64.Build.0 = DebuggableRelease|x64
19 | {2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}.Release|x64.ActiveCfg = Release|x64
20 | {2BC9AA2C-3B77-4AC5-B2F8-6CA4C3A2F576}.Release|x64.Build.0 = Release|x64
21 | EndGlobalSection
22 | GlobalSection(SolutionProperties) = preSolution
23 | HideSolutionNode = FALSE
24 | EndGlobalSection
25 | GlobalSection(ExtensibilityGlobals) = postSolution
26 | SolutionGuid = {2D94EFB1-0CE9-4595-8DDA-400A55396AE9}
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/examples/c_cpp/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Minimal Example
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/c_cpp/nakefile.nim:
--------------------------------------------------------------------------------
1 | import nake
2 | import os, strutils, system, osproc
3 |
4 | let library = "nimview"
5 | let headerFile = library & ".h"
6 | let srcDir = "src"
7 | let mainApp = srcDir / "library.nim"
8 | var srcFiles = @[mainApp]
9 | let buildDir = "out"
10 | let thisDir = system.currentSourcePath().parentDir()
11 | let cDllExtension = when defined(windows): "dll" else: "so"
12 |
13 | os.createDir buildDir
14 |
15 | const webviewIncludes = when defined(windows):
16 | "-DWEBVIEW_WINAPI=1 -mno-ms-bitfields -DWIN32_LEAN_AND_MEAN "
17 | elif defined(macosx):
18 | "-DWEBVIEW_COCOA=1 -x objective-c"
19 | else:
20 | "-DWEBVIEW_GTK=1 " & staticExec("pkg-config --cflags gtk+-3.0 webkit2gtk-4.0")
21 |
22 | const webviewlLibs = when defined(windows):
23 | "-lole32 -lcomctl32 -loleaut32 -luuid -lgdi32"
24 | elif defined(macosx):
25 | "-framework Cocoa -framework WebKit"
26 | else:
27 | system.staticExec("pkg-config --libs gtk+-3.0 webkit2gtk-4.0") & " -ldl -pthread"
28 |
29 | proc execShCmd(command: string) =
30 | echo "running: " & command
31 | doAssert 0 == os.execShellCmd(command)
32 |
33 | var nimbleDir = parentDir(parentDir(os.findExe("nimble")))
34 | var nimbaseDir = parentDir(nimbleDir) & "/lib"
35 | if (not os.fileExists(nimbaseDir & "/nimbase.h")):
36 | nimbaseDir = parentDir(parentDir(os.findExe("makelink"))) & "/lib"
37 | if (not os.fileExists(nimbaseDir & "/nimbase.h")):
38 | nimbaseDir = parentDir(parentDir(parentDir(parentDir(os.findExe("gcc"))))) & "/lib"
39 | if (not os.fileExists(nimbaseDir & "/nimbase.h")):
40 | nimbaseDir = parentDir(nimbleDir) & "/.choosenim/toolchains/nim-" & system.NimVersion & "/lib"
41 | var nimviewPath = thisDir / "../../src/"
42 | if not os.dirExists(nimviewPath):
43 | var nimviewPathTmp = $ osproc.execProcess "nimble path nimview"
44 | nimviewPathTmp = nimviewPathTmp.replace("\n", "").replace("\\", "/").replace("//", "/")
45 | if (nimviewPathTmp != "" and os.dirExists(nimviewPathTmp)):
46 | nimviewPath = nimviewPathTmp
47 |
48 | if os.fileExists("dist/inlined.html"):
49 | srcFiles.add("dist/inlined.html")
50 |
51 | proc execNim(command: string) =
52 | echo "running: nim " & command
53 | execShCmd nimexe & " " & command
54 |
55 | proc buildGenericObjects() =
56 | os.removeDir(buildDir / "tmp_o")
57 | os.createDir(buildDir / "tmp_o")
58 | let headerFilePath = thisDir / buildDir / "tmp_c" / headerFile
59 | if headerFilePath.needsRefresh(srcFiles):
60 | os.removeDir(buildDir / "tmp_c")
61 | execNim "c -d:release --noMain:on -d:noMain --noLinking --header: " & headerFilePath & " --nimcache=./" & buildDir &
62 | "/tmp_c --app:staticLib --out:" & buildDir / library & " " & " " & mainApp
63 | os.copyFile(nimviewPath / "nimview.hpp", thisDir / buildDir / "tmp_c/nimview.hpp")
64 |
65 | proc buildCSample() =
66 | execShCmd "gcc -c -w -o " & buildDir & "/tmp_o/c_sample.o -fmax-errors=3 -DWEBVIEW_STATIC -DWEBVIEW_IMPLEMENTATION -O3 -fno-strict-aliasing -fno-ident " &
67 | webviewIncludes & " -I" & nimbaseDir & " -I" & nimbleDir & "/pkgs/webview-0.1.0/webview -I. -I" & buildDir & "/tmp_c src/c_sample.c"
68 | execShCmd "gcc -w -o " & buildDir & "/c_sample.exe " & buildDir & "/tmp_c/*.o " & buildDir & "/tmp_o/c_sample.o " & webviewlLibs
69 |
70 | proc buildCppSample() =
71 | execShCmd "g++ -c -w -std=c++17 -o " & buildDir & "/tmp_o/cpp_sample.o -fmax-errors=3 -DWEBVIEW_STATIC -DWEBVIEW_IMPLEMENTATION -O3 -fno-strict-aliasing -fno-ident " &
72 | webviewIncludes & " -I" & nimbaseDir & " -I" & nimbleDir & "/pkgs/webview-0.1.0/webview -I. -I" & buildDir & "/tmp_c src/cpp_sample.cpp"
73 | execShCmd "g++ -w -o " & buildDir & "/cpp_sample.exe " & buildDir & "/tmp_c/*.o " & buildDir & "/tmp_o/cpp_sample.o " & webviewlLibs
74 |
75 | proc buildDll() =
76 | ## C/C++ libraries
77 | let outputLib = buildDir / library & "." & cDllExtension
78 | if (thisDir / buildDir / "tmp_dll" / headerFile).needsRefresh(srcFiles):
79 | os.removeDir(buildDir / "tmp_dll")
80 | execNim "c --threads:on --gc:orc --passC:-fpic -d:release --noMain:on -d:noMain --nimcache=./" & buildDir & "/tmp_dll" &
81 | " --app:lib --noLinking:on --header:" & library & ".h --compileOnly:off " & " " & mainApp # creates header and compiled .o files
82 | os.copyFile(nimviewPath / "nimview.hpp", thisDir / buildDir / "tmp_dll/nimview.hpp")
83 | os.copyFile(thisDir / buildDir / "tmp_c" / headerFile, thisDir / buildDir / "tmp_dll" / headerFile)
84 | os.copyFile(nimbaseDir / "nimbase.h", thisDir / buildDir / "tmp_dll" / "nimbase.h")
85 |
86 | let minGwSymbols = when defined(windows):
87 | " -Wl,--out-implib," & buildDir & "/lib" & library &
88 | ".a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive " & buildDir & "/tmp_dll/*.o -Wl,--no-whole-archive "
89 | elif defined(linux):
90 | " -Wl,--out-implib," & buildDir & "/lib" & library & ".a -Wl,--whole-archive " & buildDir & "/tmp_dll/*.o -Wl,--no-whole-archive "
91 | else:
92 | " " & buildDir & "/tmp_dll/*.o "
93 | execShCmd "gcc -shared -o " & outputLib & " -I" & buildDir & "/tmp_dll/" & " " & minGwSymbols & webviewlLibs # generate .dll and .a
94 | echo "Shared C libraries build completed. Files have been created in '" & buildDir & "' folder."
95 |
96 | proc runTests() =
97 | buildGenericObjects()
98 | buildDll()
99 | buildCSample()
100 | if not defined(macosx):
101 | buildCppSample()
102 |
103 | proc generateDocs() =
104 | execNim "doc -o:docs/" & library & ".html " & mainApp
105 |
106 | task "docs", "Generate doc":
107 | generateDocs()
108 |
109 | task "libs", "Build Libs":
110 | buildGenericObjects()
111 | buildDll()
112 |
113 | task "c", "Build C sample":
114 | buildGenericObjects()
115 | buildCSample()
116 |
117 | task "cpp", "Build CPP sample":
118 | buildGenericObjects()
119 | buildCPPSample()
120 |
121 | task "clean", "clean all files":
122 | os.removeDir(buildDir)
123 |
124 | task "test", "Run tests":
125 | runTests()
126 | echo "all C/C++ tests passed"
--------------------------------------------------------------------------------
/examples/c_cpp/readme.md:
--------------------------------------------------------------------------------
1 | # nimview C / CPP example
2 |
3 | Is using a "minimal precompiled html ui" and doesn't use npm.
4 | Uses "nake" to compile library and to compile C/C++ code.
5 |
6 | Requires to have gcc available in PATH.
7 |
8 | Usage:
9 | - nake libs: This will compile Dlls / so files to use Nimview as library, for example
10 | to use it from Visual Studio
11 | - nake cpp: Compiles C++ Example
12 | - nae c: Compiles C Example
13 |
14 | Before using the VS project file, you need to run "nake libs".
15 | As Webview doesn't support clang or MSVC yet, you need to use a DLL of Nimview
16 | when using Visual Studio.
--------------------------------------------------------------------------------
/examples/c_cpp/src/c_sample.c:
--------------------------------------------------------------------------------
1 | /** Nimview UI Library
2 | * Copyright (C) 2020, 2021, by Marco Mengelkoch
3 | * Licensed under MIT License, see License file for more details
4 | * git clone https://github.com/marcomq/nimview
5 | **/
6 | // Important Notice: You should use --threads:on AND you need to avoid --gc:arc ; I had crashes on windows otherwise with NIM 1.4 when starting webview
7 |
8 | #include "nimview.h"
9 | #include
10 | #include
11 |
12 | char* echoAndModify(char* something) {
13 | const char* appendString = " modified by C";
14 | char* result = malloc(strlen(something) + strlen(appendString) + 1); // +1 for the null-terminator, strlen is unchecked! "something" needs 0 termination
15 | if (result) {
16 | strcpy(result, something); // safe, result just created
17 | strcat(result, appendString); // safe, result just created with len
18 | }
19 | else {
20 | return ""; // "" will not be freed
21 | }
22 | return result;
23 | }
24 | int main(int argc, char* argv[]) {
25 | printf(" starting c code\n");
26 | NimMain();
27 | nimview_add_cstring_rstr("echoAndModify", echoAndModify, free);
28 | #ifdef _DEBUG
29 | nimview_startHttpServer("../dist/index.html", 8000, "localhost", 1);
30 | #else
31 | nimview_startDesktop("../dist/index.html", "c_sample", 640, 480, 1, 0, 1);
32 | #endif
33 | }
34 |
--------------------------------------------------------------------------------
/examples/c_cpp/src/cpp_sample.cpp:
--------------------------------------------------------------------------------
1 | /** Nimview UI Library
2 | * Copyright (C) 2020, 2021, by Marco Mengelkoch
3 | * Licensed under MIT License, see License file for more details
4 | * git clone https://github.com/marcomq/nimview
5 | **/
6 |
7 | #include
8 | #include
9 | #include "nimview.hpp"
10 |
11 |
12 | std::string echoAndModify(const std::string& something) {
13 | return (something + " appended to string");
14 | }
15 |
16 | int main(int argc, char* argv[]) {
17 | nimview::nimMain();
18 | nimview::add("echoAndModify", echoAndModify);
19 | nimview::start("../dist/index.html", 8000, "localhost");
20 | }
--------------------------------------------------------------------------------
/examples/c_cpp/src/library.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 | when isMainModule and system.appType != "lib" and not defined noMain:
3 | start()
--------------------------------------------------------------------------------
/examples/c_cpp/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../src/"
2 | --threads:on
--------------------------------------------------------------------------------
/examples/minimal/App.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 |
3 | proc echoAndModify(value: string): string =
4 | result = "'" & value & "' modified by minimal"
5 |
6 | when isMainModule:
7 | add("echoAndModify", echoAndModify)
8 | start("dist/index.html")
--------------------------------------------------------------------------------
/examples/minimal/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Minimal Example
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/minimal/nim.cfg:
--------------------------------------------------------------------------------
1 | --path: "../../src/"
--------------------------------------------------------------------------------
/examples/minimal2/App.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 | import os
3 |
4 | proc callJsProgress() =
5 | ## just simulating progress
6 | for i in 0..100:
7 | callJs("applyProgress", $(i) & "%")
8 | os.sleep(20)
9 |
10 | proc echoAndModify(value: string): string =
11 | result = "'" & value & "' modified by minimal"
12 |
13 | when isMainModule:
14 | add("callJsProgress", callJsProgress)
15 | add("echoAndModify", echoAndModify)
16 | startDesktop("dist/index.html", debug=true)
17 |
--------------------------------------------------------------------------------
/examples/minimal2/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Minimal Example
5 |
6 |
7 |
8 |
9 |
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/examples/minimal2/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../src/"
2 | --threads:on
3 | --gc:orc
--------------------------------------------------------------------------------
/examples/python/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include nakefile.nim src/library.nim nimview.pyd nimview.so
--------------------------------------------------------------------------------
/examples/python/README.md:
--------------------------------------------------------------------------------
1 | ## Nimview Python sample application
2 |
3 | This is using nakefiles to build the python library
4 | - nake pyLib
5 |
6 | The pyTest.py doesn't trigger start yet - so it doesn't opens a GUI yet.
7 | Currently only used for testing
8 |
9 | building
10 | nake pyLib
11 | python bdist_wheel.py bdist_wheel
12 | python setup.py sdist
13 | python -m twine upload --repository pypi .\dist\nimview-0.3.3.*
--------------------------------------------------------------------------------
/examples/python/bdist_wheel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | # nake pyLib
5 | # python bdist_wheel.py bdist_wheel --plat-name win-amd64
6 | # /opt/python/cp37-cp37m/bin/python bdist_wheel.py bdist_wheel --plat-name linux-x86_64
7 | # auditwheel repair --plat manylinux2014_x86_64 dist/nimview-0.*.*-py3-none-linux_x86_64.whl
8 | from setuptools import setup, Distribution
9 | import os
10 | from shutil import copy, rmtree
11 |
12 | this_directory = os.path.abspath(os.path.dirname(__file__))
13 | targetDir = "nimview"
14 | rmtree(targetDir, ignore_errors=True)
15 | os.makedirs(targetDir, exist_ok=True)
16 | if os.name == 'nt':
17 | fileName = "out/nimview.pyd"
18 | package = ["nimview.pyd"]
19 | else:
20 | fileName = "out/nimview.so"
21 | package = ["nimview.so"]
22 | fullFileName = os.path.join(this_directory, fileName)
23 | if os.path.isfile(fullFileName):
24 | print("copy " + fullFileName + " => " + targetDir)
25 | copy(fullFileName, targetDir)
26 |
27 | with open(targetDir + "/__init__.py", "w") as text_file:
28 | text_file.write("from nimview.nimview import *")
29 |
30 | class BinaryDistribution(Distribution):
31 | """Distribution which always forces a binary package with platform name"""
32 | def has_ext_modules(self):
33 | return False
34 |
35 | setup(
36 | distclass=BinaryDistribution,
37 | package_data={
38 | "nimview": package
39 | }
40 | )
41 |
42 |
--------------------------------------------------------------------------------
/examples/python/nakefile.nim:
--------------------------------------------------------------------------------
1 | import nake
2 | import os, strutils, system
3 |
4 | let library = "nimview"
5 | let srcDir = "src"
6 | let mainApp = srcDir / "library.nim"
7 | let srcFiles = [mainApp]
8 | let buildDir = "out"
9 | let thisDir = system.currentSourcePath().parentDir()
10 |
11 | os.createDir buildDir
12 |
13 | proc execCmd(command: string) =
14 | echo "running: " & command
15 | doAssert 0 == os.execShellCmd(command)
16 |
17 | proc execNim(command: string) =
18 | echo "running: nim " & command
19 | execCmd nimexe & " " & command
20 |
21 | let pyDllExtension = when defined(windows): "pyd" else: "so"
22 |
23 | proc buildPyLib() =
24 | ## creates python lib
25 | let outputLib = buildDir / library & "." & pyDllExtension
26 | if outputLib.needsRefresh(srcFiles):
27 | os.removeDir(buildDir / "tmp_py")
28 | let winParams = when defined(windows): " --tlsEmulation:off --passL:-static " else: " "
29 | execNim "c -d:release -d:noMain --threads:on --gc:orc --deepCopy:on --app:lib --nimcache=./" & buildDir & "/tmp_py --out:" & outputLib &
30 | " " & winParams & mainApp & " " # creates python lib, header file not usable
31 | os.copyFile(outputLib, thisDir / "src" / library & "." & pyDllExtension)
32 |
33 | proc runTests() =
34 | buildPyLib()
35 | try:
36 | os.copyFile(buildDir / library & "." & pyDllExtension, thisDir / "../../tests" / library & "." & pyDllExtension)
37 | except:
38 | discard
39 | execCmd "python src/pyTest.py"
40 |
41 | proc cleanUp() =
42 | os.removeDir(buildDir)
43 |
44 | task "clean", "clean all files":
45 | cleanUp()
46 |
47 | task "pyLib", "Build python lib":
48 | buildPyLib()
49 |
50 | task "test", "Run tests":
51 | cleanUp()
52 | runTests()
53 | echo "all python tests passed"
--------------------------------------------------------------------------------
/examples/python/pySample.py:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2020, 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 |
5 | # pylint: disable=import-error
6 | import __init__, nimview, json
7 | def echoAndModify(value):
8 | print (value)
9 | return json.dumps({"val": value + " appended by python"})
10 |
11 | def echoAndModify2():
12 | return json.dumps({"no val appended by python"})
13 |
14 | nimview.setUseServer(True)
15 | nimview.addRequest("echoAndModify", echoAndModify)
16 | nimview.start("minimal_ui_sample/index.html") # current dir needs to be relative to this
--------------------------------------------------------------------------------
/examples/python/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = nimview
3 | version = 0.4.2
4 | author = Marco Mengelkoch
5 | author_email = MMengelkoch@gmx.de
6 | description = A lightwight cross platform UI library for Nim, C, C++ or Python. The main purpose is to simplify creation of Desktop applications based on a HTML/CSS/JS layer that is displayed with Webview.
7 | long_description = file: src/README.md, src/LICENSE
8 | long_description_content_type = text/markdown
9 | keywords = nim, user-interface, webview, html, css, javascript, http-server
10 | url = https://github.com/marcomq/nimview
11 | license = MIT
12 | classifiers =
13 | Development Status :: 4 - Beta
14 | Natural Language :: English
15 | Operating System :: POSIX :: Linux
16 | Operating System :: Microsoft :: Windows
17 | Operating System :: MacOS :: MacOS X
18 | Environment :: Console
19 | Environment :: Other Environment
20 | Intended Audience :: Developers
21 | Programming Language :: Python
22 | Programming Language :: Python :: 3
23 | Programming Language :: Python :: 3 :: Only
24 | Programming Language :: Python :: 3.7
25 | Programming Language :: Python :: 3.8
26 | Programming Language :: Python :: 3.9
27 | Topic :: Software Development
28 | License :: OSI Approved :: MIT License
29 |
30 | [options]
31 | packages = nimview
--------------------------------------------------------------------------------
/examples/python/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | # python setup.py sdist
5 | from setuptools import setup, Extension
6 | from setuptools.command.build_ext import build_ext
7 | from subprocess import check_call
8 | import os
9 | from shutil import copy, rmtree
10 |
11 | this_directory = os.path.abspath(os.path.dirname(__file__))
12 | targetDir = "nimview"
13 |
14 | # create another nimview subfolder as setup.py is much friendlier if you do so
15 | rmtree(targetDir, ignore_errors=True)
16 | os.makedirs(targetDir, exist_ok=True)
17 | os.makedirs(targetDir + "/src", exist_ok=True)
18 | srcFiles = [ "src/library.nim", "nakefile.nim", "LICENSE", "README.md"]
19 | for index, fileName in enumerate(srcFiles):
20 | fullFileName = os.path.join(this_directory, fileName)
21 | if os.path.isfile(fullFileName):
22 | copy(fullFileName, targetDir + "/" + fileName)
23 |
24 |
25 | class NimExtension(Extension):
26 | def __init__(self, name, sourcedir=''):
27 | Extension.__init__(self, name, sources=[])
28 | self.sourcedir = os.path.abspath(sourcedir)
29 |
30 | class NimBuild(build_ext):
31 | def run(self):
32 | for ext in self.extensions:
33 | self.build_extension(ext)
34 |
35 | def build_extension(self, ext):
36 | print("=> build_extension")
37 | os.makedirs(self.build_temp, exist_ok=True)
38 | os.makedirs(self.build_temp + "/src", exist_ok=True)
39 |
40 | extdir = self.get_ext_fullpath(ext.name)
41 | os.makedirs(extdir + "/src", exist_ok=True)
42 |
43 | for fileName in srcFiles:
44 | fullFileName = os.path.join(targetDir, fileName)
45 | if os.path.isfile(fullFileName):
46 | target = self.build_temp + "/" + fileName
47 | print("copy " + fullFileName + " => " + target)
48 | copy(fullFileName, target)
49 |
50 | check_call(['nimble', 'install', 'nimview', '-dy'], cwd=self.build_temp)
51 | print("=> dependencies installed")
52 | check_call(['nake', 'pyLib'], cwd=self.build_temp, shell=True)
53 | print("=> pyLib created")
54 | libFiles = [ "out/nimview.so", "out/nimview.pyd"]
55 | install_target = os.path.abspath(os.path.dirname(extdir))
56 | os.makedirs(install_target + "/src", exist_ok=True)
57 |
58 | for fileName in libFiles:
59 | fullFileName = os.path.join(self.build_temp, fileName)
60 | if os.path.isfile(fullFileName):
61 | print("copy " + fullFileName + " => " + install_target)
62 | copy(fullFileName, install_target)
63 |
64 | setup(
65 | ext_modules=[NimExtension('.')],
66 | cmdclass={
67 | 'build_ext': NimBuild,
68 | },
69 | package_data={
70 | "nimview": srcFiles + ["nimview.so", "nimview.pyd"]
71 | },
72 | install_requires=[
73 | "choosenim_install" # Auto-installs Nim compiler
74 | ]
75 | )
76 |
--------------------------------------------------------------------------------
/examples/python/src/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 marcomq
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/python/src/__init__.py:
--------------------------------------------------------------------------------
1 | import sys, os, pathlib
2 | # print(pathlib.Path(os.path.abspath(__file__)).parent.parent)
3 | sys.path.append(str(pathlib.Path(os.path.abspath(__file__)).parent.parent) + "/out")
4 | import nimview
--------------------------------------------------------------------------------
/examples/python/src/library.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 | when isMainModule and system.appType != "lib" and not defined noMain:
3 | start()
--------------------------------------------------------------------------------
/examples/python/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../src/"
2 | --threads:on
--------------------------------------------------------------------------------
/examples/python/src/pyTest.py:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2020, 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 |
5 | # pylint: disable=import-error
6 | import nimview
7 | def echoAndModify(value):
8 | print (value)
9 | return (value + " appended by python")
10 |
11 | def echoAndModify2():
12 | print ("received nil")
13 | return (" appended by python")
14 |
15 | def echoAndModify3(value1, value2):
16 | result = value1 + " "+ value2 + " both received"
17 | print (result)
18 | return (result + " by python")
19 |
20 | def stopNimview(value):
21 | nimview.stop()
22 | return ""
23 |
24 | nimview.addRequest("echoAndModify", echoAndModify)
25 | nimview.addRequest("echoAndModify2", echoAndModify2)
26 | nimview.addRequest("echoAndModify3", echoAndModify3)
27 | nimview.addRequest("stopNimview", stopNimview)
28 |
29 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"data\":[\"this is a test\"],\"responseId\":0}")
30 | print ("[start] Expecting an error")
31 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"data\":[],\"responseId\":3}") # will cause an error
32 | print ("[end] Not expecting an error anymore in python test")
33 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify2\",\"data\":[],\"responseId\":4}")
34 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify3\",\"data\":[\"first\",\"second\"],\"responseId\":5}")
35 | nimview.dispatchCommandLineArg("{\"request\":\"stopNimview\",\"data\":\"\",\"responseId\":6}")
36 | print ("python test passed")
37 | # nimview.startDesktop("tests/minimal_ui_sample/index.html")
38 |
--------------------------------------------------------------------------------
/examples/react/.env:
--------------------------------------------------------------------------------
1 | BUILD_PATH=./dist
--------------------------------------------------------------------------------
/examples/react/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /dist
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/examples/react/README.md:
--------------------------------------------------------------------------------
1 | # Nimview react application
2 | To compile your code, just run
3 | - npm install
4 | - npm run build
5 | - nim c -r -d:release --app:gui src/App.nim
6 | - (or, if you want to have an async count down button: `nim c -r -d:release --gc:orc --threads:on --app:gui src/App.nim`)
7 |
8 | The code was mostly generated with `create-react-app` as described in
9 | https://reactjs.org/docs/create-a-new-react-app.html
10 |
11 | It was modified to run with Nimview. It was not optimized yet to be good for development
12 | or production. You probably need to modify this code by yourself to add auto
13 | reload capabilities etc...
14 |
15 |
16 |
17 | Here is the auto-generated readme from react:
18 |
19 | # Getting Started with Create React App
20 |
21 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
22 |
23 | ## Available Scripts
24 |
25 | In the project directory, you can run:
26 |
27 | ### `npm start`
28 |
29 | Runs the app in the development mode.\
30 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
31 |
32 | The page will reload when you make changes.\
33 | You may also see any lint errors in the console.
34 |
35 | ### `npm test`
36 |
37 | Launches the test runner in the interactive watch mode.\
38 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
39 |
40 | ### `npm run build`
41 |
42 | Builds the app for production to the `build` folder.\
43 | It correctly bundles React in production mode and optimizes the build for the best performance.
44 |
45 | The build is minified and the filenames include the hashes.\
46 | Your app is ready to be deployed!
47 |
48 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
49 |
50 | ### `npm run eject`
51 |
52 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
53 |
54 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
55 |
56 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
57 |
58 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
59 |
60 | ## Learn More
61 |
62 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
63 |
64 | To learn React, check out the [React documentation](https://reactjs.org/).
65 |
66 | ### Code Splitting
67 |
68 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
69 |
70 | ### Analyzing the Bundle Size
71 |
72 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
73 |
74 | ### Making a Progressive Web App
75 |
76 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
77 |
78 | ### Advanced Configuration
79 |
80 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
81 |
82 | ### Deployment
83 |
84 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
85 |
86 | ### `npm run build` fails to minify
87 |
88 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
89 |
--------------------------------------------------------------------------------
/examples/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-nimview-example",
3 | "version": "0.1.0",
4 | "homepage": "./",
5 | "proxy": "http://localhost:8000",
6 | "private": true,
7 | "dependencies": {
8 | "bootstrap": "^4.6.0",
9 | "jquery": "^3.6.0",
10 | "nimview": "^1.1.3",
11 | "react": "^17.0.2",
12 | "react-app-polyfill": "^3.0.0",
13 | "react-dom": "^17.0.2",
14 | "react-scripts": "5.0.0"
15 | },
16 | "devDependencies": {
17 | "@testing-library/jest-dom": "^5.16.1",
18 | "@testing-library/react": "^12.1.2",
19 | "@testing-library/user-event": "^13.5.0",
20 | "@tauri-apps/tauri-inliner": "^1.13.2",
21 | "web-vitals": "^2.1.2"
22 | },
23 | "scripts": {
24 | "start": "react-scripts start",
25 | "dev": "react-scripts start",
26 | "build": "react-scripts build && inliner -m --videos --preserve-comments dist/index.html > dist/inlined.html"
27 | },
28 | "eslintConfig": {
29 | "extends": [
30 | "react-app",
31 | "react-app/jest"
32 | ]
33 | },
34 | "browserslist": {
35 | "production": [
36 | "> 1%",
37 | "last 2 versions",
38 | "IE 11"
39 | ],
40 | "development": [
41 | "last 1 chrome version",
42 | "last 1 firefox version",
43 | "last 1 safari version"
44 | ]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/examples/react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/react/public/favicon.ico
--------------------------------------------------------------------------------
/examples/react/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/react/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/examples/react/src/App.jsx:
--------------------------------------------------------------------------------
1 | import Navbar from './components/Navbar'
2 | import Sample from './components/Sample'
3 |
4 | function App() {
5 | return (
6 |
7 |
8 |
9 |
10 | )
11 | }
12 |
13 | export default App
14 |
--------------------------------------------------------------------------------
/examples/react/src/App.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 | import os
3 |
4 | proc appendSomething(value: string): string {.noSideEffect.} =
5 | result = "'" & value & "' modified by react sample"
6 |
7 | proc countDown() =
8 | callJs("alert", "waiting 6 seconds")
9 | sleep(2000)
10 | callJs("alert", "4")
11 | sleep(3000)
12 | callJs("alert", "1")
13 | sleep(1000)
14 |
15 | proc main() =
16 | add("appendSomething", appendSomething)
17 | add("countDown", countDown)
18 | start()
19 |
20 | when isMainModule:
21 | main()
--------------------------------------------------------------------------------
/examples/react/src/components/Navbar.jsx:
--------------------------------------------------------------------------------
1 | export default function Navbar() {
2 | return
24 | }
--------------------------------------------------------------------------------
/examples/react/src/components/Sample.jsx:
--------------------------------------------------------------------------------
1 | import backend from "nimview"
2 | import React from "react"
3 |
4 | class Sample extends React.Component {
5 | constructor(props) {
6 | super(props)
7 | this.state = {
8 | search: '',
9 | elements: []
10 | }
11 | }
12 | renderItems = () => {
13 | const elementItems = this.state.elements.map((item) =>
14 | {item.val}
15 | )
16 | return elementItems
17 | }
18 |
19 | countDown = () => {
20 | backend.countDown().then(() => {
21 | alert(0)
22 | })
23 | }
24 |
25 | runSearch = () => {
26 | const newElements = this.state.elements
27 | newElements.push({val: this.state.search})
28 | backend.appendSomething(this.state.search).then((resp) => {
29 | this.setState({search: resp, elements: newElements})
30 | }) // calling the backend
31 | }
32 |
33 | updateSearch = (event) => {
34 | this.setState({search: event.target.value})
35 | }
36 |
37 | render() {
38 | return
39 |
40 |
45 |
46 |
{this.renderItems()}
47 |
48 | }
49 | }
50 | export default Sample
51 |
--------------------------------------------------------------------------------
/examples/react/src/index.js:
--------------------------------------------------------------------------------
1 | import 'react-app-polyfill/ie11'
2 | import React from 'react'
3 | import ReactDOM from 'react-dom'
4 | import App from './App'
5 | import 'jquery/dist/jquery.js'
6 | import 'bootstrap/dist/js/bootstrap.bundle.js'
7 | import 'bootstrap/dist/css/bootstrap.css'
8 |
9 | document.addEventListener("DOMContentLoaded", function() {
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('app')
15 | )
16 | })
--------------------------------------------------------------------------------
/examples/react/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../src/"
--------------------------------------------------------------------------------
/examples/svelte/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /public/build/
3 | /public/vendor/
4 | /dist/
5 |
6 | .DS_Store
7 | storage.json
--------------------------------------------------------------------------------
/examples/svelte/dist/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/svelte/dist/favicon.png
--------------------------------------------------------------------------------
/examples/svelte/dist/global.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/svelte/dist/global.css
--------------------------------------------------------------------------------
/examples/svelte/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Svelte app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/svelte/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-app",
3 | "version": "1.0.1",
4 | "description": "Sample application for Nimview",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/marcomq/nimview.git"
9 | },
10 | "scripts": {
11 | "build": "rollup -c && inliner -m --videos --preserve-comments dist/index.html > dist/inlined.html",
12 | "devbuild": "rollup -c",
13 | "dev": "rollup -c -w",
14 | "dev-ie": "(set USE_BABEL=1 || export USE_BABEL=1) && rollup -c -w",
15 | "start": "sirv public --no-clear"
16 | },
17 | "devDependencies": {
18 | "@babel/core": "^7.15.5",
19 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
20 | "@babel/plugin-transform-runtime": "^7.15.0",
21 | "@babel/preset-env": "^7.15.4",
22 | "@babel/runtime": "^7.15.4",
23 | "@rollup/plugin-babel": "^5.3.0",
24 | "@rollup/plugin-commonjs": "^20.0.0",
25 | "@rollup/plugin-node-resolve": "^13.0.4",
26 | "@tauri-apps/tauri-inliner": "^1.13.2",
27 | "rollup": "^2.56.3",
28 | "rollup-plugin-css-only": "^3.1.0",
29 | "rollup-plugin-livereload": "^2.0.5",
30 | "rollup-plugin-svelte": "^7.1.0",
31 | "rollup-plugin-terser": "^7.0.2",
32 | "sirv-cli": "^1.0.14",
33 | "svelte": "^3.42.4"
34 | },
35 | "dependencies": {
36 | "bootstrap": "^4.6.0",
37 | "core-js": "^3.17.2",
38 | "jquery": "^3.6.0",
39 | "nimview": "^1.1.3"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/svelte/readme.md:
--------------------------------------------------------------------------------
1 | # nimview Svelte Application
2 |
3 | To compile your code, just run
4 | - npm install
5 | - npm run build
6 | - nim c -r -d:release --app:gui src/App.nim
7 | - (or, if you want to have an async count down button: `nim c -r -d:release --gc:orc --threads:on --app:gui src/App.nim`)
8 |
--------------------------------------------------------------------------------
/examples/svelte/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte'
2 | import resolve from '@rollup/plugin-node-resolve'
3 | import commonjs from '@rollup/plugin-commonjs'
4 | import { babel } from '@rollup/plugin-babel'
5 | import livereload from 'rollup-plugin-livereload'
6 | import { terser } from 'rollup-plugin-terser'
7 | import css from 'rollup-plugin-css-only'
8 |
9 |
10 | const production = !process.env.ROLLUP_WATCH
11 | const useBabel = production || process.env.USE_BABEL
12 |
13 | export default {
14 | input: 'src/main.js',
15 | output: {
16 | sourcemap: true,
17 | format: 'iife',
18 | name: 'app',
19 | file: 'dist/build/bundle.js'
20 | },
21 | plugins: [
22 | svelte({
23 | compilerOptions: {
24 | // enable run-time checks when not in production
25 | dev: !production
26 | }
27 | }),
28 | css({ output: 'bundle.css' }),
29 | // If you have external dependencies installed from
30 | // npm, you'll most likely need these plugins. In
31 | // some cases you'll need additional configuration
32 | // consult the documentation for details:
33 | // https://github.com/rollup/rollup-plugin-commonjs
34 | resolve({
35 | browser: true,
36 | dedupe: ['svelte']
37 | }),
38 | commonjs(),
39 |
40 | // Watch the `dist` directory and refresh the
41 | // browser on changes when not in production
42 | !production && livereload('dist'),
43 | // added by angelo
44 | // compile to good old IE11 compatible ES5
45 | useBabel && babel({
46 | extensions: [ '.js', '.mjs', '.html', '.svelte' ],
47 | babelHelpers: 'runtime',
48 | exclude: [ 'node_modules/@babel/**', 'node_modules/core-js/**' ],
49 | presets: [
50 | [
51 | '@babel/preset-env',
52 | {
53 | targets: {
54 | ie: '11'
55 | },
56 | useBuiltIns: 'usage',
57 | corejs: 3
58 | }
59 | ]
60 | ],
61 | plugins: [
62 | '@babel/plugin-syntax-dynamic-import',
63 | [
64 | '@babel/plugin-transform-runtime',
65 | {
66 | useESModules: true
67 | }
68 | ]
69 | ]
70 | }),
71 |
72 | // If we're building for production (npm run build
73 | // instead of npm run dev), minify
74 | production && terser()
75 | ],
76 | watch: {
77 | clearScreen: false
78 | }
79 | }
--------------------------------------------------------------------------------
/examples/svelte/src/App.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 | import os
3 |
4 | proc appendSomething(value: string): string {.noSideEffect.} =
5 | result = "'" & value & "' modified by svelte sample"
6 |
7 | proc countDown() =
8 | callJs("alert", "waiting 6 seconds")
9 | sleep(2000)
10 | callJs("alert", "4")
11 | sleep(3000)
12 | callJs("alert", "1")
13 | sleep(1000)
14 |
15 | proc main() =
16 | add("appendSomething", appendSomething)
17 | add("countDown", countDown)
18 | start()
19 | ## alternative fullscreen mode:
20 | # start(run=false)
21 | # setFullscreen(true)
22 | # run()
23 |
24 | when isMainModule:
25 | main()
--------------------------------------------------------------------------------
/examples/svelte/src/App.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/svelte/src/components/Navbar.svelte:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/svelte/src/components/Sample.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
26 |
27 |
28 | {#if ((typeof elements !== "undefined") && (elements.length > 0))}
29 | {#each elements as el}
30 |
31 | {el.text}
32 |
33 | {/each}
34 | {:else}
35 |
No data available yet
36 | {/if}
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/examples/svelte/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte'
2 | import 'jquery/dist/jquery.js'
3 | import 'bootstrap/dist/js/bootstrap.bundle.js'
4 | import 'bootstrap/dist/css/bootstrap.css'
5 |
6 | var app
7 | document.addEventListener("DOMContentLoaded", function() {
8 | app = new App({
9 | target: document.body,
10 | })
11 | })
12 |
13 | export default app
--------------------------------------------------------------------------------
/examples/svelte/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../src/"
--------------------------------------------------------------------------------
/examples/svelte_todo/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /public/build/
3 | /public/vendor/
4 | /dist/
5 |
6 | .DS_Store
7 | storage.json
--------------------------------------------------------------------------------
/examples/svelte_todo/dist/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/svelte_todo/dist/favicon.png
--------------------------------------------------------------------------------
/examples/svelte_todo/dist/global.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/svelte_todo/dist/global.css
--------------------------------------------------------------------------------
/examples/svelte_todo/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Todo app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/svelte_todo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-todo",
3 | "version": "1.0.1",
4 | "description": "Sample application for Nimview",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/marcomq/nimview.git"
9 | },
10 | "scripts": {
11 | "build": "rollup -c && inliner -m --videos --preserve-comments dist/index.html > dist/inlined.html",
12 | "devbuild": "rollup -c",
13 | "dev": "rollup -c -w",
14 | "dev-ie": "(set USE_BABEL=1 || export USE_BABEL=1) && rollup -c -w",
15 | "start": "sirv public --no-clear"
16 | },
17 | "devDependencies": {
18 | "@babel/core": "^7.15.5",
19 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
20 | "@babel/plugin-transform-runtime": "^7.15.0",
21 | "@babel/preset-env": "^7.15.4",
22 | "@babel/runtime": "^7.15.4",
23 | "@rollup/plugin-babel": "^5.3.0",
24 | "@rollup/plugin-commonjs": "^20.0.0",
25 | "@rollup/plugin-node-resolve": "^13.0.4",
26 | "@tauri-apps/tauri-inliner": "^1.13.2",
27 | "rollup": "^2.56.3",
28 | "rollup-plugin-css-only": "^3.1.0",
29 | "rollup-plugin-livereload": "^2.0.5",
30 | "rollup-plugin-svelte": "^7.1.0",
31 | "rollup-plugin-terser": "^7.0.2",
32 | "sirv-cli": "^1.0.14",
33 | "svelte": "^3.42.4"
34 | },
35 | "dependencies": {
36 | "@palsch/svelte-sortablejs": "^1.2.1",
37 | "bootstrap": "^4.6.0",
38 | "core-js": "^3.17.2",
39 | "jquery": "^3.6.0",
40 | "nimview": "^1.1.3"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/svelte_todo/readme.md:
--------------------------------------------------------------------------------
1 | # nimview Svelte Todo-list Application
2 |
3 | This is the source code for the demo app on the Nimview page.
4 | To compile your code, just run
5 | - npm install
6 | - npm run build
7 | - nim c -r --app:gui src/App.nim
8 |
--------------------------------------------------------------------------------
/examples/svelte_todo/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte'
2 | import resolve from '@rollup/plugin-node-resolve'
3 | import commonjs from '@rollup/plugin-commonjs'
4 | import { babel } from '@rollup/plugin-babel'
5 | import livereload from 'rollup-plugin-livereload'
6 | import { terser } from 'rollup-plugin-terser'
7 | import css from 'rollup-plugin-css-only'
8 |
9 |
10 | const production = !process.env.ROLLUP_WATCH
11 | const useBabel = production || process.env.USE_BABEL
12 |
13 | export default {
14 | input: 'src/main.js',
15 | output: {
16 | sourcemap: true,
17 | format: 'iife',
18 | name: 'app',
19 | file: 'dist/build/bundle.js'
20 | },
21 | plugins: [
22 | svelte({
23 | compilerOptions: {
24 | // enable run-time checks when not in production
25 | dev: !production
26 | }
27 | }),
28 | css({ output: 'bundle.css' }),
29 | // If you have external dependencies installed from
30 | // npm, you'll most likely need these plugins. In
31 | // some cases you'll need additional configuration
32 | // consult the documentation for details:
33 | // https://github.com/rollup/rollup-plugin-commonjs
34 | resolve({
35 | browser: true,
36 | dedupe: ['svelte']
37 | }),
38 | commonjs(),
39 |
40 | // Watch the `dist` directory and refresh the
41 | // browser on changes when not in production
42 | !production && livereload('dist'),
43 | // added by angelo
44 | // compile to good old IE11 compatible ES5
45 | useBabel && babel({
46 | extensions: [ '.js', '.mjs', '.html', '.svelte' ],
47 | babelHelpers: 'runtime',
48 | exclude: [ 'node_modules/@babel/**', 'node_modules/core-js/**' ],
49 | presets: [
50 | [
51 | '@babel/preset-env',
52 | {
53 | targets: {
54 | ie: '11'
55 | },
56 | useBuiltIns: 'usage',
57 | corejs: 3
58 | }
59 | ]
60 | ],
61 | plugins: [
62 | '@babel/plugin-syntax-dynamic-import',
63 | [
64 | '@babel/plugin-transform-runtime',
65 | {
66 | useESModules: true
67 | }
68 | ]
69 | ]
70 | }),
71 |
72 | // If we're building for production (npm run build
73 | // instead of npm run dev), minify
74 | production && terser()
75 | ],
76 | watch: {
77 | clearScreen: false
78 | }
79 | }
--------------------------------------------------------------------------------
/examples/svelte_todo/src/App.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 |
3 | when isMainModule:
4 | enableStorage() # adds getStoredVal and setStoredVal
5 | start()
--------------------------------------------------------------------------------
/examples/svelte_todo/src/App.svelte:
--------------------------------------------------------------------------------
1 |
57 |
58 |
63 |
107 |
108 |
--------------------------------------------------------------------------------
/examples/svelte_todo/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte'
2 | import 'jquery/dist/jquery.js'
3 | import 'bootstrap/dist/js/bootstrap.bundle.js'
4 | import 'bootstrap/dist/css/bootstrap.css'
5 |
6 | var app
7 | document.addEventListener("DOMContentLoaded", function() {
8 | app = new App({
9 | target: document.body,
10 | })
11 | })
12 |
13 | export default app
--------------------------------------------------------------------------------
/examples/svelte_todo/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../src/"
--------------------------------------------------------------------------------
/examples/vue/README.md:
--------------------------------------------------------------------------------
1 | ## Nimview Vue sample application
2 |
3 | - npm install
4 | - npm run build
5 | - nim c -r -d:release --app:gui src/App.nim
6 | - (or, if you want to have an async count down button: `nim c -r -d:release --gc:orc --threads:on --app:gui src/App.nim`)
--------------------------------------------------------------------------------
/examples/vue/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ['@vue/app', { useBuiltIns: 'usage' }]
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/examples/vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nimview-bootstrapvue",
3 | "version": "0.1.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vue-cli-service serve --host localhost",
7 | "dev-ie": "vue-cli-service serve",
8 | "serve": "vue-cli-service serve",
9 | "build": "vue-cli-service build && inliner -m --videos --preserve-comments dist/index.html > dist/inlined.html",
10 | "lint": "vue-cli-service lint"
11 | },
12 | "devDependencies": {
13 | "@tauri-apps/tauri-inliner": "^1.13.2",
14 | "@vue/cli-plugin-babel": "^4.5.15",
15 | "@vue/cli-service": "^4.5.15",
16 | "babel-eslint": "^10.1.0",
17 | "eslint": "^7.32.0",
18 | "eslint-plugin-vue": "^7.18.0",
19 | "vue-template-compiler": "^2.6.14"
20 | },
21 | "dependencies": {
22 | "bootstrap": "^4.6.0",
23 | "bootstrap-vue": "^2.21.2",
24 | "core-js": "^3.18.0",
25 | "vue": "^2.6.14",
26 | "nimview": "^1.1.3"
27 | },
28 | "eslintConfig": {
29 | "root": true,
30 | "env": {
31 | "node": true
32 | },
33 | "extends": [
34 | "plugin:vue/essential",
35 | "eslint:recommended"
36 | ],
37 | "parserOptions": {
38 | "parser": "babel-eslint"
39 | },
40 | "rules": {}
41 | },
42 | "browserslist": {
43 | "production": [
44 | "> 1%",
45 | "last 2 versions",
46 | "IE 11"
47 | ],
48 | "development": [
49 | "last 1 chrome version",
50 | "last 1 firefox version",
51 | "last 1 safari version"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/examples/vue/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/vue/public/favicon.ico
--------------------------------------------------------------------------------
/examples/vue/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/vue/src/App.nim:
--------------------------------------------------------------------------------
1 | import nimview
2 | import os
3 |
4 | proc appendSomething(value: string): string {.noSideEffect.} =
5 | result = "'" & value & "' modified by Vue sample"
6 |
7 | proc countDown() =
8 | callFrontendJs("alert", "waiting 6 seconds")
9 | sleep(2000)
10 | callFrontendJs("alert", "4")
11 | sleep(3000)
12 | callFrontendJs("alert", "1")
13 | sleep(1000)
14 |
15 | proc main() =
16 | add("appendSomething", appendSomething)
17 | add("countDown", countDown)
18 | let argv = os.commandLineParams()
19 | for arg in argv:
20 | readAndParseJsonCmdFile(arg)
21 | start()
22 |
23 | when isMainModule:
24 | main()
--------------------------------------------------------------------------------
/examples/vue/src/App.vue:
--------------------------------------------------------------------------------
1 | //App.vue
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/vue/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/examples/vue/src/assets/logo.png
--------------------------------------------------------------------------------
/examples/vue/src/components/Navbar.vue:
--------------------------------------------------------------------------------
1 | //src/components/Navbar.vue
2 |
3 |
4 |
5 |
6 | Application
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Nothing here yet
15 | Some Action
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/vue/src/components/Sample.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
40 |
41 |
No data available yet
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/examples/vue/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import BootstrapVue from 'bootstrap-vue'
4 |
5 | import 'bootstrap/dist/css/bootstrap.css'
6 | import 'bootstrap-vue/dist/bootstrap-vue.css'
7 |
8 | document.addEventListener("DOMContentLoaded", function() {
9 | Vue.use(BootstrapVue)
10 | Vue.config.productionTip = false
11 |
12 | new Vue({
13 | render: h => h(App)
14 | }).$mount('#app')
15 | })
16 |
--------------------------------------------------------------------------------
/examples/vue/src/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"../../../src/"
--------------------------------------------------------------------------------
/examples/vue/vue.config.js:
--------------------------------------------------------------------------------
1 | // vue.config.js
2 | module.exports = {
3 | publicPath: "",
4 | filenameHashing: false,
5 | devServer: {
6 | host: "localhost",
7 | port: 5000,
8 | proxy: {
9 | "/" : { target: 'http://localhost:8000'},
10 | "/ws" : { target: 'http://localhost:8000/ws', ws: false}
11 | }
12 | },
13 | transpileDependencies: [
14 | "nimview"
15 | ]
16 | }
--------------------------------------------------------------------------------
/nimview.nimble:
--------------------------------------------------------------------------------
1 | version = "0.4.2"
2 | author = "Marco Mengelkoch"
3 | description = "Nim / Python / C library to run webview with HTML/JS as UI"
4 | license = "MIT"
5 | srcDir = "src"
6 |
7 | import os, strutils
8 | # Dependencies
9 | # you may skip nimpy and webview when compiling with nim c -d:just_core
10 | # Currently, Webview requires gcc and doesn't work with vcc or clang
11 |
12 | requires "nim >= 1.4.8", "nimpy >= 0.1.1", "nake >= 1.9.0", "ws >= 0.4.4"
13 |
14 | when defined(nimdistros):
15 | import distros
16 | # no foreignDep required for Windows
17 | if detectOs(Ubuntu):
18 | foreignDep "libwebkit2gtk-4.0-dev"
19 | elif detectOs(CentOS) or detectOs(RedHat) or detectOs(Fedora):
20 | foreignDep "webkitgtk4-devel"
21 | if not detectOs(Windows):
22 | echo "In case of trouble, you may need to install following dependencies:"
23 | echo ""
24 | echoForeignDeps()
25 | echo ""
26 | else:
27 | echo "no nimdistros"
28 |
29 | proc execSh(cmd: string) =
30 | if detectOs(Windows):
31 | exec "cmd /C " & cmd
32 | else:
33 | exec "bash -c '" & cmd & "'"
34 |
35 | proc builDemoBinaries() =
36 | let baseDir = thisDir()
37 | cd baseDir / "examples/svelte_todo"
38 | exec "nim c -f -d:release -d:useServer --out:" & baseDir & "/demo/httpTodo.exe src/App.nim"
39 | exec "nim c -f -d:release --app:gui --out:" & baseDir & "/demo/appTodo.exe src/App.nim"
40 | cd baseDir
41 |
42 | proc builDemoJs() =
43 | let baseDir = thisDir()
44 | cd baseDir / "examples/svelte_todo"
45 | execSh "npm install"
46 | execSh "npm run build"
47 | cd baseDir
48 |
49 | task docs, "Generate doc":
50 | exec "nim doc -o:docs/theindex.html src/nimview.nim "
51 | exec "nim doc -o:docs/webviewRenderer.html src/nimview/webviewRenderer.nim"
52 | exec "nim doc -o:docs/httpRenderer.html src/nimview/httpRenderer.nim"
53 | exec "nim doc -o:docs/storage.html src/nimview/storage.nim"
54 | exec "nim doc -o:docs/sharedTypes.html src/nimview/sharedTypes.nim"
55 | exec "nim doc -o:docs/requestMap.html src/nimview/requestMap.nim"
56 | exec "nim doc -o:docs/globals.html src/nimview/globals.nim"
57 | # let cmd = "inliner -n --preserve-comments --iesafe --inlinemin docs/nimview_tmp.html > docs/nimview.html"
58 | # execSh cmd
59 |
60 | task demo, "Generate demo files":
61 | builDemoJs()
62 | builDemoBinaries()
63 |
64 | task test, "Run tests":
65 | builDemoBinaries()
66 | let baseDir = thisDir()
67 | cd baseDir / "examples/c_cpp"
68 | let nake = system.findExe("nake")
69 | exec nake & " clean"
70 | exec nake & " test"
71 | cd baseDir / "examples/python"
72 | exec nake & " clean"
73 | exec nake & " test"
74 | cd baseDir
75 | exec "testament pattern \"tests/*.nim\""
76 | echo "All tests passed"
--------------------------------------------------------------------------------
/src/js/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 marcomq
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/js/README.md:
--------------------------------------------------------------------------------
1 | This package is part of [Nimview](https://github.com/marcomq/nimview/) and
2 | contains Javascript helpers to call server functions on nimview http server or
3 | nimview webview.
4 |
5 | You should import it as
6 |
7 | `import backend from "nimview"`
8 |
9 | The only function that might be called directly is
10 |
11 | `backend.waitInit().then(backend.someFunction)`
--------------------------------------------------------------------------------
/src/js/nimview.js:
--------------------------------------------------------------------------------
1 | /** Nimview UI Library
2 | * © Copyright 2021, by Marco Mengelkoch
3 | * Licensed under MIT License, see License file for more details
4 | * git clone https://github.com/marcomq/nimview
5 | **/
6 |
7 | import "whatwg-fetch"
8 |
9 | let ui
10 | if (typeof window.ui !== "object") {
11 | ui = {}
12 | ui.copyright = "© Copyright 2021, by Marco Mengelkoch"
13 | ui.resolveStorage = {}
14 | ui.callbackMapping = {}
15 | ui.requestCounter = 0
16 | ui.waitCounter = 0
17 | ui.initStarted = false
18 | ui.initFinished = false
19 | ui.initFailed = false
20 | window.ui = ui
21 | }
22 | else {
23 | ui = window.ui
24 | }
25 | let backend
26 | if (typeof window.backend !== "object") {
27 | backend = {}
28 | window.backend = backend
29 | }
30 | else {
31 | backend = window.backend
32 | }
33 | const defaultPostTarget = ""
34 | const host = "" // might cause "cors" errors if defined
35 | const wsHost = window.location.host
36 |
37 | ui.createRequestId = () => {
38 | if (ui.requestCounter >= Number.MAX_SAFE_INTEGER-1) {
39 | ui.requestCounter = 0
40 | }
41 | return ui.requestCounter++
42 | }
43 | ui.alert = (str) => {
44 | if (ui.usingBrowser()) {
45 | alert(str)
46 | }
47 | else if (typeof window.nimview.alert === 'function') {
48 | window.nimview.alert(str)
49 | }
50 | }
51 | /**
52 | * This function will usually not be required as nimview registers all back-end functions
53 | * automatically to be available on front-end. You just need to call
54 | * backend.{registeredFunction}(...)
55 | * You may still use this function to explicitely call a function on server
56 | * @param {string} request
57 | * @param {*} data
58 | * @param {string} signature
59 | */
60 | ui.callRequest = async (request, data, signature) => {
61 | if (typeof signature === "undefined") {
62 | signature = ""
63 | }
64 | if (typeof data === "undefined") {
65 | data = []
66 | }
67 | if (ui.usingBrowser()) {
68 | // http-server
69 | const postData = JSON.stringify({request: request, data: data})
70 | const requestOpts = {
71 | method: 'POST', // always use AJAX post for simplicity with special chars
72 | mode: 'cors',
73 | cache: 'no-cache',
74 | headers: {'Content-Type': 'application/json'},
75 | body: postData
76 | }
77 | let url = request
78 | if (defaultPostTarget != "") {
79 | url = defaultPostTarget
80 | }
81 | if (ui.globalToken && (ui.globalToken.length > 0)) {
82 | requestOpts.headers["global-token"] = ui.globalToken
83 | }
84 | if (data.length != Math.min(signature.length, signature.split(",").length)
85 | && (signature.indexOf("array") == -1) && (signature.indexOf("vector") == -1)
86 | && (signature.indexOf("list") == -1) && (signature.indexOf("map") == -1)
87 | && console && console.log) {
88 | console.log("Request signature might not fit: '" + request + "' signature: '"
89 | + signature + "' data: '" + JSON.stringify(data) + "'")
90 | }
91 | return fetch(host + "/" + url, requestOpts).then((response) => {
92 | if (response) {
93 | var globalToken = response.headers.get("global-token")
94 | if (globalToken && (globalToken.length > 0)) {
95 | ui.globalToken = globalToken
96 | ui.lastToken = Date.now()
97 | }
98 | }
99 | return response.text()
100 | })
101 | }
102 | else {
103 | // webview
104 | if (typeof window.nimview.call === "function") {
105 | const requestId = ui.createRequestId()
106 | const postData = JSON.stringify({request: request, data: data,
107 | requestId: requestId})
108 | let promise = new Promise((resolve, reject) => {
109 | ui.resolveStorage[requestId] = [resolve, reject]
110 | window.nimview.call(postData)
111 | })
112 | return promise
113 | }
114 | else {
115 | throw "window.nimview.call is not a function"
116 | }
117 | }
118 | }
119 | ui.addRequest = (requestOrArray) => {
120 | /*register global backend functions*/
121 | if (typeof requestOrArray === "string") {
122 | requestOrArray = [requestOrArray, ""]
123 | }
124 | let request = requestOrArray[0] + ""
125 | let signature = requestOrArray[1] + "" // for debugging
126 | backend[request] = async (...data) => {
127 | return ui.callRequest(request, data, signature)
128 | }
129 | }
130 | ui.applyResponse = (requestId, data) => {
131 | if (typeof ui.resolveStorage[requestId] !== "undefined") {
132 | ui.resolveStorage[requestId][0](data)
133 | delete ui.resolveStorage[requestId]
134 | }
135 | }
136 | ui.rejectResponse = (requestId) => {
137 | if (typeof ui.resolveStorage[requestId] !== "undefined") {
138 | ui.resolveStorage[requestId][1]()
139 | delete ui.resolveStorage[requestId]
140 | }
141 | }
142 | ui.callFunction = (functionName, ...args) => {
143 | if (typeof ui.callbackMapping[functionName] === "function") {
144 | ui.callbackMapping[functionName](args)
145 | }
146 | else {
147 | window[functionName](args)
148 | }
149 | }
150 | ui.usingBrowser = () => {
151 | return (typeof window.nimview === 'undefined')
152 | }
153 | ui.init = (async () => {
154 | if (ui.waitCounter > 30) {
155 | ui.alert("API timeout")
156 | return
157 | }
158 | if ((window.location.href.indexOf("file:") == 0)
159 | || (window.location.href.indexOf("data:") == 0)) {
160 | if (typeof window.nimview === 'undefined') {
161 | // retry later when using webview and not initialized yet
162 | window.setTimeout(ui.init, 50)
163 | ui.waitCounter += 1
164 | return
165 | }
166 | }
167 | if (ui.initStarted == false) {
168 | ui.initStarted = true
169 | if (ui.usingBrowser()) {
170 | // using websocket to listen for commands
171 | let ws = "ws"
172 | if (window.location.href.indexOf("https:") == 0
173 | || host.indexOf("https:") == 0) {
174 | ws = "wss"
175 | }
176 | ui.ws = new WebSocket(ws + "://" + wsHost + "/ws")
177 | ui.ws.onmessage = (data) => {
178 | let resp
179 | try {
180 | resp = JSON.parse(data.data)
181 | } catch (err) {
182 | resp = JSON.parse(data)
183 | }
184 | ui.callFunction(resp.function, resp.args)
185 | }
186 | }
187 | await ui.callRequest("getGlobalToken", [], "").then((resp) => {
188 | let jsResp = JSON.parse(resp)
189 | if (jsResp.useGlobalToken) {
190 | window.setInterval(ui.getGlobalToken, 60 * 1000)
191 | }
192 | }).catch(() => {
193 | ui.alert("getGlobalToken failed")
194 | ui.initFailed = true
195 | })
196 | await ui.callRequest("getRequests", [], "").then((resp) => {
197 | let jsResp = JSON.parse(resp)
198 | for (let req of jsResp) { // req is type array
199 | // bind all server requests to window.backend
200 | ui.addRequest(req)
201 | }
202 | ui.initFinished = true
203 | }).catch(() => {
204 | ui.alert("getRequests failed")
205 | ui.initFailed = true
206 | })
207 | }
208 | })
209 | /**
210 | * This call is optional. You need to call this function if you want to
211 | * immediately call a backend function and need to make sure that all functions
212 | * are already available.
213 | * In case you need to wait for initalization, call:
214 | * await backend.waitInit()
215 | * or
216 | * backend.waitInit().then(backend.functionThatNeedsToWait)
217 | */
218 | backend.waitInit = () => {
219 | // everything else was complicate when using webview on windows
220 | return new Promise((resolve, reject) => {
221 | let waitLoop = () => {
222 | if (ui.initFinished) {
223 | return resolve()
224 | }
225 | else if (ui.initFailed) {
226 | return reject()
227 | }
228 | else {
229 | setTimeout(waitLoop, 5)
230 | }
231 | }
232 | setTimeout(waitLoop, 1)
233 | })
234 | }
235 | /**
236 | * This function is used to change the mapping of a frontend function,
237 | * so it wouldn't be necessary to alter the backend, if a frontend function name
238 | * changes. You may not need it.
239 | * Use this if you need to run the same backend with multiple frontends or if
240 | * you want to call a frontend function that has a dot notation
241 | * @param {string} backendName - the function name that is called on backend
242 | * @param {string} frontendName the function name that is called on frontend
243 | */
244 | backend.map = (backendName, frontendName) => {
245 | ui.callbackMapping[backendName] = frontendName
246 | }
247 | /**
248 | * @deprecated use backend.map instead
249 | */
250 | backend.mapFrontendFunction = backend.map
251 | window.setTimeout(ui.init, 1) // may need to be increased on webview error
252 | export default backend
--------------------------------------------------------------------------------
/src/js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nimview",
3 | "version": "1.2.1",
4 | "description": "This package is part of marcomq/nimview",
5 | "main": "nimview.js",
6 | "scripts": {
7 | "build": "rollup -c",
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "copyToSamples": "copyfiles *.iife.* ../../examples/minimal/dist && copyfiles *.iife.* ../../examples/minimal2/dist && copyfiles *.iife.* ../../examples/c_cpp/dist"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/marcomq/nimview.git"
14 | },
15 | "keywords": [
16 | "nim",
17 | "nimview",
18 | "webview"
19 | ],
20 | "author": "Marco Mengelkoch",
21 | "license": "MIT",
22 | "homepage": "https://github.com/marcomq/nimview#readme",
23 | "bugs": {
24 | "url": "https://github.com/marcomq/nimview/issues"
25 | },
26 | "devDependencies": {
27 | "@babel/core": "^7.15.5",
28 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
29 | "@babel/plugin-transform-runtime": "^7.15.0",
30 | "@babel/preset-env": "^7.15.4",
31 | "@babel/runtime": "^7.15.4",
32 | "@babel/runtime-corejs2": "^7.15.4",
33 | "@rollup/plugin-babel": "^5.3.0",
34 | "@rollup/plugin-commonjs": "^20.0.0",
35 | "@rollup/plugin-node-resolve": "^13.0.4",
36 | "rollup": "^2.56.3",
37 | "rollup-plugin-terser": "^7.0.2",
38 | "copyfiles": "^2.4.1"
39 | },
40 | "dependencies": {
41 | "whatwg-fetch": "^3.6.2"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/js/rollup.config.js:
--------------------------------------------------------------------------------
1 | import resolve from '@rollup/plugin-node-resolve'
2 | import { terser } from 'rollup-plugin-terser'
3 | import { babel } from '@rollup/plugin-babel'
4 | import commonjs from '@rollup/plugin-commonjs'
5 |
6 |
7 | const production = !process.env.ROLLUP_WATCH
8 | const babelCfg = {
9 | extensions: [ '.js'],
10 | babelHelpers: 'runtime',
11 | exclude: [ 'node_modules/@babel/**', 'node_modules/core-js/**' ],
12 | presets: [
13 | [
14 | '@babel/preset-env',
15 | {
16 | targets: {
17 | ie: '11'
18 | },
19 | useBuiltIns: 'usage',
20 | corejs: 2
21 | }
22 | ]
23 | ],
24 | plugins: [
25 | '@babel/plugin-syntax-dynamic-import',
26 | [
27 | '@babel/plugin-transform-runtime',
28 | {
29 | "absoluteRuntime": false
30 | }
31 | ]
32 | ]
33 | }
34 | export default {
35 | input: 'nimview.js',
36 | output: [{
37 | sourcemap: true,
38 | format: 'cjs',
39 | name: 'nimview_js',
40 | file: 'nimview.cjs.js',
41 | exports: 'auto'
42 | }, {
43 | sourcemap: true,
44 | format: 'esm',
45 | name: 'nimview_js',
46 | file: 'nimview.esm.js',
47 | exports: 'auto'
48 | }, {
49 | sourcemap: true,
50 | format: 'iife',
51 | name: 'nimview_js',
52 | file: 'nimview.iife.js',
53 | exports: 'auto'
54 | }],
55 | plugins: [
56 | resolve({
57 | browser: true
58 | }),
59 | commonjs(),
60 | babel(babelCfg),
61 | production && terser()
62 | ],
63 | watch: {
64 | clearScreen: false
65 | }
66 | }
--------------------------------------------------------------------------------
/src/nimview.nim.cfg:
--------------------------------------------------------------------------------
1 | --threads:on
--------------------------------------------------------------------------------
/src/nimview/dispatchJsonRequest.nim:
--------------------------------------------------------------------------------
1 | import json
2 | import logging as log
3 | import globals
4 | import requestMap
5 |
6 | proc dispatchJsonRequest*(jsonMessage: JsonNode): string =
7 | ## Global json dispatcher that will be called from webview AND httpserver
8 | ## This will extract specific values that were prepared by nimview.js
9 | ## and forward those values to the string dispatcher.
10 | let request = jsonMessage["request"].getStr()
11 | if request == "getGlobalToken":
12 | return $ %* {"useGlobalToken": nimviewSettings.useGlobalToken}
13 | if not nimviewVars.requestLogger.isNil:
14 | nimviewVars.requestLogger.log(log.lvlInfo, $jsonMessage)
15 | let callbackFunc = requestMap.getCallbackFunc(request)
16 | result = callbackFunc(jsonMessage["data"])
17 |
--------------------------------------------------------------------------------
/src/nimview/globalToken.nim:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 | # git clone https://github.com/marcomq/nimview
5 |
6 | import times, asynchttpserver, std/sysrand, base64
7 |
8 | type Token = object
9 | token: array[32, byte]
10 | generated: ref times.DateTime
11 |
12 | type GlobalTokens* = ref object
13 | ## 3 tokens that rotate
14 | tokens*: array[3, Token]
15 |
16 | proc init*(): GlobalTokens =
17 | new result
18 | for i in 0 ..< result.tokens.len:
19 | result.tokens[i].generated = new times.DateTime
20 | result.tokens[i].generated[] = times.now() - 5.minutes
21 |
22 | proc checkIfTokenExists(self: GlobalTokens, token: array[32, byte]): bool =
23 | # Very unlikely, but it may be necessary to also lock here
24 | for i in 0 ..< self.tokens.len:
25 | if token == self.tokens[i].token:
26 | return true
27 | return false
28 |
29 | proc byteToString*(token: array[32, byte]): string =
30 | result = base64.encode(token)
31 |
32 | func stringToByte*(token: string): array[32, byte] =
33 | let tokenString = base64.decode(token)
34 | if (tokenString.len > 31):
35 | system.copyMem(result[0].addr, tokenString[0].unsafeAddr, 32)
36 | else:
37 | raise newException(CatchableError, "token too short")
38 |
39 | proc checkToken*(self: GlobalTokens, headers: HttpHeaders): bool =
40 | var headerToken: string
41 | if headers.hasKey("global-token"):
42 | headerToken = $headers["global-token"]
43 | if headerToken.len > 31:
44 | var headerGlobalTokens = globalToken.stringToByte(headerToken)
45 | return self.checkIfTokenExists(headerGlobalTokens)
46 | return false
47 |
48 | proc getFreshToken*(self: var GlobalTokens): array[32, byte] =
49 | var currentTime = times.now()
50 | const interval = 60
51 | let frame = (currentTime.minute * 60 + currentTime.second).div(interval) mod self.tokens.len # a new token every interval seconds
52 | var currentToken = addr self.tokens[frame]
53 | var tokenPlusInterval = currentTime - interval.seconds
54 | try:
55 | if currentToken[].generated[].isInitialized():
56 | tokenPlusInterval = currentToken[].generated[] + interval.seconds
57 | except:
58 | discard
59 | if tokenPlusInterval < currentTime:
60 | let randomValue = sysrand.urandom(32)
61 | for i in 0 ..< randomValue.len:
62 | result[i] = randomValue[i]
63 | currentToken[].generated[] = currentTime
64 | currentToken[].token = result
65 | result = currentToken[].token
--------------------------------------------------------------------------------
/src/nimview/globals.nim:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 | # git clone https://github.com/marcomq/nimview
5 |
6 | import os, macros, tables
7 | from sharedTypes import ReqFunction
8 | import logging as log
9 |
10 | type CstringFunc* = proc(jsArg: cstring) {.cdecl.}
11 | type RuntimeVars* = ref object
12 | requestLogger*: FileLogger
13 | staticDir*: string
14 | reqMapStore*: Table[string, ReqFunction]
15 | responseHttpHeader*: seq[tuple[key, val: string]]
16 | storage*: Table[string, string]
17 | storageFile*: string
18 | customJsEval*: pointer
19 | httpRenderer*: pointer
20 | webviewRenderer*: pointer
21 |
22 | type NimviewSettings* = object
23 | indexHtmlFile*: string
24 | port*: int
25 | bindAddr*: string
26 | title*: string
27 | width*: int
28 | height*: int
29 | resizable*: bool
30 | debug*: bool
31 | useHttpServer*: bool
32 | useGlobalToken*: bool
33 | useStaticIndexContent*: bool
34 | run*: bool
35 |
36 | const defaultIndex* =
37 | when not defined(release):
38 | "../dist/index.html"
39 | else:
40 | "../dist/inlined.html"
41 |
42 | const displayAvailable =
43 | when (system.hostOS == "windows"):
44 | true
45 | else: os.getEnv("DISPLAY") != ""
46 |
47 | const preferWebview = defined(useWebview) or not defined(useServer)
48 | const compileWithWebview* = not defined(just_core) and preferWebview
49 |
50 | proc initSettings*(indexHtmlFile: string = defaultIndex, port: int = 8000,
51 | bindAddr: string = "localhost", title: string = "nimview",
52 | width: int = 640, height: int = 480, resizable: bool = true): NimviewSettings =
53 |
54 | var useServer =
55 | not compileWithWebview or
56 | defined(useServer) or
57 | not defined(release) or
58 | not displayAvailable or
59 | (os.fileExists("/.dockerenv"))
60 |
61 | result.indexHtmlFile = indexHtmlFile
62 | result.port = port
63 | result.bindAddr = bindAddr
64 | result.title = title
65 | result.width = width
66 | result.height = height
67 | result.resizable = resizable
68 | result.debug = not defined release
69 | result.run = true
70 | result.useHttpServer = useServer
71 | result.useGlobalToken = defined(release)
72 | result.useStaticIndexContent =
73 | when declared(doNotLoadIndexContent):
74 | true
75 | else:
76 | false
77 |
78 | proc newRuntime*(): RuntimeVars =
79 | new result
80 | GC_ref(result)
81 | result.responseHttpHeader = @[("Access-Control-Allow-Origin", "127.0.0.1")]
82 | result.reqMapStore = initTable[string, ReqFunction]()
83 | result.storageFile = "storage.json"
84 | result.storage = initTable[string, string]()
85 |
86 | const defaultSettings* :NimviewSettings = initSettings()
87 | var nimviewSettings* {.global.} :NimviewSettings = initSettings()
88 | var nimviewVars* {.global.} :RuntimeVars = newRuntime()
89 |
90 |
91 | var indexContent* {.threadVar.}: string
92 | const indexContentStatic* =
93 | if fileExists(getProjectPath() & "/" & defaultSettings.indexHtmlFile):
94 | staticRead(getProjectPath() & "/" & defaultSettings.indexHtmlFile)
95 | else:
96 | ""
--------------------------------------------------------------------------------
/src/nimview/httpRenderer.nim:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # © Copyright 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 | # git clone https://github.com/marcomq/nimview
5 |
6 | import asynchttpserver, json, httpcore, asyncdispatch, os, strutils, sequtils
7 | import ws
8 | import globalToken
9 | import globals
10 | import sharedTypes
11 | import logging as log
12 | import dispatchJsonRequest
13 |
14 | type HttpRenderer* = ref object
15 | connections: seq[WebSocket] # old ws are not removed
16 | globalTokens: GlobalTokens
17 |
18 | proc getInstance: ptr HttpRenderer =
19 | {.gcsafe.}:
20 | if nimviewVars.httpRenderer.isNil:
21 | var newObj {.global.} = new HttpRenderer
22 | nimviewVars.httpRenderer = newObj.unsafeAddr
23 | GC_ref(newObj)
24 | return cast[ptr HttpRenderer](nimviewVars.httpRenderer)
25 |
26 | proc callFrontendJsEscapedHttp*(functionName: string, params: string) =
27 | ## "params" should be JS escaped values, separated by commas with surrounding quotes for string values
28 | var deletable = newSeq[int]()
29 | for idx, wsCon in getInstance().connections:
30 | if wsCon.readyState == ReadyState.Open:
31 | try:
32 | asynccheck wsCon.send("{\"function\":\"" & functionName & "\",\"args\":[" & params & "]}")
33 | except WebSocketProtocolMismatchError:
34 | log.info "Call frontend socket tried to use an unknown protocol: ", getCurrentExceptionMsg()
35 | except CatchableError:
36 | log.error "Call frontend error: ", getCurrentExceptionMsg()
37 | else:
38 | deletable.add(idx)
39 | for idx in deletable:
40 | when NimMinor >= 6 or NimMajor > 1:
41 | getInstance().connections.delete(idx..idx)
42 | else:
43 | getInstance().connections.delete(idx, idx)
44 |
45 | proc getCurrentAppDir(): string =
46 | let applicationName = os.getAppFilename().extractFilename()
47 | # debug applicationName
48 | if (applicationName.startsWith("python") or applicationName.startsWith("platform-python")):
49 | result = os.getCurrentDir()
50 | else:
51 | result = os.getAppDir()
52 |
53 | proc getAbsPath*(indexHtmlFile: string): (string, string) =
54 | let separatorFound = indexHtmlFile.rfind({'#', '?'})
55 | if separatorFound == -1:
56 | result[0] = indexHtmlFile
57 | else:
58 | result[0] = indexHtmlFile[0 ..< separatorFound]
59 | result[1] = indexHtmlFile[separatorFound .. ^1]
60 | if (not os.isAbsolute(result[0])):
61 | result[0] = getCurrentAppDir() & "/" & indexHtmlFile
62 |
63 | proc dispatchHttpRequest*(jsonMessage: JsonNode, headers: HttpHeaders): string =
64 | ## Modify this, if you want to add some authentication, input format validation
65 | ## or if you want to process HttpHeaders.
66 | if not nimviewSettings.useGlobalToken or getInstance().globalTokens.checkToken(headers):
67 | return dispatchJsonRequest(jsonMessage)
68 | else:
69 | let request = jsonMessage["request"].getStr()
70 | if request == "getGlobalToken":
71 | return $ %* {"useGlobalToken": nimviewSettings.useGlobalToken}
72 | else:
73 | raise newException(ReqDeniedException, "403 - Token expired")
74 |
75 | proc handleRequest(request: Request): Future[void] {.async.} =
76 | ## used by HttpServer
77 | var response: string
78 | var requestPath: string = request.url.path
79 | var header = @[("Content-Type", "application/javascript")]
80 | {.gcsafe.}:
81 | let defaultHeader = nimviewVars.responseHttpHeader
82 | let separatorFound = requestPath.rfind({'#', '?'})
83 | if separatorFound != -1:
84 | requestPath = requestPath[0 ..< separatorFound]
85 | if requestPath == "/":
86 | requestPath = "/index.html"
87 | if requestPath == "/index.html":
88 | when defined(release):
89 | if not indexContent.isEmptyOrWhitespace() and indexContent == indexContentStatic:
90 | header = @[("Content-Type", "text/html;charset=utf-8")]
91 | header.add(defaultHeader)
92 | await request.respond(Http200, indexContent, newHttpHeaders(header))
93 | return
94 |
95 | try:
96 | {.gcsafe.}:
97 | let potentialFilename = nimviewVars.staticDir &
98 | requestPath.replace("../", "").replace("..", "")
99 | if os.fileExists(potentialFilename):
100 | debug "Sending " & potentialFilename
101 | let fileData = splitFile(potentialFilename)
102 | let contentType = case fileData.ext:
103 | of ".json": "application/json;charset=utf-8"
104 | of ".js": "text/javascript;charset=utf-8"
105 | of ".css": "text/css;charset=utf-8"
106 | of ".jpg": "image/jpeg"
107 | of ".txt": "text/plain;charset=utf-8"
108 | of ".map": "application/octet-stream"
109 | else: "text/html;charset=utf-8"
110 | header = @[("Content-Type", contentType)]
111 | header.add(defaultHeader)
112 | await request.respond(Http200, system.readFile(potentialFilename), newHttpHeaders(header))
113 | elif requestPath == "/ws":
114 | when not defined(just_core):
115 | try:
116 | var ws = await newWebSocket(request)
117 | getInstance().connections.add(ws)
118 | while ws.readyState == ReadyState.Open:
119 | let packet = await ws.receiveStrPacket()
120 | info "Received packet: " & packet
121 | except WebSocketProtocolMismatchError:
122 | echo "Socket tried to use an unknown protocol: ", getCurrentExceptionMsg()
123 | except WebSocketError:
124 | echo "Socket error: ", getCurrentExceptionMsg()
125 | elif (request.body == ""):
126 | raise newException(ReqUnknownException, "404 - File not found")
127 | else:
128 | # if not a file, assume this is a json request
129 | var jsonMessage: JsonNode
130 | debug request.body
131 | # if unlikely(request.body == ""):
132 | # jsonMessage = parseJson(uri.decodeUrl(requestPath))
133 | # else:
134 | jsonMessage = parseJson(request.body)
135 | {.gcsafe.}:
136 | response = dispatchHttpRequest(jsonMessage, request.headers)
137 | let byteToken = getInstance().globalTokens.getFreshToken()
138 | let currentToken = globalToken.byteToString(byteToken)
139 | let header = @{"global-token": currentToken}
140 | await request.respond(Http200, response, newHttpHeaders(header))
141 |
142 | except ReqUnknownException:
143 | await request.respond(Http404,
144 | $ %* {"error": "404", "value": getCurrentExceptionMsg()},
145 | newHttpHeaders(defaultHeader))
146 | except ReqDeniedException:
147 | await request.respond(Http403,
148 | $ %* {"error": "403", "value": getCurrentExceptionMsg()},
149 | newHttpHeaders(defaultHeader))
150 | except ServerException:
151 | await request.respond(Http500,
152 | $ %* {"error": "500", "value": getCurrentExceptionMsg()},
153 | newHttpHeaders(defaultHeader))
154 | except JsonParsingError, KeyError:
155 | await request.respond(Http500,
156 | $ %* {"error": "500", "value": "request doesn't contain valid json"},
157 | newHttpHeaders(defaultHeader))
158 | except:
159 | await request.respond(Http500,
160 | $ %* {"error": "500", "value": "server error: " & getCurrentExceptionMsg()},
161 | newHttpHeaders(defaultHeader))
162 |
163 |
164 | proc serve*() {.async.} =
165 | var server = newAsyncHttpServer()
166 | getInstance().globalTokens = globalToken.init()
167 | listen(server, Port(nimviewSettings.port), nimviewSettings.bindAddr)
168 | while nimviewSettings.run:
169 | if server.shouldAcceptRequest():
170 | await server.acceptRequest(handleRequest)
171 | else:
172 | poll()
--------------------------------------------------------------------------------
/src/nimview/readme.md:
--------------------------------------------------------------------------------
1 | Git commands that were performed to checkout / update webview
2 | ```
3 | (from nimview base dir)
4 | git subtree add --prefix src/nimview/webview https://github.com/marcomq/webview.git master --squash
5 |
6 | update to latest:
7 | git subtree pull --prefix src/nimview/webview https://github.com/marcomq/webview.git master --squash
8 |
9 | push back to webview:
10 | git subtree push --prefix src/nimview/webview https://github.com/marcomq/webview.git master
11 |
12 | ```
--------------------------------------------------------------------------------
/src/nimview/sharedTypes.nim:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 | # git clone https://github.com/marcomq/nimview
5 | import json
6 | type ReqDeniedException* = object of CatchableError
7 | type ServerException* = object of CatchableError
8 | type ReqUnknownException* = object of CatchableError
9 | type ReqFunction* = object
10 | nimCallback*: proc (values: JsonNode): string
11 | jsSignature*: string
--------------------------------------------------------------------------------
/src/nimview/std/readme.md:
--------------------------------------------------------------------------------
1 | This specific file sysrand.nim is part of Nim 1.6 source code
2 | https://github.com/nim-lang/Nim/blob/devel/lib/std/sysrand.nim
3 |
4 | It was copied here as Nim 1.6 was not available yet at time of writing.
5 | It will be removed later when Nim 1.6 is widely available and stable.
--------------------------------------------------------------------------------
/src/nimview/storage.nim:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 | # git clone https://github.com/marcomq/nimview
5 |
6 | ## Implements a simple key / value store that can be used to store preferences
7 | import strutils, os
8 | import std/[json, jsonutils]
9 | import tables
10 | import globals
11 |
12 | proc initStorage*(fileName: string = "") =
13 | try:
14 | if fileName != "":
15 | nimviewVars.storageFile = fileName
16 | if os.fileExists(nimviewVars.storageFile):
17 | var storageString = system.readFile(nimviewVars.storageFile)
18 | if not storageString.isEmptyOrWhitespace():
19 | nimviewVars.storage = storageString.parseJson().jsonTo(typeof nimviewVars.storage)
20 | echo storageString
21 | except:
22 | echo "Couldn't read storage"
23 |
24 | proc getStoredVal*(key: string): string =
25 | try:
26 | result = nimviewVars.storage[key]
27 | except KeyError:
28 | discard
29 |
30 | proc setStoredVal*(key, value: string): string =
31 | if value == "":
32 | nimviewVars.storage.del(key)
33 | else:
34 | nimviewVars.storage[key] = value
35 | try:
36 | var jsonOutput: JsonNode
37 | jsonOutput = nimviewVars.storage.toJson()
38 | system.writeFile(nimviewVars.storageFile, $jsonOutput)
39 | except:
40 | echo "error setting storage key '" & key & "': " & getCurrentExceptionMsg()
41 |
--------------------------------------------------------------------------------
/src/nimview/webview/.gitattributes:
--------------------------------------------------------------------------------
1 | *.h linguist-language=c
--------------------------------------------------------------------------------
/src/nimview/webview/.gitignore:
--------------------------------------------------------------------------------
1 | nimcache/
2 | simple
3 | window
4 | minimal
5 | *Ex*
6 | *.html
7 | *Test
--------------------------------------------------------------------------------
/src/nimview/webview/readme.md:
--------------------------------------------------------------------------------
1 | # Webview for nim
2 |
3 | Nim bindings for [zserge's Webview](https://github.com/zserge/webview) which is an
4 | excellent cross-platform single header webview
5 | library for C/C++ using Gtk, Cocoa or MSHTML
6 | repectively.
7 |
8 | # Docs
9 |
10 | Documentation is [here](http://htmlpreview.github.io/?https://github.com/oskca/webview/blob/master/docs/webview.html)
11 |
12 | and [Golang's doc for webview](https://godoc.org/github.com/zserge/webview) is
13 | also very useful.
14 |
15 | When on `debian/ubuntu` `libwebkit2gtk-4.0-dev` is required as `debian/ubuntu`.
16 |
--------------------------------------------------------------------------------
/src/nimview/webview/tests/bindEx.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | action: "compile"
3 | """
4 | import webview
5 | import strutils
6 | import os
7 |
8 | const indexHTML = """
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 | """
32 | let htmlFile = getTempDir() / "xxx.html"
33 | writeFile(htmlFile, indexHTML)
34 | var w = newWebView("Simple window demo2", "file://" & htmlFile)
35 | var fullScreen = true
36 | w.bindProcs("api"):
37 | proc open() = echo w.dialogOpen()
38 | proc save() = echo w.dialogSave()
39 | proc opendir() = echo w.dialogOpen(flag=dFlagDir)
40 | proc message() = w.msg("hello", "message")
41 | proc info() = w.info("hello", "info")
42 | proc warn() = w.warn("hello", "warn")
43 | proc error() = w.error("hello", "error")
44 | proc changeTitle(title: string) = w.setTitle(title)
45 | proc close() = w.terminate()
46 | proc changeColor() = w.setColor(210,210,210,100)
47 | proc toggleFullScreen() = fullScreen = not w.setFullscreen(fullScreen)
48 |
49 | # w.setFullscreen()
50 | w.run()
51 | w.exit()
52 | removeFile(htmlFile)
53 |
--------------------------------------------------------------------------------
/src/nimview/webview/tests/config.nims:
--------------------------------------------------------------------------------
1 | --path:".."
--------------------------------------------------------------------------------
/src/nimview/webview/tests/minimal.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | action: "compile"
3 | """
4 | import webview
5 |
6 | open("Minimal webview example", "https://www.bing.com")
7 |
--------------------------------------------------------------------------------
/src/nimview/webview/tests/scopeTest.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | action: "compile"
3 | """
4 | import macros
5 |
6 | block:
7 | proc hello() =
8 | echo "nice to see youi"
9 |
10 | proc defInBlock[T, U](a:T, b:U) = echo a, b
11 |
12 | macro defInBlock(a, s: string, n: untyped): untyped =
13 | expectKind(n, nnkStmtList)
14 | let body = n
15 | body.add(newCall("hello2"))
16 | result = newBlockStmt(body)
17 | echo repr result
18 |
19 | defInBlock("waht", "api"):
20 | proc hello2() =
21 | echo "echo hello2"
22 |
23 | # hello2()
--------------------------------------------------------------------------------
/src/nimview/webview/webview.nimble:
--------------------------------------------------------------------------------
1 | # Package
2 |
3 | version = "0.1.0"
4 | author = "oskca"
5 | description = "Nim bindings for zserge\'s webview"
6 | license = "MIT"
7 | skipDirs = @["tests"]
8 |
9 | # Dependencies
10 |
11 | requires "nim >= 0.17.2"
12 |
13 | task test, "a simple test case":
14 | exec "testament pattern \"tests/*.nim\""
15 |
16 | task docs, "generate doc":
17 | exec "nim doc2 -o:docs/webview.html webview.nim"
18 |
19 | task sync, "update webview.h":
20 | exec "wget -O webview/webview.h https://raw.githubusercontent.com/wailsapp/wails/master/lib/renderer/webview/webview.h"
21 | exec "wget -O webview/webview.go https://raw.githubusercontent.com/wailsapp/wails/master/lib/renderer/webview/webview.go"
22 | exec "wget -O webview/LICENSE https://raw.githubusercontent.com/wailsapp/wails/master/lib/renderer/webview/LICENSE"
23 |
24 | task clean, "clean tmp files":
25 | exec "rm -rf nimcache"
26 | exec "rm -rf tests/nimcache"
27 |
--------------------------------------------------------------------------------
/src/nimview/webview/webview/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Serge Zaitsev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/nimview/webviewRenderer.nim:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # © Copyright 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 | # git clone https://github.com/marcomq/nimview
5 |
6 |
7 | const useWebviewInThread* = compileOption("threads") and not defined useWebviewSingleThreaded
8 | when useWebviewInThread:
9 | import threadpool
10 | import ../nimview/webview/webview except debug
11 | import json
12 | import logging as log
13 | import nimpy, strutils
14 | import globals
15 | import dispatchJsonRequest
16 |
17 | type WebviewRenderer = ref object
18 | webView*: Webview
19 | when useWebviewInThread:
20 | webviewQueue: Channel[string]
21 | runBarrier: Channel[bool]
22 | initBarrier: Channel[bool]
23 |
24 |
25 | proc getInstance: ptr WebviewRenderer =
26 | {.gcsafe.}:
27 | if nimviewVars.webviewRenderer.isNil:
28 | var newObj {.global.} = new WebviewRenderer
29 | when useWebviewInThread:
30 | newObj.webviewQueue.open()
31 | newObj.runBarrier.open()
32 | newObj.initBarrier.open()
33 | GC_ref(newObj)
34 | nimviewVars.webviewRenderer = newObj.unsafeAddr
35 | return cast[ptr WebviewRenderer](nimviewVars.webviewRenderer)
36 |
37 | proc computeMessageWebview(message: string)
38 |
39 | proc evalJs*(evalJsCode: string) =
40 | getInstance().webview.dispatch(proc() =
41 | discard getInstance().webview.eval(evalJsCode.cstring))
42 |
43 | proc callFrontendJsEscapedWebview*(functionName: string, params: string) =
44 | ## "params" should be JS escaped values, separated by commas with surrounding quotes for string values
45 | {.gcsafe.}:
46 | if not getInstance().webview.isNil:
47 | let jsExec: string = "window.ui.callFunction(\"" & functionName & "\"," & params & ");"
48 | log.info jsExec
49 | evalJs(jsExec)
50 |
51 | proc stopDesktop*() {.exportpy, exportc: "nimview_$1".} =
52 | ## Will stop the Desktop app - may trigger application exit.
53 | debug "stopping ..."
54 | if not getInstance().webview.isNil():
55 | getInstance().webview.dispatch(proc() =
56 | getInstance().webview.terminate()
57 | dealloc(getInstance().webview))
58 |
59 | proc runDesktop*(url: string, title: string, width: int, height: int,
60 | resizable: bool, debug: bool, run: bool) =
61 | {.gcsafe.}:
62 | if getInstance().webview.isNil:
63 | getInstance().webview = webview.newWebView(title, url, width,
64 | height, resizable = resizable, debug = debug)
65 | getInstance().webview.bindProc("nimview", "alert", proc (message: string) =
66 | getInstance().webview.info("alert", message))
67 | let dispatchCall = proc (message: string) =
68 | when useWebviewInThread:
69 | getInstance().webviewQueue.send(message)
70 | else:
71 | computeMessageWebview(message)
72 | getInstance().webview.bindProc("nimview", "call", dispatchCall)
73 | when useWebviewInThread:
74 | getInstance().initBarrier.send(true)
75 | if not run:
76 | discard getInstance().runBarrier.recv()
77 | getInstance().webview.run()
78 | getInstance().webviewQueue.send("")
79 | getInstance().runBarrier.close()
80 | getInstance().initBarrier.close()
81 | stopDesktop()
82 |
83 |
84 | proc spawnDesktopThread*(url: string, title: string, width: int, height: int,
85 | resizable: bool, debug: bool, run: bool) =
86 | when useWebviewInThread:
87 | spawn runDesktop(url, title, width, height, resizable, debug, run)
88 | discard getInstance().initBarrier.recv()
89 |
90 | proc waitForThreads*() =
91 | when useWebviewInThread:
92 | sync()
93 |
94 | proc runWebview*() =
95 | when useWebviewInThread:
96 | # actual webview is currently waiting in "runDesktop"
97 | getInstance().runBarrier.send(true)
98 | while nimviewSettings.run:
99 | var message = getInstance().webviewQueue.recv()
100 | computeMessageWebview(message)
101 | else:
102 | getInstance().webview.run()
103 | stopDesktop()
104 |
105 |
106 | proc selectFolderDialog*(title: string): string {.exportpy.} =
107 | ## Will open a "sect folder dialog" if in webview mode and return the selection.
108 | ## Will return emptys string in webserver mode
109 | if not getInstance().webview.isNil():
110 | result = getInstance().webview.dialogOpen(title=if title != "" : title else: "Select Folder", flag=webview.dFlagDir)
111 |
112 | proc selectFileDialog*(title: string): string {.exportpy.} =
113 | ## Will open a "sect file dialog" if in webview mode and return the selection.
114 | ## Will return emptys string in webserver mode
115 | if not getInstance().webview.isNil():
116 | result = getInstance().webview.dialogOpen(title=if title != "" : title else: "Select File", flag=webview.dFlagFile)
117 |
118 | proc setIcon*(icon: string) {.exportpy.} =
119 | getInstance().webview.dispatch(proc() =
120 | getInstance().webview.setIcon(icon.cstring))
121 |
122 | proc setBorderless*(decorated: bool = false) {.exportc, exportpy.} =
123 | ## Use gtk mode without borders, only works on linux and only in desktop mode
124 | when defined(linux):
125 | let myWebView = getInstance().webview
126 | if not myWebView.isNil():
127 | {.emit: "gtk_window_set_decorated(GTK_WINDOW(`myWebView`->priv.window), `decorated`);".}
128 |
129 | proc setFullscreen*(fullScreen: bool = true) {.exportc, exportpy.} =
130 | if not getInstance().webview.isNil():
131 | getInstance().webview.dispatch(proc() =
132 | discard getInstance().webview.setFullscreen(fullScreen))
133 |
134 | proc setColor*(r, g, b, alpha: uint8) {.exportc, exportpy.} =
135 | if not getInstance().webview.isNil():
136 | getInstance().webview.dispatch(proc() =
137 | getInstance().webview.setColor(r, g, b, alpha))
138 |
139 | proc setMaxSize*(width, height: int) {.exportpy.} =
140 | if not getInstance().webview.isNil():
141 | getInstance().webview.dispatch(proc() =
142 | getInstance().webview.setMaxSize(width.cint, height.cint))
143 |
144 | proc setMaxSize*(width, height: cint) {.exportc.} =
145 | setMaxSize(width.int, height.int)
146 |
147 | proc setMinSize*(width, height: int) {.exportpy.} =
148 | if not getInstance().webview.isNil():
149 | getInstance().webview.dispatch(proc() =
150 | getInstance().webview.setMinSize(width.cint, height.cint))
151 |
152 | proc setMinSize*(width, height: cint) {.exportc.} =
153 | setMinSize(width.int, height.int)
154 |
155 | proc focus*(width, height: int) {.exportpy, exportc.} =
156 | if not getInstance().webview.isNil():
157 | getInstance().webview.dispatch(proc() =
158 | getInstance().webview.focus())
159 |
160 | proc computeMessageWebview(message: string) {.used.} =
161 | info message
162 | if message.len == 0:
163 | nimviewSettings.run = false
164 | else:
165 | let jsonMessage = json.parseJson(message)
166 | let requestId = jsonMessage["requestId"].getInt()
167 | try:
168 | let response = dispatchJsonRequest(jsonMessage)
169 | let evalJsCode = "window.ui.applyResponse(" & $requestId & "," &
170 | response.escape("'","'") & ");"
171 | evalJs(evalJsCode)
172 | except:
173 | log.error getCurrentExceptionMsg()
174 | let evalJsCode = "window.ui.rejectResponse(" & $requestId & ");"
175 | evalJs(evalJsCode)
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | import sys, os, pathlib
2 | # print(pathlib.Path(os.path.abspath(__file__)).parent.parent)
3 | # sys.path.append(str(pathlib.Path(os.path.abspath(__file__)).parent.parent) + "/out")
4 | import nimview
--------------------------------------------------------------------------------
/tests/c_test.c:
--------------------------------------------------------------------------------
1 | /** Nimview UI Library
2 | * Copyright (C) 2020, 2021, by Marco Mengelkoch
3 | * Licensed under MIT License, see License file for more details
4 | * git clone https://github.com/marcomq/nimview
5 | **/
6 | // Important Notice: You should use --threads:on AND you need to avoid --gc:arc ; I had crashes on windows otherwise with NIM 1.4 when starting webview
7 |
8 | #include "../out/tmp_c/nimview.h"
9 | #include
10 | #include
11 |
12 | char* echoAndModify(char* something) {
13 | const char* appendString = " modified by C";
14 | char* result = malloc(strlen(something) + strlen(appendString) + 1); // +1 for the null-terminator, strlen is unchecked! "something" needs 0 termination
15 | if (result) {
16 | strcpy(result, something); // safe, result just created
17 | strcat(result, appendString); // safe, result just created with len
18 | }
19 | else {
20 | return ""; // "" will not be freed
21 | }
22 | return result;
23 | }
24 |
25 | char* stopNimview(char* something) {
26 | nimview_stopDesktop();
27 | return "";
28 | }
29 | int main(int argc, char* argv[]) {
30 | printf(" starting c code\n");
31 | NimMain();
32 | nimview_addRequest("echoAndModify", echoAndModify, free);
33 | nimview_addRequest("stopNimview", stopNimview, free);
34 |
35 | nimview_dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"value\":\"this is a test\",\"responseId\":0}");
36 | nimview_dispatchCommandLineArg("{\"request\":\"stopNimview\",\"value\":\"\",\"responseId\":1}");
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/tests/desktopSample.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | action: "compile"
3 | matrix: "; -d:just_core; -d:useWebviewSingleThreaded"
4 | cmd: "nim $target -f --hints:on -d:testing $file"
5 | """
6 | import ../src/nimview
7 | import os
8 |
9 | proc main() =
10 | nimview.add("echoAndModify", proc (value: string): string =
11 | echo value
12 | ## just simulating progress
13 | for i in 0..100:
14 | callJs("applyProgress", $(i) & "%")
15 | os.sleep(20)
16 | result = "'" & value & "' modified by Webview Backend")
17 | if not defined(just_core):
18 | nimview.startDesktop("../examples/minimal2/dist/index.html", run=false)
19 | nimview.setBorderless()
20 | nimview.setFullscreen()
21 | nimview.setColor(1,2,3,50)
22 | nimview.setIcon(currentSourcePath.parentDir() / "icon.ico") # will not be visible in fullscreen
23 | nimviewSettings.width = 600
24 | nimview.enableStorage()
25 | nimview.enableRequestLogger()
26 | nimview.disableRequestLogger()
27 | nimview.add("callJsProgress", proc () =
28 | echo nimview.selectFolderDialog("")
29 | )
30 | nimview.setUseServer(false)
31 | nimview.setUseGlobalToken(false)
32 | nimview.run()
33 |
34 | when isMainModule:
35 | main()
--------------------------------------------------------------------------------
/tests/httpSample.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | matrix: "; -d:just_core; -d:useServer"
3 | action: "compile"
4 | cmd: "nim $target -f --hints:on -d:testing $file"
5 | """
6 | import ../src/nimview
7 |
8 | add("appendSomething", proc (value: string): string =
9 | echo value
10 | result = "'" & value & "' modified by Web Backend"
11 | )
12 |
13 | add("appendSomething2", proc (value: string) =
14 | echo value
15 | )
16 |
17 | add("appendSomething3", proc (value: string, number: int) =
18 | echo value & $number
19 | )
20 |
21 | add("appendSomething4", proc (value: string, number: int): string =
22 | echo value & $number
23 | result = "'" & value & $number & "' modified by Web Backend"
24 | )
25 |
26 | add("appendSomething5", proc (value: string, number: int, number2: int): string =
27 | echo value & $number
28 | result = "'" & value & $number & $number2 & "' modified by Web Backend"
29 | )
30 |
31 | add("appendSomething6", proc (value: string, number: int, number2: int) =
32 | echo value & $number & $number2
33 | )
34 |
35 | add("appendSomething7", proc (number: int, number2: int): int =
36 | echo $number & $number2
37 | result = number + number2
38 | )
39 |
40 | add("appendSomething8", proc (value: string, value2: string, number: int, number2: int): int =
41 | echo value & $number & $number2 & value2
42 | result = number + number2
43 | )
44 |
45 | proc main() =
46 | if not defined(just_core):
47 | startHttpServer("../examples/minimal/dist/index.html")
48 |
49 | when isMainModule:
50 | main()
--------------------------------------------------------------------------------
/tests/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcomq/nimview/d6bf5ce39d710f6ed80f0ca320b93ee6323ae66f/tests/icon.ico
--------------------------------------------------------------------------------
/tests/nim.cfg:
--------------------------------------------------------------------------------
1 | --threads:on
--------------------------------------------------------------------------------
/tests/pyTest.py:
--------------------------------------------------------------------------------
1 | # Nimview UI Library
2 | # Copyright (C) 2020, 2021, by Marco Mengelkoch
3 | # Licensed under MIT License, see License file for more details
4 |
5 | # pylint: disable=import-error
6 | import __init__, nimview
7 | def echoAndModify(value):
8 | print (value)
9 | return (value + " appended by python")
10 |
11 | def echoAndModify2():
12 | print ("received nil")
13 | return (" appended by python")
14 |
15 | def echoAndModify3(value1, value2):
16 | result = value1 + " "+ value2 + " both received"
17 | print (result)
18 | return (result + " by python")
19 |
20 | def stopNimview(value):
21 | nimview.stopDesktop()
22 | return ""
23 |
24 | nimview.addRequest("echoAndModify", echoAndModify)
25 | nimview.addRequest("echoAndModify2", echoAndModify2)
26 | nimview.addRequest("echoAndModify3", echoAndModify3)
27 | nimview.addRequest("stopNimview", stopNimview)
28 |
29 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"value\":\"this is a test\",\"responseId\":0}")
30 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"value\":[],\"responseId\":3}") # will cause an error
31 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify2\",\"value\":[],\"responseId\":4}")
32 | nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify3\",\"value\":[\"first\",\"second\"],\"responseId\":5}")
33 | nimview.dispatchCommandLineArg("{\"request\":\"stopNimview\",\"value\":\"\",\"responseId\":6}")
34 | print ("python test passed")
35 | # nimview.startDesktop("tests/minimal_ui_sample/index.html")
36 |
--------------------------------------------------------------------------------
/tests/pyWebViewSample.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # pylint: disable=no-member
3 | import nimview
4 | import os, time
5 | import threading
6 |
7 | def threadedWait1():
8 | try:
9 | global thread
10 | thread = threading.Thread(target = asyncWait1, daemon=None)
11 | thread.start()
12 | except:
13 | print ("some other error")
14 | raise()
15 | return ("")
16 |
17 | def asyncWait1():
18 | try:
19 | print ("wait 1 start")
20 | time.sleep(1)
21 | print ("wait 1 running")
22 | time.sleep(1)
23 | print ("wait 1 still running")
24 | time.sleep(1)
25 | print ("wait 1 still running")
26 | time.sleep(5)
27 | print ("wait 1 end")
28 | except:
29 | print ("some error")
30 | raise()
31 | return ("")
32 |
33 | def wait2():
34 | print ("wait 2 start")
35 | time.sleep(2)
36 | print ("wait 2 end")
37 | return ("")
38 |
39 | def wait():
40 | time.sleep(0.002)
41 | return ("")
42 |
43 | nimview.addRequest("asyncWait1", threadedWait1)
44 | nimview.addRequest("wait2", wait2)
45 | nimview.addRequest("wait", wait)
46 | nimview.startDesktop("asyncPy/index.html")
47 | thread.join()
48 | # threadedWait1()
49 | # asyncWait2()
50 | # time.sleep(29)
--------------------------------------------------------------------------------
/tests/requestsFail.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | action: "run"
3 | cmd: "nim $target -f --hints:on -d:testing $file"
4 | output: '''
5 | WARN Error calling function, args: {"request":"echoAndModify","data":[],"responseId":0}
6 | WARN Error calling function, args: {"request":"echoAndModify3","data":["first"],"responseId":2}
7 | '''
8 | """
9 |
10 | import ../src/nimview
11 | import logging
12 |
13 | proc echoAndModify(value: string): string =
14 | return (value & " appended by nim")
15 |
16 | proc echoAndModify2(): string =
17 | return (" appended by python")
18 |
19 | proc echoAndModify3(value1, value2: string): string =
20 | result = value1 & " " & value2 & " both received"
21 |
22 | proc echoAndModify4(value1: string, value2: string, value3: int): string =
23 | result = value1 & " " & value2 & " " & $value3 & " received"
24 |
25 | proc stopNimview() =
26 | nimview.stop()
27 |
28 |
29 | proc main() =
30 | logging.getHandlers()[0].levelThreshold = lvlWarn
31 | nimview.add("echoAndModify", echoAndModify)
32 | nimview.add("echoAndModify2", echoAndModify2)
33 | nimview.add("echoAndModify3", echoAndModify3)
34 | nimview.add("echoAndModify4", echoAndModify4)
35 | nimview.add("stopNimview", stopNimview)
36 |
37 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"data\":[],\"responseId\":0}") # will print warning
38 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify2\",\"data\":[\"unused\"],\"responseId\":1}") # will currently not print warning
39 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify3\",\"data\":[\"first\"],\"responseId\":2}") # will print warning
40 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify4\",\"data\":[\"first\",2,3],\"responseId\":3}") # will currently not print warning, as 2 is converted to string
41 | discard nimview.dispatchCommandLineArg("{\"request\":\"stopNimview\",\"data\":[],\"responseId\":6}")
42 |
43 | when isMainModule:
44 | main()
--------------------------------------------------------------------------------
/tests/requestsSuccess.nim:
--------------------------------------------------------------------------------
1 | discard """
2 | action: "run"
3 | cmd: "nim $target --hints:on -d:testing $file"
4 | output: ""
5 | """
6 |
7 | import ../src/nimview
8 | import logging
9 | logging.getHandlers()[0].levelThreshold = lvlWarn
10 |
11 | proc echoAndModify(value: string): string =
12 | return (value & " appended by nim")
13 |
14 | proc echoAndModify2(): string =
15 | return (" appended by python")
16 |
17 | proc echoAndModify3(value1, value2: string): string =
18 | result = value1 & " " & value2 & " both received"
19 |
20 | proc echoAndModify4(value1: string, value2: string, value3: int): string =
21 | result = value1 & " " & value2 & " " & $value3 & " received"
22 |
23 | proc stopNimview() =
24 | nimview.stopDesktop()
25 |
26 |
27 | nimview.add("echoAndModify", echoAndModify)
28 | nimview.add("echoAndModify2", echoAndModify2)
29 | nimview.add("echoAndModify3", echoAndModify3)
30 | nimview.add("echoAndModify4", echoAndModify4)
31 | nimview.add("stopNimview", stopNimview)
32 |
33 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify\",\"data\":[\"this is a test\"],\"responseId\":0}")
34 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify2\",\"data\":[],\"responseId\":4}")
35 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify3\",\"data\":[\"first\",\"second\"],\"responseId\":5}")
36 | discard nimview.dispatchCommandLineArg("{\"request\":\"echoAndModify4\",\"data\":[\"first\",\"second\",3],\"responseId\":7}")
37 | discard nimview.dispatchCommandLineArg("{\"request\":\"stopNimview\",\"data\":[],\"responseId\":6}")
38 |
--------------------------------------------------------------------------------
/tests/test.dump:
--------------------------------------------------------------------------------
1 | {"request":"appendSomething","value":"gg","responseId":0}
2 | {"request":"appendSomething","value":"ff","responseId":1}
3 | {"request":"appendSomething","value":"vv","responseId":2}
--------------------------------------------------------------------------------