Use Case: Custom File Format Handler

Register a custom application that handles your own file format. This demo creates a .todo format with a custom viewer that parses and renders todo lists with checkboxes.

Live Demo

<iframe id="cf-demo" src="/online/webapp/file-manager" width="100%" height="650" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('cf-demo', 'cfSocket');
window._cfSeq = function (cmds, done) {

var s = window._ws('cfSocket');
if (!s) return;
var i = 0;
var next = function () {
    if (i >= cmds.length) { if (done) done(); return; }
    var cmd = cmds[i++];
    var args = cmd.concat([function () { setTimeout(next, 5); }]);
    s.fire.apply(s, ['webapp::instance::request'].concat(args));
};
next();

};
window._cfAppCode = function (renderFnStr) {

return 'module.exports = function () {\n' +
    'var app = new ApplicationPrototype();\n' +
    'var node = document.createElement("div");\n' +
    'var win = null;\n' +
    'var ready = new Application.Promise();\n' +
    'app.bind("node", function () { return node; }, "");\n' +
    'app.bind("window", function () { return win; }, "");\n' +
    'app.bind("ready", function () { return ready; });\n' +
    'app.bind("handleWindow", function (w) {\n' +
    '    win = w;\n' +
    '    w.emit("api-request::attached", []);\n' +
    '    w.on("api-request::ready", function (cb) { cb(ready); });\n' +
    '});\n' +
    'app.bind("render", function (cb) {\n' +
    '    (' + renderFnStr + ')(app, win, node, cb);\n' +
    '});\n' +
    'app.bind("destroy", function () {});\n' +
    'app.bind("init", function () {\n' +
    '    app.render(function (err) {\n' +
    '        if (err) return ready.reject(err);\n' +
    '        ready.resolve(app);\n' +
    '    });\n' +
    '    return app;\n' +
    '});\n' +
    'return app;\n' +
'};';

};
window._cfSetup = function () {

// Todo Viewer app
var todoAppCode = window._cfAppCode((function (app, win, node, cb) {
    win.title('Todo Viewer'); win.icon('paper/icons/apps/preferences-system-notifications');
    win.height(450); win.width(500);
    var args = app.window().env().args || [];
    var filePath = args[0];
    if (!filePath) { node.innerHTML = '

No file

'; cb(); return; } node.innerHTML = '

Loading todo list...

'; Application.require('/files/api/modules/fs.js').then(function (fsModule) { var fs = fsModule(); fs.read(filePath, null, true).response('text').then(function (text) { var lines = text.split('\n'); var html = '
'; html += '

' + filePath.replace(/^.*\//, '') + '

'; lines.forEach(function (line) { line = line.trim(); if (!line) return; if (line.match(/^#/)) { html += '

' + line.replace(/^#+\s*/, '') + '

'; } else { var checked = line.match(/^\[x\]/i); var text = line.replace(/^\[[ x]\]\s*/i, ''); var style = checked ? 'text-decoration:line-through;color:#999' : 'color:#333'; html += ''; } }); var done = lines.filter(function(l){return l.match(/^\[x\]/i)}).length; var total = lines.filter(function(l){return l.match(/^\[[ x]\]/i)}).length; if (total) html += '
' + done + '/' + total + ' tasks completed (' + Math.round(done/total*100) + '%)
'; html += '
'; node.innerHTML = html; }); }); cb(); }).toString());
// Config Viewer app (for .env and .cfg files)
var configAppCode = window._cfAppCode((function (app, win, node, cb) {
    win.title('Config Viewer'); win.icon('breeze/icons/mimetypes/64/text-x-makefile');
    win.height(400); win.width(550);
    var args = app.window().env().args || [];
    if (!args[0]) { cb(); return; }
    node.innerHTML = '

Loading...

'; Application.require('/files/api/modules/fs.js').then(function (fsModule) { fsModule().read(args[0], null, true).response('text').then(function (text) { var lines = text.split('\n'); var html = ''; html += ''; var row = 0; lines.forEach(function (line) { line = line.trim(); if (!line || line.charAt(0) === '#') return; var eq = line.indexOf('='); if (eq === -1) return; var key = line.substring(0, eq).trim(); var val = line.substring(eq + 1).trim(); var bg = row++ % 2 ? '#f8f9fa' : '#fff'; html += ''; html += ''; }); html += '
KeyValue
' + key + '' + val.replace(/
'; node.innerHTML = '
' + html + '
'; }); }); cb(); }).toString());
var todoFile = [
    '# Sprint 23 Tasks',
    '[x] Setup project structure',
    '[x] Create database schema',
    '[x] Implement user authentication',
    '[ ] Build REST API endpoints',
    '[ ] Add input validation',
    '[ ] Write unit tests',
    '',
    '# Bugs',
    '[x] Fix login redirect loop',
    '[ ] Memory leak in WebSocket handler',
    '[ ] CSS overflow on mobile',
    '',
    '# Nice to Have',
    '[ ] Dark mode toggle',
    '[ ] Keyboard shortcuts',
    '[ ] Export to PDF'
].join('\n');
var envFile = [
    '# Server Configuration',
    'NODE_ENV=production',
    'PORT=3000',
    'HOST=0.0.0.0',
    '',
    '# Database',
    'DB_HOST=localhost',
    'DB_PORT=5432',
    'DB_NAME=myapp',
    'DB_USER=admin',
    'DB_PASS=secret123',
    '',
    '# External APIs',
    'SMTP_HOST=smtp.gmail.com',
    'SMTP_PORT=587',
    'API_KEY=sk-abc123def456',
    'REDIS_URL=redis://localhost:6379'
].join('\n');
window._cfSeq([
    ['gui:specialPaths:clear'],
    ['fs:mkdirp', 'input://apps/'],
    ['fs:mkdirp', 'input://my-project/'],
    ['fs:write', 'input://apps/todo-viewer.js', todoAppCode],
    ['fs:write', 'input://apps/config-viewer.js', configAppCode],
    ['fs:write', 'input://my-project/sprint-tasks.todo', todoFile],
    ['fs:write', 'input://my-project/backlog.todo', '# Backlog\n[ ] Multi-language support\n[ ] OAuth providers\n[ ] Rate limiting\n[x] Logging framework\n[x] Error handling middleware'],
    ['fs:write', 'input://my-project/.env', envFile],
    ['fs:write', 'input://my-project/database.cfg', 'host=localhost\nport=5432\nname=myapp\npool_size=10\ntimeout=30\nssl=true'],
    ['apps:register', {
        'todo-viewer': { path: 'input://apps/todo-viewer.js', name: 'Todo Viewer', icon: 'paper/icons/apps/preferences-system-notifications', comment: 'View todo lists', mimetypes: [], 'file-handlers': ['\\.todo
    
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] },\n            'config-viewer': { path: 'input://apps/config-viewer.js', name: 'Config Viewer', icon: 'breeze/icons/mimetypes/64/text-x-makefile', comment: 'View config files', mimetypes: [], 'file-handlers': ['\\\\.env
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] }\n        }],\n        ['gui:specialPaths:add', { path: 'input://my-project/', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue', bookmark: { category: 'project', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue' } }],\n        ['fs:cwd', 'input://my-project/']\n    ], function () {\n        alert('Custom file formats ready!\\n\\nTry:\\n- Double-click sprint-tasks.todo (Todo Viewer with checkboxes)\\n- Double-click .env (Config Viewer with key-value table)\\n- Double-click database.cfg (Config Viewer)');\n    });\n};\n<\/script>\n\n\n\n---\n\n## What This Demo Does\n\n1. **Registers two custom apps** for non-standard file formats:\n   - **Todo Viewer** (`.todo`) — parses a checkbox-based todo format and renders it with checkboxes, completion counts, and section headers\n   - **Config Viewer** (`.env`, `.cfg`) — parses key=value configuration files and renders them as a styled table\n\n2. **Uses `file-handlers` regex** instead of MIME types, since `.todo`, `.env`, and `.cfg` don't have standard MIME types:\n   ```js\n   'file-handlers': ['\\\\.todo
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

]   // matches any file ending in .todo\n   'file-handlers': ['\\\\.env
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

]  // matches .env and .cfg\n   ```\n\n3. **Creates sample files** to demonstrate each format\n\n## The `.todo` Format\n\nA simple text-based format:\n```\n# Section Header\n[x] Completed task\n[ ] Pending task\n```\n\nThe Todo Viewer parses this and renders:\n- `#` lines as section headers\n- `[x]` as checked checkboxes (strikethrough text)\n- `[ ]` as unchecked checkboxes\n- A completion progress bar at the bottom\n\n## Building Your Own File Format Handler\n\n```js\n// 1. Write the viewer app\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n    \"input://apps/my-format.js\",\n    appCode  // module.exports = function() { ... }\n);\n\n// 2. Register with file-handlers for custom extensions\nsocket.fire(\"webapp::instance::request\", \"apps:register\", {\n    \"my-format-viewer\": {\n        path: \"input://apps/my-format.js\",\n        name: \"My Format Viewer\",\n        icon: \"paper/icons/apps/system-software-install\",\n        mimetypes: [],\n        \"file-handlers\": [\"\\\\.myformat$\", \"\\\\.mf$\"],\n        args: [\"%U\"]\n    }\n});\n\n// 3. Create a sample file\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n    \"input://demo/example.myformat\",\n    \"your format content here\"\n);\n```\n";window.$preloadedPath = "/webapp-docs/use-cases/custom-file-format";
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] },
        'config-viewer': { path: 'input://apps/config-viewer.js', name: 'Config Viewer', icon: 'breeze/icons/mimetypes/64/text-x-makefile', comment: 'View config files', mimetypes: [], 'file-handlers': ['\\.env
    
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] },\n            'config-viewer': { path: 'input://apps/config-viewer.js', name: 'Config Viewer', icon: 'breeze/icons/mimetypes/64/text-x-makefile', comment: 'View config files', mimetypes: [], 'file-handlers': ['\\\\.env
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] }\n        }],\n        ['gui:specialPaths:add', { path: 'input://my-project/', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue', bookmark: { category: 'project', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue' } }],\n        ['fs:cwd', 'input://my-project/']\n    ], function () {\n        alert('Custom file formats ready!\\n\\nTry:\\n- Double-click sprint-tasks.todo (Todo Viewer with checkboxes)\\n- Double-click .env (Config Viewer with key-value table)\\n- Double-click database.cfg (Config Viewer)');\n    });\n};\n<\/script>\n\n\n\n---\n\n## What This Demo Does\n\n1. **Registers two custom apps** for non-standard file formats:\n   - **Todo Viewer** (`.todo`) — parses a checkbox-based todo format and renders it with checkboxes, completion counts, and section headers\n   - **Config Viewer** (`.env`, `.cfg`) — parses key=value configuration files and renders them as a styled table\n\n2. **Uses `file-handlers` regex** instead of MIME types, since `.todo`, `.env`, and `.cfg` don't have standard MIME types:\n   ```js\n   'file-handlers': ['\\\\.todo
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

]   // matches any file ending in .todo\n   'file-handlers': ['\\\\.env
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

]  // matches .env and .cfg\n   ```\n\n3. **Creates sample files** to demonstrate each format\n\n## The `.todo` Format\n\nA simple text-based format:\n```\n# Section Header\n[x] Completed task\n[ ] Pending task\n```\n\nThe Todo Viewer parses this and renders:\n- `#` lines as section headers\n- `[x]` as checked checkboxes (strikethrough text)\n- `[ ]` as unchecked checkboxes\n- A completion progress bar at the bottom\n\n## Building Your Own File Format Handler\n\n```js\n// 1. Write the viewer app\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n    \"input://apps/my-format.js\",\n    appCode  // module.exports = function() { ... }\n);\n\n// 2. Register with file-handlers for custom extensions\nsocket.fire(\"webapp::instance::request\", \"apps:register\", {\n    \"my-format-viewer\": {\n        path: \"input://apps/my-format.js\",\n        name: \"My Format Viewer\",\n        icon: \"paper/icons/apps/system-software-install\",\n        mimetypes: [],\n        \"file-handlers\": [\"\\\\.myformat$\", \"\\\\.mf$\"],\n        args: [\"%U\"]\n    }\n});\n\n// 3. Create a sample file\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n    \"input://demo/example.myformat\",\n    \"your format content here\"\n);\n```\n";window.$preloadedPath = "/webapp-docs/use-cases/custom-file-format";
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] },\n            'config-viewer': { path: 'input://apps/config-viewer.js', name: 'Config Viewer', icon: 'breeze/icons/mimetypes/64/text-x-makefile', comment: 'View config files', mimetypes: [], 'file-handlers': ['\\\\.env
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] }\n        }],\n        ['gui:specialPaths:add', { path: 'input://my-project/', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue', bookmark: { category: 'project', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue' } }],\n        ['fs:cwd', 'input://my-project/']\n    ], function () {\n        alert('Custom file formats ready!\\n\\nTry:\\n- Double-click sprint-tasks.todo (Todo Viewer with checkboxes)\\n- Double-click .env (Config Viewer with key-value table)\\n- Double-click database.cfg (Config Viewer)');\n    });\n};\n<\/script>\n\n\n\n---\n\n## What This Demo Does\n\n1. **Registers two custom apps** for non-standard file formats:\n   - **Todo Viewer** (`.todo`) — parses a checkbox-based todo format and renders it with checkboxes, completion counts, and section headers\n   - **Config Viewer** (`.env`, `.cfg`) — parses key=value configuration files and renders them as a styled table\n\n2. **Uses `file-handlers` regex** instead of MIME types, since `.todo`, `.env`, and `.cfg` don't have standard MIME types:\n   ```js\n   'file-handlers': ['\\\\.todo
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

]   // matches any file ending in .todo\n   'file-handlers': ['\\\\.env
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

