@willwade/aac-processors 0.0.29 → 0.1.0
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 +43 -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 +421 -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 +355 -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 +17 -3
- 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 +118 -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 +7 -7
- package/dist/validation/snapValidator.js +28 -35
- package/docs/BROWSER_USAGE.md +618 -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 +74 -0
- package/examples/vitedemo/README.md +157 -0
- package/examples/vitedemo/index.html +376 -0
- package/examples/vitedemo/package-lock.json +1221 -0
- package/examples/vitedemo/package.json +18 -0
- package/examples/vitedemo/src/main.ts +519 -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 +20 -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)
|
package/examples/README.md
CHANGED
|
@@ -48,3 +48,80 @@ These pagesets are used by:
|
|
|
48
48
|
- Integration examples
|
|
49
49
|
|
|
50
50
|
To run demo scripts that use these pagesets, see the [scripts/README.md](../scripts/README.md).
|
|
51
|
+
|
|
52
|
+
## Browser Testing
|
|
53
|
+
|
|
54
|
+
### ⚠️ Important Note
|
|
55
|
+
|
|
56
|
+
AACProcessors is built with TypeScript and outputs CommonJS modules. To use it in a browser, you **must use a bundler** (Vite, Webpack, Rollup, etc.). The browser test page below only validates the library structure - it cannot run actual processors without a bundler.
|
|
57
|
+
|
|
58
|
+
### Browser Test Page
|
|
59
|
+
|
|
60
|
+
A dedicated browser test page is available for validating the library structure:
|
|
61
|
+
|
|
62
|
+
**Start the test server:**
|
|
63
|
+
```bash
|
|
64
|
+
node examples/browser-test-server.js
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Open in your browser:**
|
|
68
|
+
```
|
|
69
|
+
http://localhost:8080/examples/browser-test.html
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**What it tests:**
|
|
73
|
+
- ✅ Browser build files exist and are accessible
|
|
74
|
+
- ✅ Type definitions are present
|
|
75
|
+
- ✅ Processor exports are available
|
|
76
|
+
- ❌ **Does NOT run actual processors** (requires bundler)
|
|
77
|
+
|
|
78
|
+
### What Gets Tested
|
|
79
|
+
|
|
80
|
+
The browser test page (`browser-test.html`) verifies:
|
|
81
|
+
|
|
82
|
+
1. **Module Loading** - Can the browser load the ES modules?
|
|
83
|
+
2. **Factory Functions** - Do `getProcessor()` and `getSupportedExtensions()` work?
|
|
84
|
+
3. **Processor Instantiation** - Can processors be created?
|
|
85
|
+
4. **File Loading** - Can files be loaded from `<input type="file">`?
|
|
86
|
+
5. **Buffer Handling** - Do ArrayBuffers/Uint8Arrays work correctly?
|
|
87
|
+
6. **Tree Structure** - Can AACTree be created from files?
|
|
88
|
+
7. **Text Extraction** - Can texts be extracted from files?
|
|
89
|
+
|
|
90
|
+
### Supported File Types in Browser
|
|
91
|
+
|
|
92
|
+
The browser test page supports all browser-compatible processors:
|
|
93
|
+
|
|
94
|
+
- **DotProcessor** (.dot) - OpenSymbols Board files
|
|
95
|
+
- **OpmlProcessor** (.opml) - OPML outline files
|
|
96
|
+
- **ObfProcessor** (.obf/.obz) - Open Board Format files
|
|
97
|
+
- **GridsetProcessor** (.gridset) - Grid 3 gridset files (not .gridsetx)
|
|
98
|
+
- **ApplePanelsProcessor** (.plist) - Apple Panels files
|
|
99
|
+
- **AstericsGridProcessor** (.grd) - Asterics Grid files
|
|
100
|
+
|
|
101
|
+
### Manual Testing
|
|
102
|
+
|
|
103
|
+
1. Open the browser console (F12 or Cmd+Option+I)
|
|
104
|
+
2. Click "Select a file to test" to upload an AAC file
|
|
105
|
+
3. Click "Test File" to process it
|
|
106
|
+
4. Check the results panel for page count, button count, and extracted texts
|
|
107
|
+
|
|
108
|
+
### Automated Tests
|
|
109
|
+
|
|
110
|
+
Click "Run All Browser Tests" to run automated checks:
|
|
111
|
+
- Factory function tests
|
|
112
|
+
- Extension support tests
|
|
113
|
+
- Processor instantiation tests
|
|
114
|
+
- Buffer handling tests
|
|
115
|
+
|
|
116
|
+
### Node-Only Processors
|
|
117
|
+
|
|
118
|
+
The following processors are **not available** in the browser:
|
|
119
|
+
- **SnapProcessor** (.spb/.sps) - Requires SQLite
|
|
120
|
+
- **TouchChatProcessor** (.ce) - Requires SQLite
|
|
121
|
+
- **ExcelProcessor** (.xlsx) - Uses fs at top level
|
|
122
|
+
|
|
123
|
+
### Notes
|
|
124
|
+
|
|
125
|
+
- Gridset `.gridsetx` files (encrypted) are not supported in browser
|
|
126
|
+
- All processors work with Buffer, Uint8Array, and ArrayBuffer inputs
|
|
127
|
+
- File paths are not supported in browser (use file inputs or fetch)
|