From 6247a750b5e569fa6a5e74e283bec4f2a3d1b657 Mon Sep 17 00:00:00 2001 From: Rijul Shrestha Date: Thu, 26 Mar 2026 11:26:43 +0000 Subject: [PATCH 1/6] Updated file system guides with the new upload/download functionality --- .../src/content/docs/11-guides/filesystem.mdx | 95 +++++++++---------- .../14-explanation/File-System-support.md | 17 +++- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx index 0e383920..97bce045 100644 --- a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx +++ b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx @@ -3,25 +3,35 @@ title: Filesystem description: Interacting with the virtual filesystem in CheerpJ --- -CheerpJ provides a **virtual filesystem** that allows Java applications to read and write files within a secure, browser-sandboxed environment. For browser security reasons, code running in the browser cannot access the user’s local disk directly. Instead, all file operations are confined to a virtual space, which provides multiple mounting points, each with a specific purpose and access model. +CheerpJ provides a **virtual filesystem** that allows Java applications to read and write files within a secure, browser-sandboxed environment. For browser security reasons, code running in the browser cannot access the user's local disk directly. Instead, all file operations are confined to a virtual space, which provides multiple mounting points, each with a specific purpose and access model. **Mounting points overview** - **`/app/`** — Read-only mount that points to the root of your web server. Java can read files using the `/app/` prefix. - **`/files/`** — A persistent, Java read-write area and the default mounting point for Java. JavaScript can read via CheerpJ APIs. + - **`/files/uploads/`** — Files uploaded from the local machine via the application's file picker land here automatically. + - **`/files/downloads/`** — Files saved here by Java are automatically downloaded to the user's local machine by the browser. - **`/str/`** — A transient mount used to pass data from JavaScript to Java. JavaScript can read and write, Java can only read. Not persisted. -If a file is served by your HTTP server (e.g., alongside your JARs), your Java code can read it via the `/app` prefix. For any other local files, it is necessary to load them into the virtual filesystem first, either via `/str` (inject from JavaScript) or `/files` (read/write at runtime). CheerpJ provides several ways to move files into and out of this virtual filesystem. +If a file is served by your HTTP server (e.g., alongside your JARs), your Java code can read it via the `/app` prefix. For any other local files, it is necessary to load them into the virtual filesystem first. CheerpJ provides several ways to move files into and out of this virtual filesystem, ranging from built-in UI interactions to JavaScript APIs. > For a detailed overview of mounting points (`/app/`, `/files/`, `/str/`) and how they work, see the **[File and Filesystem guide](/docs/explanation/File-System-support)**. -## Loading Files from JavaScript into the Virtual Filesystem +## Importing files to the virtual filesystem -While your application runs under **CheerpJ**, any page-provided assets must first be placed in the **virtual filesystem** for Java to access them. Expose them from JavaScript to the `/str/` mount using [`cheerpOSAddStringFile`](/docs/reference/cheerpOSAddStringFile) or [Library Mode](/docs/guides/implementing-native-libraries), and then read them from Java like regular files. +When the user needs to provide local files to the Java application, CheerpJ offers several methods to load them into the virtual filesystem. The simplest requires no custom code at all. -### Method 1: Using `cheerpOSAddStringFile` (string or binary). +### Method 1: Using the file picker upload button -The quickest way to place a file into CheerpJ’s virtual filesystem from JavaScript is `cheerpOSAddStringFile`. It’s ideal for string content and also supports binary data. +CheerpJ's built-in file picker dialog includes an **upload button** (upward arrow icon) in the top-right corner. Clicking it opens the browser's native file picker, allowing the user to select a file from their local machine. The selected file is automatically placed into **`/files/uploads/`** and becomes available to the Java application immediately. No JavaScript is required. + +To open or import an uploaded file from within the application, use the application's file picker and navigate to `/files/uploads/`, then select the file you want to load. + +This is the recommended method for applications that already use `JFileChooser` or any file open/import dialog, since the upload functionality is provided out of the box. + +### Method 2: Using `cheerpOSAddStringFile` (string or binary) + +The quickest way to place a file into CheerpJ's virtual filesystem from JavaScript is [`cheerpOSAddStringFile`](/docs/reference/cheerpOSAddStringFile). It's ideal for string content and also supports binary data via `Uint8Array`. **When to call it:** Invoke `cheerpOSAddStringFile` after `cheerpjInit()` finishes (i.e., once its Promise resolves). The API depends on the runtime and virtual filesystem being fully initialized. @@ -52,9 +62,9 @@ String text = Files.readString(Path.of("/str/fileName.txt")); System.out.println(text); ``` -### Method 2: Using library mode +### Method 3: Using library mode -When a file already lives under `/app/` but your Java code needs to read it as if it were in `/files/` (i.e., without the `/app/` prefix), use [Library Mode](/docs/guides/library-mode) to copy it across mounts. With [`cheerpjRunLibrary`](/docs/reference/cheerpjRunLibrary), you can invoke Java’s `java.nio.file` from JavaScript to copy the file from `/app/…` to `/files/…`, after which the application can open it using just its bare filename. +When a file already lives under `/app/` but your Java code needs to read it as if it were in `/files/` (i.e., without the `/app/` prefix), use [Library Mode](/docs/guides/library-mode) to copy it across mounts. With [`cheerpjRunLibrary`](/docs/reference/cheerpjRunLibrary), you can invoke Java's `java.nio.file` from JavaScript to copy the file from `/app/…` to `/files/…`, after which the application can open it using just its bare filename. ```js async function copyFileToFilesMountPoint() { @@ -88,13 +98,35 @@ copyFileToFilesMountPoint(); // without needing the /app/ prefix. ``` -## Getting a file from the virtual filesystem to JavaScript (i.e. the local file system) +## Downloading files from the virtual filesystem -When Java runs under **CheerpJ**, files are saved to the **virtual filesystem** (default **`/files/`**), not the user’s disk. You can expose these files to the page either directly from JavaScript or by handing off from Java to JavaScript via a native method. +When Java runs under **CheerpJ**, files are saved to the **virtual filesystem** (default **`/files/`**), not the user's disk. CheerpJ provides several ways to deliver these files to the user's local machine. -### Method 1: Using `cjFileBlob` +### Method 1: Saving to `/files/downloads/` -Use the JavaScript-accessible [cjFileBlob API](/docs/reference/cjFileBlob) to extract files from the virtual file system. Java writes the file into `/files/`, and JavaScript reads it and triggers a download. +The simplest way to offer a file download requires no custom JavaScript. Any file that the Java application saves under **`/files/downloads/`** is **automatically downloaded** to the user's local machine by the browser. + +When saving or exporting from within the application, make sure the destination path is `/files/downloads/`. For example, from Java: + +```java title="App.java" +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +// Writing to /files/downloads/ triggers an automatic browser download +File file = new File("/files/downloads/report.txt"); +try (FileWriter writer = new FileWriter(file)) { + writer.write("Report content here."); +} catch (IOException e) { + System.err.println("Error writing file: " + e.getMessage()); +} +``` + +If your application uses `JFileChooser` for save/export dialogs, the user can also navigate to `/files/downloads/` manually to trigger the browser download after saving. + +### Method 2: Using `cjFileBlob` + +Use the JavaScript-accessible [`cjFileBlob` API](/docs/reference/cjFileBlob) to extract files from the virtual filesystem and trigger a browser download programmatically. Java writes the file into `/files/`, and JavaScript reads it and triggers a download. ```html title="index.html" @@ -120,9 +152,9 @@ Use the JavaScript-accessible [cjFileBlob API](/docs/reference/cjFileBlob) to ex ``` -### Method 2: Call a JavaScript native method from Java +### Method 3: Call a JavaScript native method from Java -Use this when the **Java** code should decide when to save/preview/upload. Java writes the file to `/files/` and calls a native method (implemented in JavaScript) to perform the browser action. +Use this when the **Java** code should decide when to trigger the download. Java writes the file to `/files/` and calls a native method (implemented in JavaScript) to perform the browser action. **Java Writes the File and Calls a Native Method** @@ -149,7 +181,7 @@ try { **JavaScript Implements the Native Method and Downloads the File** -Now we’ll implement the [native method](/docs/guides/implementing-native-methods) `downloadFileFromCheerpJ` in JavaScript to process the file. The function receives the file path from Java, uses CheerpJ’s `cjFileBlob()` to get the file’s content, and then triggers a download using standard browser APIs. +Now we'll implement the [native method](/docs/guides/implementing-native-methods) `downloadFileFromCheerpJ` in JavaScript to process the file. The function receives the file path from Java, uses CheerpJ's `cjFileBlob()` to get the file's content, and then triggers a download using standard browser APIs. ```js // Native method implementation called from Java @@ -186,39 +218,6 @@ async function cj3init() { cj3init(); ``` -## Using Java's `JFileChooser` with CheerpJ - -`JFileChooser` works the same under CheerpJ, but it targets the **virtual filesystem**. By default the dialog opens in `/files/` mount (the writable, persistent area), so any file you open or save is referenced by a virtual file system path (e.g., `/files/report.txt`) rather than the user’s physical disk. - -Here is how the dialog looks like when you use `JFileChooser` with the default `/files/` mount point: -![](/docs/cheerpj3/assets/filechooser.png) - -You can still perform normal Java file operations with CheerpJ. The paths simply refer to the virtual filesystem rather than the user’s physical disk. - -To access local files, first import them into the virtual file system (see previous section). To save or download files to the user’s machine from Java, you can utilize a JavaScript native method again. - -**Java Source Code: `JFileChooser` and Download Logic** - -```js title="App.java" -public static native void downloadFileFromCheerpJ(String filePath); -/* -Rest of your Java code... -*/ -JFileChooser fileChooser = new JFileChooser(); -int result = fileChooser.showOpenDialog(null); - -// User confirmed file selection -if (result == JFileChooser.APPROVE_OPTION) { - File selectedFile = fileChooser.getSelectedFile(); - String filePath = selectedFile.getPath(); - - // Trigger the native JavaScript function that handles the file - downloadFileFromCheerpJ(filePath); -} -``` - -The JavaScript code for handling the download is essentially the same as the Step 3 code of **[Getting the file from the virtual file system to JavaScript](/docs/guides/filesystem#getting-a-file-from-the-virtual-file-system-to-javascript-ie-local-file-system)**. - ## Special Case: Applets using `showDocument()` For **Applets**, `AppletContext.showDocument()` can be used as a lightweight workaround to trigger downloads. This can be handy, but the **native-method approach** remains more flexible and robust for most cases. diff --git a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md index 1c5d4ac1..8c72003c 100644 --- a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md +++ b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md @@ -5,11 +5,11 @@ description: Virtual filesystems and how to use them CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multiple mount points: -| Mount | Description | Write | Read | -| --------- | ------------------------------------------------------------------ | --------- | ---- | -| `/app/` | An HTTP-based filesystem for loading files from the web server | No | Yes | -| `/files/` | A persistent read-write file system | Java only | Yes | -| `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | +| Mount | Description | Write | Read | +| --------- | ---------------------------------------------------------------------------- | --------- | ---- | +| `/app/` | An HTTP-based filesystem for loading files from the web server | No | Yes | +| `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | +| `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | ![](/docs/cheerpj3/assets/filesystem.png) @@ -51,6 +51,13 @@ OutputStream out = new FileOutputStream(file); out.close(); ``` +### Specialized directories + +Within the `/files/` mount point, there are two specialized directories for interacting with the user's local machine: + +- **`/files/uploads/`** — When a user uploads a file using the application's file picker (via the upward arrow icon), it is automatically placed here and becomes accessible to the Java application. +- **`/files/downloads/`** — Any file written to this directory by the Java application will be automatically downloaded by the browser to the user's local machine. + > [!tip] About data persistency > The data in this mount-point would persist even when closing the application and re-launching it. In the scenario of wiping out the browser's data or using the browser as "incognito" data will be evicted. This behaviour may vary depending in the browser used among other scenarios. From 7494cbf328b84357f9fd6e514936fe7602bf5990 Mon Sep 17 00:00:00 2001 From: Rijul Shrestha Date: Mon, 30 Mar 2026 12:01:25 +0100 Subject: [PATCH 2/6] Added upload bottom image and reference --- .../public/cheerpj3/assets/upload-btn.png | Bin 0 -> 18215 bytes .../src/content/docs/11-guides/filesystem.mdx | 4 +++- .../docs/14-explanation/File-System-support.md | 12 +++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 sites/cheerpj/public/cheerpj3/assets/upload-btn.png diff --git a/sites/cheerpj/public/cheerpj3/assets/upload-btn.png b/sites/cheerpj/public/cheerpj3/assets/upload-btn.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d64383b8ab7e9c7aa29d1f9ce1b2ea39c2cb60 GIT binary patch literal 18215 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%0D8!}f)X@WOapQN-Pi64v}ac>+up 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 SUt8eeHVmGwelF{r5}E*(-L6Rh literal 0 HcmV?d00001 diff --git a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx index 97bce045..b4c9a3c9 100644 --- a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx +++ b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx @@ -25,7 +25,9 @@ When the user needs to provide local files to the Java application, CheerpJ offe CheerpJ's built-in file picker dialog includes an **upload button** (upward arrow icon) in the top-right corner. Clicking it opens the browser's native file picker, allowing the user to select a file from their local machine. The selected file is automatically placed into **`/files/uploads/`** and becomes available to the Java application immediately. No JavaScript is required. -To open or import an uploaded file from within the application, use the application's file picker and navigate to `/files/uploads/`, then select the file you want to load. +![Upload button](/docs/cheerpj3/assets/upload-btn.png) + +Files imported this way will be available in the virtual `/files/uploads/` directory. Please note that files imported to `/files/uploads/` are not persistent and will be gone upon browser restart. This is the recommended method for applications that already use `JFileChooser` or any file open/import dialog, since the upload functionality is provided out of the box. diff --git a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md index 8c72003c..01997640 100644 --- a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md +++ b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md @@ -11,6 +11,13 @@ CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multi | `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | | `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | +### Directories + +| Directory | Description | Persistent | +| ------------------- | ------------------------------------------------------------------- | ---------- | +| `/files/uploads/` | Files uploaded via the application's file picker | No | +| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Yes | + ![](/docs/cheerpj3/assets/filesystem.png) > [!info] Local files @@ -55,7 +62,10 @@ out.close(); Within the `/files/` mount point, there are two specialized directories for interacting with the user's local machine: -- **`/files/uploads/`** — When a user uploads a file using the application's file picker (via the upward arrow icon), it is automatically placed here and becomes accessible to the Java application. +- **`/files/uploads/`** — When a user uploads a file using the application's file picker (via the upward arrow icon), it is automatically placed here and becomes accessible to the Java application. Please note that this directory is **not persistent** and its contents will be gone upon browser restart. + +![Upload button](/docs/cheerpj3/assets/upload-btn.png) + - **`/files/downloads/`** — Any file written to this directory by the Java application will be automatically downloaded by the browser to the user's local machine. > [!tip] About data persistency From b4c2da09b6988616382e252635907311145b4ee9 Mon Sep 17 00:00:00 2001 From: Rijul Shrestha Date: Mon, 30 Mar 2026 14:26:59 +0100 Subject: [PATCH 3/6] Implemented feedback (updated wording and context) --- .../src/content/docs/11-guides/filesystem.mdx | 17 +++++------ .../14-explanation/File-System-support.md | 28 +++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx index b4c9a3c9..824cab80 100644 --- a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx +++ b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx @@ -9,8 +9,8 @@ CheerpJ provides a **virtual filesystem** that allows Java applications to read - **`/app/`** — Read-only mount that points to the root of your web server. Java can read files using the `/app/` prefix. - **`/files/`** — A persistent, Java read-write area and the default mounting point for Java. JavaScript can read via CheerpJ APIs. - - **`/files/uploads/`** — Files uploaded from the local machine via the application's file picker land here automatically. - - **`/files/downloads/`** — Files saved here by Java are automatically downloaded to the user's local machine by the browser. + - **`/files/uploads/`** — Files uploaded from the local machine via the upload button on any Java window's title bar land here automatically. + - **`/files/downloads/`** — Files saved here by Java are automatically downloaded to the user's local machine (into the browser's default download directory). - **`/str/`** — A transient mount used to pass data from JavaScript to Java. JavaScript can read and write, Java can only read. Not persisted. If a file is served by your HTTP server (e.g., alongside your JARs), your Java code can read it via the `/app` prefix. For any other local files, it is necessary to load them into the virtual filesystem first. CheerpJ provides several ways to move files into and out of this virtual filesystem, ranging from built-in UI interactions to JavaScript APIs. @@ -21,15 +21,16 @@ If a file is served by your HTTP server (e.g., alongside your JARs), your Java c When the user needs to provide local files to the Java application, CheerpJ offers several methods to load them into the virtual filesystem. The simplest requires no custom code at all. -### Method 1: Using the file picker upload button +### Method 1: Using the window title bar upload button -CheerpJ's built-in file picker dialog includes an **upload button** (upward arrow icon) in the top-right corner. Clicking it opens the browser's native file picker, allowing the user to select a file from their local machine. The selected file is automatically placed into **`/files/uploads/`** and becomes available to the Java application immediately. No JavaScript is required. +Any CheerpJ window with a title bar includes an **upload button** (upward arrow icon) in the top-right corner. Clicking it opens the browser's native file picker, allowing the user to select a file from their local machine. The selected file is automatically placed into **`/files/uploads/`** and becomes available to the Java application immediately. No JavaScript is required. -![Upload button](/docs/cheerpj3/assets/upload-btn.png) +
![](/docs/cheerpj3/assets/upload-btn.png)
-Files imported this way will be available in the virtual `/files/uploads/` directory. Please note that files imported to `/files/uploads/` are not persistent and will be gone upon browser restart. +> [!info] Uploads are not persistent +> Files imported this way will be available in the virtual `/files/uploads/` directory. Please note that files imported to `/files/uploads/` are not persistent and will be gone upon browser restart. -This is the recommended method for applications that already use `JFileChooser` or any file open/import dialog, since the upload functionality is provided out of the box. +While this upload button is present on all windows with a title bar, using it from a `JFileChooser` or any file open/import dialog is often the most convenient approach, as users are already intending to interact with files in that context. ### Method 2: Using `cheerpOSAddStringFile` (string or binary) @@ -106,7 +107,7 @@ When Java runs under **CheerpJ**, files are saved to the **virtual filesystem** ### Method 1: Saving to `/files/downloads/` -The simplest way to offer a file download requires no custom JavaScript. Any file that the Java application saves under **`/files/downloads/`** is **automatically downloaded** to the user's local machine by the browser. +The simplest way to offer a file download requires no custom JavaScript. Any file that the Java application saves under **`/files/downloads/`** is **automatically downloaded** to the user's local machine (into the browser's default download directory). When saving or exporting from within the application, make sure the destination path is `/files/downloads/`. For example, from Java: diff --git a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md index 01997640..ad0fe896 100644 --- a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md +++ b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md @@ -11,15 +11,17 @@ CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multi | `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | | `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | -### Directories +| Directory | Description | Persistent | Write | Read | +| ------------------- | ------------------------------------------------------------------- | ---------- | ----- | ---- | +| `/files/uploads/` | Files uploaded via the window title bar upload button | No | Yes | Yes | +| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Yes | Yes | Yes | -| Directory | Description | Persistent | -| ------------------- | ------------------------------------------------------------------- | ---------- | -| `/files/uploads/` | Files uploaded via the application's file picker | No | -| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Yes | +
![](/docs/cheerpj3/assets/filesystem.png) +
+ > [!info] Local files > CheerpJ provides access to a virtualized filesystem, which does not correspond to the local user's computer. Accessing local files directly is forbidden for browser security reasons. @@ -58,20 +60,24 @@ OutputStream out = new FileOutputStream(file); out.close(); ``` +> [!tip] About data persistency +> The data in this mount-point would persist even when closing the application and re-launching it. In the scenario of wiping out the browser's data or using the browser as "incognito" data will be evicted. This behaviour may vary depending in the browser used among other scenarios. + +For more information about browser's data eviction and persistency please visit [this page](https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria#when_is_data_evicted). + ### Specialized directories Within the `/files/` mount point, there are two specialized directories for interacting with the user's local machine: -- **`/files/uploads/`** — When a user uploads a file using the application's file picker (via the upward arrow icon), it is automatically placed here and becomes accessible to the Java application. Please note that this directory is **not persistent** and its contents will be gone upon browser restart. +- **`/files/uploads/`** — When a user uploads a file using the upload icon that is present in the title bar of any decorated window in Java (via the upward arrow icon in the title bar), it is automatically placed here and becomes accessible to the Java application. Please note that this directory is **not persistent** and its contents will be gone upon browser restart. + +
![Upload button](/docs/cheerpj3/assets/upload-btn.png) -- **`/files/downloads/`** — Any file written to this directory by the Java application will be automatically downloaded by the browser to the user's local machine. +
-> [!tip] About data persistency -> The data in this mount-point would persist even when closing the application and re-launching it. In the scenario of wiping out the browser's data or using the browser as "incognito" data will be evicted. This behaviour may vary depending in the browser used among other scenarios. - -For more information about browser's data eviction and persistency please visit [this page](https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria#when_is_data_evicted). +- **`/files/downloads/`** — Any file written to this directory by the Java application will be automatically downloaded to the default download location of the browser. ## `/str/` mount point From f63fc390e36124ab771cb23c4eb1abadb4c43bcd Mon Sep 17 00:00:00 2001 From: Rijul Shrestha Date: Tue, 31 Mar 2026 12:56:46 +0100 Subject: [PATCH 4/6] Updated table --- .../14-explanation/File-System-support.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md index ad0fe896..32d55525 100644 --- a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md +++ b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md @@ -5,16 +5,16 @@ description: Virtual filesystems and how to use them CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multiple mount points: -| Mount | Description | Write | Read | -| --------- | ---------------------------------------------------------------------------- | --------- | ---- | -| `/app/` | An HTTP-based filesystem for loading files from the web server | No | Yes | -| `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | -| `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | - -| Directory | Description | Persistent | Write | Read | -| ------------------- | ------------------------------------------------------------------- | ---------- | ----- | ---- | -| `/files/uploads/` | Files uploaded via the window title bar upload button | No | Yes | Yes | -| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Yes | Yes | Yes | +| Mount | Description | Write | Read | +| ------------------- | ---------------------------------------------------------------------------- | --------- | ---- | +| `/app/` | An HTTP-based filesystem for loading files from the web server | No | Yes | +| `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | +| `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | + +| Directory | Description | Write | Read | +| ------------------- | ---------------------------------------------------------------------------- | --------- | ---- | +| `/files/uploads/` | Files uploaded via the window title bar upload button, non persistent | No | Yes | +| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Java only | Yes |
From 347def856b923ed8831b9d7e2732bd1d514944e7 Mon Sep 17 00:00:00 2001 From: Rijul Shrestha Date: Tue, 31 Mar 2026 13:02:18 +0100 Subject: [PATCH 5/6] Table prettier check --- .../14-explanation/File-System-support.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md index 32d55525..a0fbbc4e 100644 --- a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md +++ b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md @@ -5,16 +5,16 @@ description: Virtual filesystems and how to use them CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multiple mount points: -| Mount | Description | Write | Read | -| ------------------- | ---------------------------------------------------------------------------- | --------- | ---- | -| `/app/` | An HTTP-based filesystem for loading files from the web server | No | Yes | -| `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | -| `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | - -| Directory | Description | Write | Read | -| ------------------- | ---------------------------------------------------------------------------- | --------- | ---- | -| `/files/uploads/` | Files uploaded via the window title bar upload button, non persistent | No | Yes | -| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Java only | Yes | +| Mount | Description | Write | Read | +| --------- | ---------------------------------------------------------------------------- | --------- | ---- | +| `/app/` | An HTTP-based filesystem for loading files from the web server | No | Yes | +| `/files/` | A persistent read-write file system (includes `/uploads/` and `/downloads/`) | Java only | Yes | +| `/str/` | A filesystem for passing JavaScript strings or binary data to Java | JS only | Yes | + +| Directory | Description | Write | Read | +| ------------------- | --------------------------------------------------------------------- | --------- | ---- | +| `/files/uploads/` | Files uploaded via the window title bar upload button, non persistent | No | Yes | +| `/files/downloads/` | Files saved here are automatically downloaded to the user's machine | Java only | Yes |
From 8382ede90bc5e2b61274668a63eee16f4f13ccbf Mon Sep 17 00:00:00 2001 From: Rijul Shrestha Date: Wed, 1 Apr 2026 18:12:16 +0100 Subject: [PATCH 6/6] Added directory tree structure --- .../cheerpj/src/content/docs/11-guides/filesystem.mdx | 11 +++++++++++ .../docs/14-explanation/File-System-support.md | 11 ++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx index 824cab80..50e84756 100644 --- a/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx +++ b/sites/cheerpj/src/content/docs/11-guides/filesystem.mdx @@ -7,6 +7,17 @@ CheerpJ provides a **virtual filesystem** that allows Java applications to read **Mounting points overview** +The virtual filesystem structure looks like this: + +```text +/ +├── app/ +├── files/ +│ ├── downloads/ +│ └── uploads/ +└── str/ +``` + - **`/app/`** — Read-only mount that points to the root of your web server. Java can read files using the `/app/` prefix. - **`/files/`** — A persistent, Java read-write area and the default mounting point for Java. JavaScript can read via CheerpJ APIs. - **`/files/uploads/`** — Files uploaded from the local machine via the upload button on any Java window's title bar land here automatically. diff --git a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md index a0fbbc4e..c7057d9e 100644 --- a/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md +++ b/sites/cheerpj/src/content/docs/14-explanation/File-System-support.md @@ -3,7 +3,16 @@ title: Files and filesystems description: Virtual filesystems and how to use them --- -CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multiple mount points: +CheerpJ filesystems are implemented as UNIX-style virtual filesystems with multiple mount points. The folder structure looks like this: + +```text +/ +├── app/ +├── files/ +│ ├── downloads/ +│ └── uploads/ +└── str/ +``` | Mount | Description | Write | Read | | --------- | ---------------------------------------------------------------------------- | --------- | ---- |