, '\\\\.cfg
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

]  // matches .env and .cfg\n   ```\n\n3. **Creates sample files** to demonstrate each format\n\n## The `.todo` Format\n\nA simple text-based format:\n```\n# Section Header\n[x] Completed task\n[ ] Pending task\n```\n\nThe Todo Viewer parses this and renders:\n- `#` lines as section headers\n- `[x]` as checked checkboxes (strikethrough text)\n- `[ ]` as unchecked checkboxes\n- A completion progress bar at the bottom\n\n## Building Your Own File Format Handler\n\n```js\n// 1. Write the viewer app\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n    \"input://apps/my-format.js\",\n    appCode  // module.exports = function() { ... }\n);\n\n// 2. Register with file-handlers for custom extensions\nsocket.fire(\"webapp::instance::request\", \"apps:register\", {\n    \"my-format-viewer\": {\n        path: \"input://apps/my-format.js\",\n        name: \"My Format Viewer\",\n        icon: \"paper/icons/apps/system-software-install\",\n        mimetypes: [],\n        \"file-handlers\": [\"\\\\.myformat$\", \"\\\\.mf$\"],\n        args: [\"%U\"]\n    }\n});\n\n// 3. Create a sample file\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n    \"input://demo/example.myformat\",\n    \"your format content here\"\n);\n```\n";window.$preloadedPath = "/webapp-docs/use-cases/custom-file-format";
    
    
    
    
    
    
    
    
    
    
    
    
sgapps.io

], args: ['%U'] }
    }],
    ['gui:specialPaths:add', { path: 'input://my-project/', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue', bookmark: { category: 'project', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue' } }],
    ['fs:cwd', 'input://my-project/']
], function () {
    alert('Custom file formats ready!\n\nTry:\n- Double-click sprint-tasks.todo (Todo Viewer with checkboxes)\n- Double-click .env (Config Viewer with key-value table)\n- Double-click database.cfg (Config Viewer)');
});

};</script>
<button onclick="window._cfSetup()" style="padding:10px 20px;font-size:15px;cursor:pointer">Setup Custom File Formats</button>


