# Steps to Add FileManager Integration and Browser Storage to PaperScape Apps

This guide shows how to add FileManager integration, browser storage support, and persistent save location tracking to PaperScape Giraffe apps, using the centralized PaperScape.fileManager API.

## Prerequisites

1. The app must have `toJson()` and `fromJson()` methods for serializing/deserializing state
2. The app must be a Giraffe app loaded via PaperScape
3. PaperScape must be loaded (provides centralized FileManager integration)

## Step 1: Add Storage Location State Variables

In your app's constructor, add these instance variables:

```javascript
self.storagePath = "/YourAppName/default-state.json";  // Default path
self.storageIsBrowser = true;  // Default to browser storage
```

## Step 2: Add Path Cleaning Helper Function

Use PaperScape's centralized path cleaning utility:

```javascript
var updateStoragePath = function(path) {
  if(typeof path !== "string") {
    self.storagePath = "";
    return self.storagePath;
  }
  // Use PaperScape's centralized path cleaning utility
  var cleaned = controllerRef && controllerRef.storage ? controllerRef.storage.cleanPath(path) : path.trim();
  self.storagePath = cleaned;
  return self.storagePath;
};
```

## Step 3: Update toJson() to Include Storage Metadata

Modify your `toJson()` method to include storage location:

```javascript
self.toJson = function() {
  var json = {
    // ... your existing state properties ...
  };

  // Include storage location metadata if available
  if(self.storagePath && self.storagePath !== DEFAULT_PATH) {
    json.storagePath = self.storagePath;
    json.storageIsBrowser = self.storageIsBrowser;
  }

  return json;
};
```

## Step 4: Update fromJson() to Restore Storage Metadata

Modify your `fromJson()` method to restore storage location:

```javascript
self.fromJson = function(jsonData) {
  if(!jsonData || typeof jsonData !== "object") {
    console.error("Invalid JSON data provided");
    return;
  }

  // ... restore your existing state properties ...

  // Restore storage location metadata if present
  if(jsonData.storagePath) {
    updateStoragePath(jsonData.storagePath);
    self.storageIsBrowser = jsonData.storageIsBrowser || false;
    console.log("[YourApp] Restored storage location from JSON:", jsonData.storagePath, "isBrowser:", self.storageIsBrowser);
  } else {
    console.log("[YourApp] No storage location in JSON - file will save to default path unless you use 'Save As'");
  }

  // ... continue with rendering ...
};
```

## Step 5: Implement saveToFile() Method

Add this method to handle saving to both browser and server storage:

```javascript
self.saveToFile = function(targetPath, isBrowser) {
  var path = (typeof targetPath === "string" && targetPath.trim().length) ? targetPath.trim() : self.storagePath;
  if(!path || !path.length) {
    alert("Please provide a file path to save.");
    return;
  }

  // Use stored value if isBrowser is not explicitly provided
  var useBrowser = (typeof isBrowser !== 'undefined') ? isBrowser : self.storageIsBrowser;

  // Update stored value when explicitly provided
  if(typeof isBrowser !== 'undefined') {
    self.storageIsBrowser = isBrowser;
  }

  updateStoragePath(path);

  var snapshot = self.toJson();
  var payload = JSON.stringify(snapshot, null, 2);

  // Save to browser storage if useBrowser is true
  if(useBrowser) {
    if(typeof OpenForum !== "undefined" && typeof OpenForum.saveFile === "function") {
      var browserPath = 'browser://' + path;
      OpenForum.saveFile(browserPath, payload, function(response) {
        if(response && response.saved) {
          console.log("[YourApp] Saved to browser storage: " + path);
        } else {
          alert("Failed to save to browser storage: " + path);
        }
      });
    } else {
      alert("Browser storage is not available");
    }
    return;
  }

  // Save to server
  if(typeof OpenForum !== "undefined" && typeof OpenForum.saveFile === "function") {
    OpenForum.saveFile(path, payload, function(response) {
      if(response && response.result === "ok") {
        console.log("[YourApp] Saved to server: " + path);
      } else {
        alert("Failed to save to " + path);
      }
    });
  }
};
```

## Step 6: Implement loadFromFile() Method

Add this method to handle loading from both browser and server storage:

