@willwade/aac-processors 0.0.30 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -852
- package/dist/browser/core/baseProcessor.js +241 -0
- package/dist/browser/core/stringCasing.js +179 -0
- package/dist/browser/core/treeStructure.js +255 -0
- package/dist/browser/index.browser.js +73 -0
- package/dist/browser/processors/applePanelsProcessor.js +582 -0
- package/dist/browser/processors/astericsGridProcessor.js +1509 -0
- package/dist/browser/processors/dotProcessor.js +221 -0
- package/dist/browser/processors/gridset/commands.js +962 -0
- package/dist/browser/processors/gridset/crypto.js +53 -0
- package/dist/browser/processors/gridset/password.js +49 -0
- package/dist/browser/processors/gridset/pluginTypes.js +277 -0
- package/dist/browser/processors/gridset/resolver.js +137 -0
- package/dist/browser/processors/gridset/symbolAlignment.js +276 -0
- package/dist/browser/processors/gridset/symbols.js +464 -0
- package/dist/browser/processors/gridsetProcessor.js +2002 -0
- package/dist/browser/processors/obfProcessor.js +705 -0
- package/dist/browser/processors/opmlProcessor.js +274 -0
- package/dist/browser/types/aac.js +38 -0
- package/dist/browser/utilities/analytics/utils/idGenerator.js +89 -0
- package/dist/browser/utilities/translation/translationProcessor.js +200 -0
- package/dist/browser/utils/io.js +95 -0
- package/dist/browser/validation/baseValidator.js +156 -0
- package/dist/browser/validation/gridsetValidator.js +356 -0
- package/dist/browser/validation/obfValidator.js +500 -0
- package/dist/browser/validation/validationTypes.js +46 -0
- package/dist/cli/index.js +5 -5
- package/dist/core/analyze.d.ts +2 -2
- package/dist/core/analyze.js +2 -2
- package/dist/core/baseProcessor.d.ts +5 -4
- package/dist/core/baseProcessor.js +22 -27
- package/dist/core/treeStructure.d.ts +5 -5
- package/dist/core/treeStructure.js +1 -4
- package/dist/index.browser.d.ts +37 -0
- package/dist/index.browser.js +99 -0
- package/dist/index.d.ts +1 -48
- package/dist/index.js +1 -136
- package/dist/index.node.d.ts +48 -0
- package/dist/index.node.js +152 -0
- package/dist/processors/applePanelsProcessor.d.ts +5 -4
- package/dist/processors/applePanelsProcessor.js +58 -62
- package/dist/processors/astericsGridProcessor.d.ts +7 -6
- package/dist/processors/astericsGridProcessor.js +31 -42
- package/dist/processors/dotProcessor.d.ts +5 -4
- package/dist/processors/dotProcessor.js +25 -33
- package/dist/processors/excelProcessor.d.ts +4 -3
- package/dist/processors/excelProcessor.js +6 -3
- package/dist/processors/gridset/crypto.d.ts +18 -0
- package/dist/processors/gridset/crypto.js +57 -0
- package/dist/processors/gridset/helpers.d.ts +1 -1
- package/dist/processors/gridset/helpers.js +18 -8
- package/dist/processors/gridset/password.d.ts +20 -3
- package/dist/processors/gridset/password.js +29 -12
- package/dist/processors/gridset/symbols.js +63 -46
- package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
- package/dist/processors/gridset/wordlistHelpers.js +21 -20
- package/dist/processors/gridsetProcessor.d.ts +7 -12
- package/dist/processors/gridsetProcessor.js +116 -77
- package/dist/processors/obfProcessor.d.ts +9 -7
- package/dist/processors/obfProcessor.js +131 -56
- package/dist/processors/obfsetProcessor.d.ts +5 -4
- package/dist/processors/obfsetProcessor.js +10 -16
- package/dist/processors/opmlProcessor.d.ts +5 -4
- package/dist/processors/opmlProcessor.js +27 -34
- package/dist/processors/snapProcessor.d.ts +8 -7
- package/dist/processors/snapProcessor.js +15 -12
- package/dist/processors/touchchatProcessor.d.ts +8 -7
- package/dist/processors/touchchatProcessor.js +22 -17
- package/dist/types/aac.d.ts +0 -2
- package/dist/types/aac.js +2 -0
- package/dist/utils/io.d.ts +12 -0
- package/dist/utils/io.js +107 -0
- package/dist/validation/gridsetValidator.js +10 -9
- package/dist/validation/snapValidator.js +28 -35
- package/docs/BROWSER_USAGE.md +618 -0
- package/docs/PAGESET_GETTING_STARTED.md +185 -0
- package/examples/README.md +77 -0
- package/examples/browser-test-server.js +81 -0
- package/examples/browser-test.html +331 -0
- package/examples/vitedemo/QUICKSTART.md +75 -0
- package/examples/vitedemo/README.md +157 -0
- package/examples/vitedemo/index.html +531 -0
- package/examples/vitedemo/package-lock.json +1221 -0
- package/examples/vitedemo/package.json +18 -0
- package/examples/vitedemo/src/main.ts +871 -0
- package/examples/vitedemo/test-files/example.dot +14 -0
- package/examples/vitedemo/test-files/example.grd +1 -0
- package/examples/vitedemo/test-files/example.gridset +0 -0
- package/examples/vitedemo/test-files/example.obz +0 -0
- package/examples/vitedemo/test-files/example.opml +18 -0
- package/examples/vitedemo/test-files/simple.obf +53 -0
- package/examples/vitedemo/tsconfig.json +24 -0
- package/examples/vitedemo/vite.config.ts +34 -0
- package/package.json +21 -4
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
# Browser Usage Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to use AACProcessors in browser environments.
|
|
4
|
+
|
|
5
|
+
## ⚠️ Important: Bundler Required
|
|
6
|
+
|
|
7
|
+
**AACProcessors uses TypeScript and outputs CommonJS modules, which requires a bundler for browser use.**
|
|
8
|
+
|
|
9
|
+
You **cannot** directly import from `dist/index.browser.js` in a browser without a bundler.
|
|
10
|
+
|
|
11
|
+
### Recommended Bundlers
|
|
12
|
+
|
|
13
|
+
- **Vite** (recommended, easiest setup)
|
|
14
|
+
- **Webpack**
|
|
15
|
+
- **Rollup**
|
|
16
|
+
- **esbuild**
|
|
17
|
+
- **Parcel**
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @willwade/aac-processors
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start with Vite
|
|
26
|
+
|
|
27
|
+
### 1. Create a Vite Project
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm create vite@latest my-aac-app -- --template vanilla-ts
|
|
31
|
+
cd my-aac-app
|
|
32
|
+
npm install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Install AACProcessors
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install @willwade/aac-processors
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. Configure Vite
|
|
42
|
+
|
|
43
|
+
Create `vite.config.ts`:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { defineConfig } from 'vite';
|
|
47
|
+
import path from 'path';
|
|
48
|
+
|
|
49
|
+
export default defineConfig({
|
|
50
|
+
resolve: {
|
|
51
|
+
alias: {
|
|
52
|
+
'aac-processors': path.resolve(__dirname, 'node_modules/@willwade/aac-processors/src/index.browser.ts')
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 4. Use in Your Code
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// src/main.ts
|
|
62
|
+
import { getProcessor } from 'aac-processors';
|
|
63
|
+
|
|
64
|
+
async function loadFile(file: File) {
|
|
65
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
66
|
+
const processor = getProcessor('.obf');
|
|
67
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
68
|
+
console.log('Loaded tree:', tree);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Use with file input
|
|
72
|
+
document.getElementById('fileInput')?.addEventListener('change', async (e) => {
|
|
73
|
+
const file = (e.target as HTMLInputElement).files?.[0];
|
|
74
|
+
if (file) {
|
|
75
|
+
await loadFile(file);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 5. Run the Dev Server
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm run dev
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Quick Start with Webpack
|
|
87
|
+
|
|
88
|
+
### 1. Install Dependencies
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install @willwade/aac-processors webpack webpack-cli ts-loader
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 2. Configure Webpack
|
|
95
|
+
|
|
96
|
+
Create `webpack.config.js`:
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const path = require('path');
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
mode: 'development',
|
|
103
|
+
entry: './src/index.ts',
|
|
104
|
+
output: {
|
|
105
|
+
filename: 'bundle.js',
|
|
106
|
+
path: path.resolve(__dirname, 'dist')
|
|
107
|
+
},
|
|
108
|
+
resolve: {
|
|
109
|
+
extensions: ['.ts', '.js'],
|
|
110
|
+
alias: {
|
|
111
|
+
'aac-processors': path.resolve(__dirname, 'node_modules/@willwade/aac-processors/src/index.browser.ts')
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
module: {
|
|
115
|
+
rules: [
|
|
116
|
+
{
|
|
117
|
+
test: /\.ts$/,
|
|
118
|
+
use: 'ts-loader',
|
|
119
|
+
exclude: /node_modules/
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 3. Use in Your Code
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// src/index.ts
|
|
130
|
+
import { getProcessor } from 'aac-processors';
|
|
131
|
+
|
|
132
|
+
// Same usage as Vite example above
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Using with CDN (Not Recommended)
|
|
136
|
+
|
|
137
|
+
While you can use the library via CDN, it's **not recommended** because:
|
|
138
|
+
|
|
139
|
+
1. The library is not currently published as an ESM bundle
|
|
140
|
+
2. You'll need to use a compatibility layer like SystemJS
|
|
141
|
+
3. TypeScript types won't work properly
|
|
142
|
+
|
|
143
|
+
For production use, **always use a bundler**.
|
|
144
|
+
|
|
145
|
+
## Basic Usage
|
|
146
|
+
|
|
147
|
+
### Loading a File from File Input
|
|
148
|
+
|
|
149
|
+
The most common browser use case is loading files from an `<input type="file">` element:
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<input type="file" id="fileInput" accept=".obf,.obz,.gridset,.dot,.opml">
|
|
153
|
+
<script type="module">
|
|
154
|
+
import { getProcessor } from 'aac-processors';
|
|
155
|
+
|
|
156
|
+
const fileInput = document.getElementById('fileInput');
|
|
157
|
+
|
|
158
|
+
fileInput.addEventListener('change', async (event) => {
|
|
159
|
+
const file = event.target.files[0];
|
|
160
|
+
if (!file) return;
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
// Get file extension
|
|
164
|
+
const extension = '.' + file.name.split('.').pop();
|
|
165
|
+
|
|
166
|
+
// Get appropriate processor
|
|
167
|
+
const processor = getProcessor(extension);
|
|
168
|
+
|
|
169
|
+
if (!processor) {
|
|
170
|
+
console.error('No processor found for:', extension);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Read file as ArrayBuffer
|
|
175
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
176
|
+
|
|
177
|
+
// Load into tree
|
|
178
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
179
|
+
|
|
180
|
+
console.log('Loaded tree:', tree);
|
|
181
|
+
console.log('Pages:', Object.keys(tree.pages));
|
|
182
|
+
console.log('Root page:', tree.pages[tree.rootId]);
|
|
183
|
+
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error('Error loading file:', error);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
</script>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Extracting Texts from a File
|
|
192
|
+
|
|
193
|
+
```html
|
|
194
|
+
<script type="module">
|
|
195
|
+
import { ObfProcessor } from 'aac-processors';
|
|
196
|
+
|
|
197
|
+
async function extractTextsFromFile(file) {
|
|
198
|
+
const processor = new ObfProcessor();
|
|
199
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
200
|
+
const texts = await processor.extractTexts(arrayBuffer);
|
|
201
|
+
|
|
202
|
+
console.log(`Extracted ${texts.length} texts:`, texts);
|
|
203
|
+
return texts;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Usage
|
|
207
|
+
document.getElementById('extractButton').addEventListener('click', async () => {
|
|
208
|
+
const file = document.getElementById('fileInput').files[0];
|
|
209
|
+
const texts = await extractTextsFromFile(file);
|
|
210
|
+
displayTexts(texts);
|
|
211
|
+
});
|
|
212
|
+
</script>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Processing Translations
|
|
216
|
+
|
|
217
|
+
```html
|
|
218
|
+
<script type="module">
|
|
219
|
+
import { getProcessor } from 'aac-processors';
|
|
220
|
+
|
|
221
|
+
async function translateFile(file, translations) {
|
|
222
|
+
const extension = '.' + file.name.split('.').pop();
|
|
223
|
+
const processor = getProcessor(extension);
|
|
224
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
225
|
+
|
|
226
|
+
// Process texts with translations
|
|
227
|
+
const translatedBuffer = await processor.processTexts(
|
|
228
|
+
arrayBuffer,
|
|
229
|
+
translations,
|
|
230
|
+
null // Don't save to file, return buffer
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Create download link
|
|
234
|
+
const blob = new Blob([translatedBuffer], { type: 'application/octet-stream' });
|
|
235
|
+
const url = URL.createObjectURL(blob);
|
|
236
|
+
const a = document.createElement('a');
|
|
237
|
+
a.href = url;
|
|
238
|
+
a.download = 'translated-' + file.name;
|
|
239
|
+
a.click();
|
|
240
|
+
URL.revokeObjectURL(url);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Usage
|
|
244
|
+
const translations = new Map([
|
|
245
|
+
['Hello', 'Hola'],
|
|
246
|
+
['Goodbye', 'Adiós'],
|
|
247
|
+
['Yes', 'Sí'],
|
|
248
|
+
['No', 'No']
|
|
249
|
+
]);
|
|
250
|
+
|
|
251
|
+
translateFile(myFile, translations);
|
|
252
|
+
</script>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Supported File Types
|
|
256
|
+
|
|
257
|
+
### Browser-Compatible Processors
|
|
258
|
+
|
|
259
|
+
These processors work in browser environments:
|
|
260
|
+
|
|
261
|
+
| Processor | Extensions | Description |
|
|
262
|
+
|-----------------|-----------------|----------------------------------|
|
|
263
|
+
| DotProcessor | `.dot` | OpenSymbols Board files |
|
|
264
|
+
| OpmlProcessor | `.opml` | OPML outline files |
|
|
265
|
+
| ObfProcessor | `.obf`, `.obz` | Open Board Format files |
|
|
266
|
+
| GridsetProcessor| `.gridset` | Grid 3 gridset files (not .gridsetx) |
|
|
267
|
+
| ApplePanelsProcessor | `.plist` | Apple Panels files |
|
|
268
|
+
| AstericsGridProcessor | `.grd` | Asterics Grid files |
|
|
269
|
+
|
|
270
|
+
### Node-Only Processors
|
|
271
|
+
|
|
272
|
+
These processors require Node.js and **do not work** in browser:
|
|
273
|
+
|
|
274
|
+
- **SnapProcessor** (.spb, .sps) - Requires SQLite
|
|
275
|
+
- **TouchChatProcessor** (.ce) - Requires SQLite
|
|
276
|
+
- **ExcelProcessor** (.xlsx) - Uses fs at top level
|
|
277
|
+
|
|
278
|
+
## Factory Functions
|
|
279
|
+
|
|
280
|
+
### getProcessor(extension)
|
|
281
|
+
|
|
282
|
+
Get a processor instance for a file extension:
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
import { getProcessor } from 'aac-processors';
|
|
286
|
+
|
|
287
|
+
const processor = getProcessor('.obf');
|
|
288
|
+
console.log(processor.constructor.name); // 'ObfProcessor'
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### getSupportedExtensions()
|
|
292
|
+
|
|
293
|
+
Get list of supported file extensions:
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
import { getSupportedExtensions } from 'aac-processors';
|
|
297
|
+
|
|
298
|
+
const extensions = getSupportedExtensions();
|
|
299
|
+
// ['.dot', '.opml', '.obf', '.obz', '.gridset', '.plist', '.grd']
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### isExtensionSupported(extension)
|
|
303
|
+
|
|
304
|
+
Check if an extension is supported:
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
import { isExtensionSupported } from 'aac-processors';
|
|
308
|
+
|
|
309
|
+
console.log(isExtensionSupported('.obf')); // true
|
|
310
|
+
console.log(isExtensionSupported('.pdf')); // false
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Working with Tree Structure
|
|
314
|
+
|
|
315
|
+
### Accessing Pages
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
319
|
+
|
|
320
|
+
// Get all page IDs
|
|
321
|
+
const pageIds = Object.keys(tree.pages);
|
|
322
|
+
console.log('Pages:', pageIds);
|
|
323
|
+
|
|
324
|
+
// Get root page
|
|
325
|
+
const rootPage = tree.pages[tree.rootId];
|
|
326
|
+
console.log('Root page:', rootPage.name);
|
|
327
|
+
|
|
328
|
+
// Get specific page
|
|
329
|
+
const page = tree.pages['page-id'];
|
|
330
|
+
console.log('Page buttons:', page.buttons.length);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Accessing Buttons
|
|
334
|
+
|
|
335
|
+
```javascript
|
|
336
|
+
const page = tree.pages['page-id'];
|
|
337
|
+
|
|
338
|
+
// Iterate through buttons
|
|
339
|
+
page.buttons.forEach(button => {
|
|
340
|
+
console.log('Button:', button.label);
|
|
341
|
+
console.log('Message:', button.message);
|
|
342
|
+
console.log('Type:', button.type);
|
|
343
|
+
|
|
344
|
+
// Check for navigation
|
|
345
|
+
if (button.type === 'NAVIGATE') {
|
|
346
|
+
console.log('Navigates to:', button.targetPageId);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Get buttons with specific type
|
|
351
|
+
const speakButtons = page.buttons.filter(b => b.type === 'SPEAK');
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Accessing Images
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
// For OBF/OBZ files with embedded images
|
|
358
|
+
const button = page.buttons[0];
|
|
359
|
+
if (button.imagePath) {
|
|
360
|
+
console.log('Image path:', button.imagePath);
|
|
361
|
+
|
|
362
|
+
// Extract image as data URL (browser-compatible)
|
|
363
|
+
const processor = new ObfProcessor();
|
|
364
|
+
const dataUrl = await processor.extractImageAsDataUrl(arrayBuffer, button.imagePath);
|
|
365
|
+
console.log('Data URL:', dataUrl);
|
|
366
|
+
|
|
367
|
+
// Use in img tag
|
|
368
|
+
const img = document.createElement('img');
|
|
369
|
+
img.src = dataUrl;
|
|
370
|
+
document.body.appendChild(img);
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Complete Example: AAC File Viewer
|
|
375
|
+
|
|
376
|
+
```html
|
|
377
|
+
<!DOCTYPE html>
|
|
378
|
+
<html lang="en">
|
|
379
|
+
<head>
|
|
380
|
+
<meta charset="UTF-8">
|
|
381
|
+
<title>AAC File Viewer</title>
|
|
382
|
+
<style>
|
|
383
|
+
.button-grid {
|
|
384
|
+
display: grid;
|
|
385
|
+
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
|
386
|
+
gap: 10px;
|
|
387
|
+
padding: 20px;
|
|
388
|
+
}
|
|
389
|
+
.aac-button {
|
|
390
|
+
border: 2px solid #333;
|
|
391
|
+
border-radius: 8px;
|
|
392
|
+
padding: 15px;
|
|
393
|
+
text-align: center;
|
|
394
|
+
cursor: pointer;
|
|
395
|
+
background: #f0f0f0;
|
|
396
|
+
}
|
|
397
|
+
.aac-button:hover {
|
|
398
|
+
background: #e0e0e0;
|
|
399
|
+
}
|
|
400
|
+
</style>
|
|
401
|
+
</head>
|
|
402
|
+
<body>
|
|
403
|
+
<h1>AAC File Viewer</h1>
|
|
404
|
+
<input type="file" id="fileInput" accept=".obf,.obz,.gridset,.dot,.opml,.plist,.grd">
|
|
405
|
+
<div id="content"></div>
|
|
406
|
+
|
|
407
|
+
<script type="module">
|
|
408
|
+
import { getProcessor } from 'aac-processors';
|
|
409
|
+
|
|
410
|
+
const fileInput = document.getElementById('fileInput');
|
|
411
|
+
const contentDiv = document.getElementById('content');
|
|
412
|
+
|
|
413
|
+
fileInput.addEventListener('change', async (event) => {
|
|
414
|
+
const file = event.target.files[0];
|
|
415
|
+
if (!file) return;
|
|
416
|
+
|
|
417
|
+
const extension = '.' + file.name.split('.').pop();
|
|
418
|
+
const processor = getProcessor(extension);
|
|
419
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
420
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
421
|
+
|
|
422
|
+
displayPage(tree.rootId);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
function displayPage(pageId) {
|
|
426
|
+
const page = tree.pages[pageId];
|
|
427
|
+
contentDiv.innerHTML = `<h2>${page.name}</h2>`;
|
|
428
|
+
|
|
429
|
+
const grid = document.createElement('div');
|
|
430
|
+
grid.className = 'button-grid';
|
|
431
|
+
|
|
432
|
+
page.buttons.forEach(button => {
|
|
433
|
+
const btnDiv = document.createElement('div');
|
|
434
|
+
btnDiv.className = 'aac-button';
|
|
435
|
+
btnDiv.textContent = button.label;
|
|
436
|
+
btnDiv.addEventListener('click', () => {
|
|
437
|
+
if (button.type === 'NAVIGATE') {
|
|
438
|
+
displayPage(button.targetPageId);
|
|
439
|
+
} else {
|
|
440
|
+
console.log('Button clicked:', button.label, button.message);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
grid.appendChild(btnDiv);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
contentDiv.appendChild(grid);
|
|
447
|
+
}
|
|
448
|
+
</script>
|
|
449
|
+
</body>
|
|
450
|
+
</html>
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## Browser-Specific Considerations
|
|
454
|
+
|
|
455
|
+
### No File Paths
|
|
456
|
+
|
|
457
|
+
Browsers don't have access to file paths. Always use:
|
|
458
|
+
|
|
459
|
+
- `File` objects from `<input type="file">`
|
|
460
|
+
- `ArrayBuffer` or `Uint8Array` from `fetch()` or `FileReader`
|
|
461
|
+
- `Blob` objects
|
|
462
|
+
|
|
463
|
+
### CORS for Remote Files
|
|
464
|
+
|
|
465
|
+
When loading files from remote URLs, ensure CORS is enabled:
|
|
466
|
+
|
|
467
|
+
```javascript
|
|
468
|
+
async function loadFromUrl(url) {
|
|
469
|
+
const response = await fetch(url);
|
|
470
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
471
|
+
const processor = getProcessor('.obf');
|
|
472
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
473
|
+
return tree;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// This will fail if the server doesn't send proper CORS headers
|
|
477
|
+
loadFromUrl('https://example.com/file.obf');
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Memory Management
|
|
481
|
+
|
|
482
|
+
Large files can consume significant memory. Consider:
|
|
483
|
+
|
|
484
|
+
1. **Process files one at a time** - Avoid loading multiple files simultaneously
|
|
485
|
+
2. **Revoke object URLs** - `URL.revokeObjectURL(url)` when done with blobs
|
|
486
|
+
3. **Clear references** - Set variables to `null` when done
|
|
487
|
+
|
|
488
|
+
```javascript
|
|
489
|
+
let currentTree = null;
|
|
490
|
+
|
|
491
|
+
async function loadFile(file) {
|
|
492
|
+
// Clear previous
|
|
493
|
+
currentTree = null;
|
|
494
|
+
|
|
495
|
+
// Load new
|
|
496
|
+
const processor = getProcessor('.obf');
|
|
497
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
498
|
+
currentTree = await processor.loadIntoTree(arrayBuffer);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function clearTree() {
|
|
502
|
+
currentTree = null;
|
|
503
|
+
// Trigger garbage collection hint
|
|
504
|
+
if (window.gc) window.gc();
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Performance Tips
|
|
509
|
+
|
|
510
|
+
1. **Use Web Workers** for large files:
|
|
511
|
+
```javascript
|
|
512
|
+
// worker.js
|
|
513
|
+
import { getProcessor } from 'aac-processors';
|
|
514
|
+
|
|
515
|
+
self.onmessage = async (event) => {
|
|
516
|
+
const { file } = event.data;
|
|
517
|
+
const processor = getProcessor('.obf');
|
|
518
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
519
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
520
|
+
self.postMessage({ tree });
|
|
521
|
+
};
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
2. **Show progress indicators**:
|
|
525
|
+
```javascript
|
|
526
|
+
function showLoading(message) {
|
|
527
|
+
document.getElementById('status').textContent = message;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async function loadWithProgress(file) {
|
|
531
|
+
showLoading('Loading file...');
|
|
532
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
533
|
+
showLoading('Processing file...');
|
|
534
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
535
|
+
showLoading('Done!');
|
|
536
|
+
return tree;
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
## Error Handling
|
|
541
|
+
|
|
542
|
+
Always wrap processor calls in try/catch:
|
|
543
|
+
|
|
544
|
+
```javascript
|
|
545
|
+
async function safeLoadFile(file) {
|
|
546
|
+
try {
|
|
547
|
+
const extension = '.' + file.name.split('.').pop();
|
|
548
|
+
const processor = getProcessor(extension);
|
|
549
|
+
|
|
550
|
+
if (!processor) {
|
|
551
|
+
throw new Error(`Unsupported file type: ${extension}`);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
555
|
+
const tree = await processor.loadIntoTree(arrayBuffer);
|
|
556
|
+
|
|
557
|
+
return tree;
|
|
558
|
+
} catch (error) {
|
|
559
|
+
console.error('Failed to load file:', error);
|
|
560
|
+
alert(`Error: ${error.message}`);
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## Testing
|
|
567
|
+
|
|
568
|
+
See [Browser Test Page](../examples/browser-test.html) for interactive testing.
|
|
569
|
+
|
|
570
|
+
To run the test server:
|
|
571
|
+
```bash
|
|
572
|
+
node examples/browser-test-server.js
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
Then open: http://localhost:8080/examples/browser-test.html
|
|
576
|
+
|
|
577
|
+
## Troubleshooting
|
|
578
|
+
|
|
579
|
+
### Module Not Found
|
|
580
|
+
|
|
581
|
+
**Problem:** `Cannot resolve 'aac-processors'`
|
|
582
|
+
|
|
583
|
+
**Solution:** Ensure you're importing from the correct path:
|
|
584
|
+
```javascript
|
|
585
|
+
// For npm installs
|
|
586
|
+
import { getProcessor } from 'aac-processors';
|
|
587
|
+
|
|
588
|
+
// For local development
|
|
589
|
+
import { getProcessor } from './dist/index.browser.js';
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Buffer vs ArrayBuffer
|
|
593
|
+
|
|
594
|
+
**Problem:** Type mismatch between Buffer and ArrayBuffer
|
|
595
|
+
|
|
596
|
+
**Solution:** Browsers use ArrayBuffer/Uint8Array, not Buffer:
|
|
597
|
+
```javascript
|
|
598
|
+
// Browser
|
|
599
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
600
|
+
const uint8Array = new Uint8Array(arrayBuffer);
|
|
601
|
+
|
|
602
|
+
// Both work with processors
|
|
603
|
+
await processor.loadIntoTree(arrayBuffer);
|
|
604
|
+
await processor.loadIntoTree(uint8Array);
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### Gridset .gridsetx Files
|
|
608
|
+
|
|
609
|
+
**Problem:** `.gridsetx` files fail to load
|
|
610
|
+
|
|
611
|
+
**Solution:** Encrypted `.gridsetx` files require Node.js crypto. Use regular `.gridset` files in browser.
|
|
612
|
+
|
|
613
|
+
## Additional Resources
|
|
614
|
+
|
|
615
|
+
- [API Documentation](./API.md)
|
|
616
|
+
- [Examples](../examples/)
|
|
617
|
+
- [Browser Test Page](../examples/browser-test.html)
|
|
618
|
+
- [Test Server](../examples/browser-test-server.js)
|