What This Demo Does

  1. Registers two custom apps for non-standard file formats: - Todo Viewer (.todo) — parses a checkbox-based todo format and renders it with checkboxes, completion counts, and section headers - Config Viewer (.env, .cfg) — parses key=value configuration files and renders them as a styled table
  1. Uses file-handlers regex instead of MIME types, since .todo, .env, and .cfg don't have standard MIME types:
    `js
    &#x27;file-handlers&#x27;: [&#x27;\.todo&#x24;&#x27;]   // matches any file ending in .todo
    &#x27;file-handlers&#x27;: [&#x27;\.env&#x24;&#x27;, &#x27;\.cfg&#x24;&#x27;]  // matches .env and .cfg
    
    `
  1. Creates sample files to demonstrate each format

The .todo Format

A simple text-based format:

# Section Header
[x] Completed task
[ ] Pending task

The Todo Viewer parses this and renders:

Building Your Own File Format Handler

// 1. Write the viewer app
socket.fire("webapp::instance::request", "fs:write",
    "input://apps/my-format.js",
    appCode  // module.exports = function() { ... }
);

// 2. Register with file-handlers for custom extensions
socket.fire("webapp::instance::request", "apps:register", {
    "my-format-viewer": {
        path: "input://apps/my-format.js",
        name: "My Format Viewer",
        icon: "paper/icons/apps/system-software-install",
        mimetypes: [],
        "file-handlers": ["\\.myformat$", "\\.mf$"],
        args: ["%U"]
    }
});