```javascript
self.loadFromFile = function(targetPath, isBrowser) {
  var path = (typeof targetPath === "string" && targetPath.trim().length) ? targetPath.trim() : self.storagePath;
  if(!path || !path.length) {
    alert("Please provide a file path to load.");
    return;
  }

  // Build the full path with browser:// prefix if needed
  var loadPath = path;
  if(isBrowser && !path.startsWith('browser://')) {
    loadPath = 'browser://' + path;
  }

  if(typeof OpenForum !== "undefined" && typeof OpenForum.loadJSON === "function") {
    OpenForum.loadJSON(loadPath, function(json) {
      if(!json) {
        alert("No data found at " + path);
        return;
      }

      self.fromJson(json);

      // Set storage path AFTER fromJson to ensure it's not overwritten
      updateStoragePath(path);
      if(typeof isBrowser !== 'undefined') {
        self.storageIsBrowser = isBrowser;
      }

      console.log("[YourApp] Loaded from " + loadPath + " (isBrowser: " + isBrowser + ")");
      console.log("[YourApp] Storage location set to:", self.storagePath, "isBrowser:", self.storageIsBrowser);
    });
  } else {
    alert("OpenForum.loadJSON not available");
  }
};
```

## Step 7: Add UI Methods for Save As and Open

Use the centralized PaperScape.fileManager API:

```javascript
self.saveModelAs = function() {
  // Use centralized PaperScape FileManager
  if(controllerRef && controllerRef.fileManager && typeof controllerRef.fileManager.showSave === "function") {
    var currentFilename = self.storagePath ? self.storagePath.substring(self.storagePath.lastIndexOf('/') + 1) : 'default.json';
    controllerRef.fileManager.showSave(self, currentFilename);
  } else {
    alert("FileManager is not available");
  }
};

self.openModel = function() {
  // Use centralized PaperScape FileManager
  if(controllerRef && controllerRef.fileManager && typeof controllerRef.fileManager.showLoad === "function") {
    controllerRef.fileManager.showLoad(self);
  } else {
    alert("FileManager is not available");
  }
};
```

## Step 8: Add UI Buttons

Add buttons to your app's control panel or UI. These can call the methods directly:

```javascript
html += '<button onclick="yourAppInstance.saveModelAs()">Save As</button>';
html += '<button onclick="yourAppInstance.openModel()">Open</button>';
```

Or if using PaperScape dialog system, add them as dialog actions.

## Important Notes

### Path Handling Rules

1. **Never store `browser://` prefix in `self.storagePath`** - it should only contain the path
2. **Always add `browser://` prefix when calling `OpenForum.saveFile()` or `OpenForum.loadFile()` for browser storage**
3. **Use `controllerRef.storage.cleanPath()`** to strip prefixes and clean up paths
4. **Use `isBrowser` flag** to track whether storage is browser or server

### Auto-Save Behavior

If your app has auto-save, make sure it uses the stored `isBrowser` flag:

```javascript
function autoSave() {
  // Don't pass isBrowser parameter - let saveToFile use stored value
  self.saveToFile(self.storagePath);
}
```

### Testing Checklist

- [ ] "Save As" to browser storage creates file with key like `/FolderName/filename.json`
- [ ] "Save As" to server storage saves to server path
- [ ] After "Save As" to browser, auto-save continues to browser storage
- [ ] After "Save As" to server, auto-save continues to server storage
- [ ] Opening a file from browser storage remembers location for future saves
- [ ] Opening a file from server storage remembers location for future saves
- [ ] Closing and reopening an app preserves the save location via PaperScape state

## Example: Setting Browser Storage as Default

To make your app default to browser storage:

```javascript
var DEFAULT_PATH = "/YourAppName/default-state.json";

// In constructor:
self.storagePath = DEFAULT_PATH;
self.storageIsBrowser = true;  // Default to browser storage
```

## Centralized PaperScape.fileManager API

The PaperScape framework provides centralized FileManager integration:

### `PaperScape.fileManager.showSave(appInstance, currentFilename)`
Shows FileManager in save mode. Your app must implement `saveToFile(path, isBrowser)`.

### `PaperScape.fileManager.showLoad(appInstance)`
Shows FileManager in open mode. Your app must implement `loadFromFile(path, isBrowser)`.

### `PaperScape.fileManager.close()`
Closes the FileManager popup.

### `PaperScape.fileManager.isAvailable()`
Returns true if FileManager is available.

### `PaperScape.storage.cleanPath(path)`
Cleans a path by removing `browser://` prefix and extra leading slashes.

### `PaperScape.storage.browserPath(path)`
Builds a browser storage URL by adding `browser://` prefix to a cleaned path.

## Building Your App

After making changes to your Giraffe app source files, rebuild using:

```
http://localhost:8888/OpenForum/AddOn/ServiceBuilder?action=buildJavascript&pageName=/YourAppPage&fileName=script.build.json
```

## Additional Resources

- FileManager API: `/Development/OpenForum/AddOn/FileManager/`
- OpenForum Browser Storage: `/OpenForum/Javascript/Core/open-forum-browser.js`
- PaperScape Core: `/OpenForum/AddOn/PaperScape/paperscape.js` (lines 802-934)
- DependencyModelView Reference: `/OpenForum/AddOn/PaperScape/DependencyModelView/dependency-model-view-core.giraffe.js`