// 3. Create a sample file
socket.fire("webapp::instance::request", "fs:write",
    "input://demo/example.myformat",
    "your format content here"
);
sgapps.io ], args: ['%U'] },\n 'config-viewer': { path: 'input://apps/config-viewer.js', name: 'Config Viewer', icon: 'breeze/icons/mimetypes/64/text-x-makefile', comment: 'View config files', mimetypes: [], 'file-handlers': ['\\\\.env sgapps.io , '\\\\.cfg sgapps.io ], args: ['%U'] }\n }],\n ['gui:specialPaths:add', { path: 'input://my-project/', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue', bookmark: { category: 'project', name: 'My Project', icon: 'breeze/icons/places/64/folder-blue' } }],\n ['fs:cwd', 'input://my-project/']\n ], function () {\n alert('Custom file formats ready!\\n\\nTry:\\n- Double-click sprint-tasks.todo (Todo Viewer with checkboxes)\\n- Double-click .env (Config Viewer with key-value table)\\n- Double-click database.cfg (Config Viewer)');\n });\n};\n<\/script>\n\n\n\n---\n\n## What This Demo Does\n\n1. **Registers two custom apps** for non-standard file formats:\n - **Todo Viewer** (`.todo`) — parses a checkbox-based todo format and renders it with checkboxes, completion counts, and section headers\n - **Config Viewer** (`.env`, `.cfg`) — parses key=value configuration files and renders them as a styled table\n\n2. **Uses `file-handlers` regex** instead of MIME types, since `.todo`, `.env`, and `.cfg` don't have standard MIME types:\n ```js\n 'file-handlers': ['\\\\.todo sgapps.io ] // matches any file ending in .todo\n 'file-handlers': ['\\\\.env sgapps.io , '\\\\.cfg sgapps.io ] // matches .env and .cfg\n ```\n\n3. **Creates sample files** to demonstrate each format\n\n## The `.todo` Format\n\nA simple text-based format:\n```\n# Section Header\n[x] Completed task\n[ ] Pending task\n```\n\nThe Todo Viewer parses this and renders:\n- `#` lines as section headers\n- `[x]` as checked checkboxes (strikethrough text)\n- `[ ]` as unchecked checkboxes\n- A completion progress bar at the bottom\n\n## Building Your Own File Format Handler\n\n```js\n// 1. Write the viewer app\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n \"input://apps/my-format.js\",\n appCode // module.exports = function() { ... }\n);\n\n// 2. Register with file-handlers for custom extensions\nsocket.fire(\"webapp::instance::request\", \"apps:register\", {\n \"my-format-viewer\": {\n path: \"input://apps/my-format.js\",\n name: \"My Format Viewer\",\n icon: \"paper/icons/apps/system-software-install\",\n mimetypes: [],\n \"file-handlers\": [\"\\\\.myformat$\", \"\\\\.mf$\"],\n args: [\"%U\"]\n }\n});\n\n// 3. Create a sample file\nsocket.fire(\"webapp::instance::request\", \"fs:write\",\n \"input://demo/example.myformat\",\n \"your format content here\"\n);\n```\n";window.$preloadedPath = "/webapp-docs/use-cases/custom-file-format"; sgapps.io