mirror of
https://github.com/mileswolfallen2/gelectron.git
synced 2026-09-08 12:43:16 +00:00
- Created main.js for the application logic, including tests for Electron app properties and methods. - Added package.json to define app metadata. - Included necessary code signature files for macOS app distribution. - Implemented basic window management and event handling in the app.
707 lines
24 KiB
HTML
707 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Gelectron Demo</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
background: #0f0f1a;
|
|
color: #e0e0e0;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
header {
|
|
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
border-bottom: 1px solid #2a2a4a;
|
|
padding: 24px 32px;
|
|
}
|
|
|
|
header h1 {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
background: linear-gradient(90deg, #7b68ee, #00d4ff);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
}
|
|
|
|
header p {
|
|
margin-top: 6px;
|
|
color: #8888aa;
|
|
font-size: 14px;
|
|
}
|
|
|
|
main {
|
|
flex: 1;
|
|
padding: 32px;
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 24px;
|
|
align-content: start;
|
|
}
|
|
|
|
.card {
|
|
background: #1a1a2e;
|
|
border: 1px solid #2a2a4a;
|
|
border-radius: 12px;
|
|
padding: 24px;
|
|
}
|
|
|
|
.card h2 {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #7b68ee;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.card p, .card li {
|
|
font-size: 14px;
|
|
line-height: 1.7;
|
|
color: #b0b0cc;
|
|
}
|
|
|
|
.card ul {
|
|
list-style: none;
|
|
padding: 0;
|
|
}
|
|
|
|
.card ul li::before {
|
|
content: '\2713';
|
|
color: #00d4ff;
|
|
margin-right: 8px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.counter {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.counter button {
|
|
background: #2a2a4a;
|
|
color: #e0e0e0;
|
|
border: 1px solid #3a3a6a;
|
|
border-radius: 8px;
|
|
padding: 10px 20px;
|
|
font-size: 18px;
|
|
cursor: pointer;
|
|
transition: background 0.15s, transform 0.1s;
|
|
}
|
|
|
|
.counter button:hover { background: #3a3a6a; }
|
|
.counter button:active { transform: scale(0.95); }
|
|
|
|
.counter .value {
|
|
font-size: 36px;
|
|
font-weight: 700;
|
|
color: #00d4ff;
|
|
min-width: 60px;
|
|
text-align: center;
|
|
}
|
|
|
|
.canvas-wrap {
|
|
margin-top: 12px;
|
|
}
|
|
|
|
canvas {
|
|
background: #12121f;
|
|
border: 1px solid #2a2a4a;
|
|
border-radius: 8px;
|
|
display: block;
|
|
width: 100%;
|
|
height: 200px;
|
|
}
|
|
|
|
.color-bar {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-top: 12px;
|
|
}
|
|
|
|
.color-bar span {
|
|
flex: 1;
|
|
height: 32px;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
#clock {
|
|
font-size: 32px;
|
|
font-weight: 300;
|
|
color: #00d4ff;
|
|
font-variant-numeric: tabular-nums;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.env-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.env-table td {
|
|
padding: 6px 0;
|
|
font-size: 13px;
|
|
border-bottom: 1px solid #1f1f35;
|
|
}
|
|
|
|
.env-table td:first-child {
|
|
color: #7b68ee;
|
|
font-weight: 600;
|
|
width: 40%;
|
|
}
|
|
|
|
.env-table td:last-child {
|
|
color: #b0b0cc;
|
|
font-family: 'SF Mono', Menlo, monospace;
|
|
}
|
|
|
|
.test-card { grid-column: 1 / -1; }
|
|
.test-results { margin-top: 12px; }
|
|
.test-row {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 6px 0;
|
|
border-bottom: 1px solid #1f1f35;
|
|
font-size: 13px;
|
|
}
|
|
.test-row:last-child { border-bottom: none; }
|
|
.test-pass { color: #6bcb77; }
|
|
.test-fail { color: #ff6b6b; }
|
|
.test-name { flex: 1; color: #b0b0cc; }
|
|
.test-value { color: #8888aa; font-family: 'SF Mono', Menlo, monospace; margin-left: 12px; }
|
|
|
|
.btn-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-top: 12px;
|
|
}
|
|
.btn-grid button {
|
|
background: #2a2a4a;
|
|
color: #e0e0e0;
|
|
border: 1px solid #3a3a6a;
|
|
border-radius: 8px;
|
|
padding: 8px 14px;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
transition: background 0.15s, transform 0.1s;
|
|
}
|
|
.btn-grid button:hover { background: #3a3a6a; }
|
|
.btn-grid button:active { transform: scale(0.95); }
|
|
.btn-grid button.active { background: #7b68ee; border-color: #7b68ee; }
|
|
|
|
.demo-output {
|
|
margin-top: 10px;
|
|
background: #12121f;
|
|
border: 1px solid #2a2a4a;
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
font-family: 'SF Mono', Menlo, monospace;
|
|
font-size: 12px;
|
|
color: #b0b0cc;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
max-height: 180px;
|
|
overflow-y: auto;
|
|
display: none;
|
|
}
|
|
|
|
footer {
|
|
padding: 16px 32px;
|
|
border-top: 1px solid #2a2a4a;
|
|
text-align: center;
|
|
font-size: 12px;
|
|
color: #555577;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>Gelectron Demo</h1>
|
|
<p>HTML + CSS + JavaScript rendering via Gecko / Servo engine</p>
|
|
</header>
|
|
|
|
<main>
|
|
<div class="card">
|
|
<h2>Interactive Counter</h2>
|
|
<p>Proof that JavaScript runs and DOM updates work.</p>
|
|
<div class="counter">
|
|
<button onclick="dec()">\u2212</button>
|
|
<div class="value" id="count">0</div>
|
|
<button onclick="inc()">+</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Live Clock</h2>
|
|
<p>requestAnimationFrame-driven rendering.</p>
|
|
<div id="clock">--:--:--</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Canvas 2D</h2>
|
|
<p>Animated canvas with moving shapes.</p>
|
|
<div class="canvas-wrap">
|
|
<canvas id="scene" width="400" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Runtime Info</h2>
|
|
<p>Environment details from the gelectron shim.</p>
|
|
<table class="env-table">
|
|
<tr><td>Platform</td><td id="env-platform"></td></tr>
|
|
<tr><td>Arch</td><td id="env-arch"></td></tr>
|
|
<tr><td>Node.js</td><td id="env-node"></td></tr>
|
|
<tr><td>User Agent</td><td id="env-ua"></td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="card" style="grid-column: 1 / -1;">
|
|
<h2>CSS Features</h2>
|
|
<p>Grid, gradients, border-radius, transitions, flexbox, backdrop styling.</p>
|
|
<div class="color-bar">
|
|
<span style="background: #7b68ee;"></span>
|
|
<span style="background: #00d4ff;"></span>
|
|
<span style="background: #ff6b9d;"></span>
|
|
<span style="background: #ffd93d;"></span>
|
|
<span style="background: #6bcb77;"></span>
|
|
<span style="background: #ee5a24;"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" style="grid-column: 1 / -1;">
|
|
<h2>App Module Demo</h2>
|
|
<p>Interactive demo of the Electron app API — properties, methods, and lifecycle.</p>
|
|
<div class="btn-grid">
|
|
<button onclick="demoApp('version')">getVersion()</button>
|
|
<button onclick="demoApp('locale')">getLocale()</button>
|
|
<button onclick="demoApp('userAgent')">getUserAgent()</button>
|
|
<button onclick="demoApp('setUserAgent')">setUserAgent()</button>
|
|
<button onclick="demoApp('appPath')">getAppPath()</button>
|
|
<button onclick="demoApp('isReady')">isReady</button>
|
|
<button onclick="demoApp('badge')">setBadgeCount(7)</button>
|
|
<button onclick="demoApp('metrics')">getAppMetrics()</button>
|
|
<button onclick="demoApp('gpu')">getGPUInfo()</button>
|
|
<button onclick="demoApp('gpuFeatures')">getGPUFeatureStatus()</button>
|
|
<button onclick="demoApp('loginItem')">getLoginItemSettings()</button>
|
|
<button onclick="demoApp('aboutPanel')">getAboutPanelOptions()</button>
|
|
<button onclick="demoApp('secureKeyboard')">setSecureKeyboardEntry()</button>
|
|
<button onclick="demoApp('name')">app.name =</button>
|
|
<button onclick="demoApp('paths')">getPath(home)</button>
|
|
<button onclick="demoApp('dock')">dock.bounce()</button>
|
|
</div>
|
|
<div class="demo-output" id="app-demo-output"></div>
|
|
</div>
|
|
|
|
<div class="card" style="grid-column: 1 / -1;">
|
|
<h2>Menu Module Demo</h2>
|
|
<p>Interactive demo of the Electron Menu API — build, set, and inspect native menus.</p>
|
|
<div class="btn-grid">
|
|
<button onclick="demoMenu('build')">Menu.buildFromTemplate()</button>
|
|
<button onclick="demoMenu('set')">Menu.setApplicationMenu()</button>
|
|
<button onclick="demoMenu('get')">Menu.getApplicationMenu()</button>
|
|
<button onclick="demoMenu('findById')">getMenuItemById()</button>
|
|
<button onclick="demoMenu('append')">menu.append()</button>
|
|
<button onclick="demoMenu('serialize')">menu._serialize()</button>
|
|
<button onclick="demoMenu('count')">menu.items.length</button>
|
|
<button onclick="demoMenu('submenu')">Submenu nesting</button>
|
|
</div>
|
|
<div class="demo-output" id="menu-demo-output"></div>
|
|
</div>
|
|
|
|
<div class="card test-card">
|
|
<h2>App Module Tests</h2>
|
|
<p>Automated tests for the Electron app compatibility layer.</p>
|
|
<div id="app-tests" class="test-results">
|
|
<p style="color: #8888aa; font-size: 13px;">Waiting for test results...</p>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer>Gelectron v0.1.0 — Electron API compatibility layer powered by Gecko/Servo</footer>
|
|
|
|
<script>
|
|
// Counter
|
|
var count = 0;
|
|
var countEl = document.getElementById('count');
|
|
function inc() { countEl.textContent = ++count; }
|
|
function dec() { countEl.textContent = --count; }
|
|
|
|
// Live clock
|
|
function tick() {
|
|
var now = new Date();
|
|
var h = String(now.getHours()).padStart(2, '0');
|
|
var m = String(now.getMinutes()).padStart(2, '0');
|
|
var s = String(now.getSeconds()).padStart(2, '0');
|
|
document.getElementById('clock').textContent = h + ':' + m + ':' + s;
|
|
requestAnimationFrame(tick);
|
|
}
|
|
tick();
|
|
|
|
// Canvas animation
|
|
var canvas = document.getElementById('scene');
|
|
var ctx = canvas.getContext('2d');
|
|
var t = 0;
|
|
function drawFrame() {
|
|
t += 0.02;
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
// bouncing ball
|
|
var bx = 50 + Math.sin(t) * 150;
|
|
var by = 100 + Math.cos(t * 1.3) * 60;
|
|
ctx.beginPath();
|
|
ctx.arc(bx, by, 18, 0, Math.PI * 2);
|
|
ctx.fillStyle = '#7b68ee';
|
|
ctx.fill();
|
|
|
|
// second ball
|
|
var bx2 = 200 + Math.cos(t * 0.7) * 120;
|
|
var by2 = 80 + Math.sin(t * 1.1) * 70;
|
|
ctx.beginPath();
|
|
ctx.arc(bx2, by2, 14, 0, Math.PI * 2);
|
|
ctx.fillStyle = '#00d4ff';
|
|
ctx.fill();
|
|
|
|
// trailing line
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 100 + Math.sin(t) * 40);
|
|
for (var x = 0; x < canvas.width; x += 4) {
|
|
ctx.lineTo(x, 100 + Math.sin(t + x * 0.03) * 40);
|
|
}
|
|
ctx.strokeStyle = 'rgba(123,104,238,0.3)';
|
|
ctx.lineWidth = 2;
|
|
ctx.stroke();
|
|
|
|
requestAnimationFrame(drawFrame);
|
|
}
|
|
drawFrame();
|
|
|
|
// Runtime info
|
|
document.getElementById('env-platform').textContent = navigator.platform || 'unknown';
|
|
document.getElementById('env-arch').textContent = 'unknown (browser sandbox)';
|
|
document.getElementById('env-node').textContent = 'N/A in renderer';
|
|
document.getElementById('env-ua').textContent = navigator.userAgent;
|
|
|
|
// App module interactive demo
|
|
function demoApp(action) {
|
|
var out = document.getElementById('app-demo-output');
|
|
out.style.display = 'block';
|
|
var electron = window.electron;
|
|
if (!electron || !electron.app) {
|
|
out.textContent = 'Error: window.electron.app not available (renderer-only mode)';
|
|
return;
|
|
}
|
|
var app = electron.app;
|
|
var result = '';
|
|
switch (action) {
|
|
case 'version':
|
|
result = 'app.getVersion() → ' + app.getVersion() +
|
|
'\napp.version (property) → ' + app.version;
|
|
break;
|
|
case 'locale':
|
|
result = 'app.getLocale() → ' + app.getLocale() +
|
|
'\napp.locale (property) → ' + app.locale;
|
|
break;
|
|
case 'userAgent':
|
|
result = 'app.getUserAgent() → ' + app.getUserAgent() +
|
|
'\napp.userAgent (property) → ' + app.userAgent;
|
|
break;
|
|
case 'setUserAgent':
|
|
app.setUserAgent('GelectronDemo/2.0');
|
|
result = 'app.setUserAgent("GelectronDemo/2.0")' +
|
|
'\napp.getUserAgent() → ' + app.getUserAgent();
|
|
app.setUserAgent(null);
|
|
result += '\napp.setUserAgent(null) reset → ' + app.getUserAgent();
|
|
break;
|
|
case 'appPath':
|
|
result = 'app.getAppPath() → ' + app.getAppPath() +
|
|
'\napp.appPath (property) → ' + app.appPath;
|
|
break;
|
|
case 'isReady':
|
|
result = 'app.isReady (property) → ' + app.isReady +
|
|
'\napp.isReady() method → ' + app.isReady() +
|
|
'\napp.whenReady() → [Promise resolved]';
|
|
app.whenReady().then(function() {
|
|
out.textContent += '\n→ whenReady promise resolved!';
|
|
});
|
|
break;
|
|
case 'badge':
|
|
app.setBadgeCount(7);
|
|
result = 'app.setBadgeCount(7)' +
|
|
'\napp.getBadgeCount() → ' + app.getBadgeCount();
|
|
app.setBadgeCount(0);
|
|
result += '\napp.setBadgeCount(0) → ' + app.getBadgeCount();
|
|
break;
|
|
case 'metrics':
|
|
var m = app.getAppMetrics();
|
|
result = 'app.getAppMetrics() → [' + m.length + ' entries]' +
|
|
'\n pid: ' + m[0].pid +
|
|
'\n type: ' + m[0].type +
|
|
'\n memory: ' + JSON.stringify(m[0].memory) +
|
|
'\n sandboxed: ' + m[0].sandboxed;
|
|
break;
|
|
case 'gpu':
|
|
app.getGPUInfo('basic').then(function(info) {
|
|
out.textContent = 'app.getGPUInfo("basic") →\n' +
|
|
' GPUActive: ' + info.GPUActive +
|
|
'\n gpuDevice: ' + JSON.stringify(info.gpuDevice, null, 2);
|
|
});
|
|
result = 'Loading GPU info...';
|
|
break;
|
|
case 'gpuFeatures':
|
|
var f = app.getGPUFeatureStatus();
|
|
var lines = ['app.getGPUFeatureStatus() →'];
|
|
for (var k in f) lines.push(' ' + k + ': ' + f[k]);
|
|
result = lines.join('\n');
|
|
break;
|
|
case 'loginItem':
|
|
var s = app.getLoginItemSettings();
|
|
result = 'app.getLoginItemSettings() →\n' +
|
|
' openAtLogin: ' + s.openAtLogin +
|
|
'\n openAsHidden: ' + s.openAsHidden +
|
|
'\n launchAtLogin: ' + s.launchAtLogin +
|
|
'\n launchItems: ' + JSON.stringify(s.launchItems);
|
|
break;
|
|
case 'aboutPanel':
|
|
app.setAboutPanelOptions({ applicationName: 'Gelectron Demo', copyright: 'MIT' });
|
|
var o = app.getAboutPanelOptions();
|
|
result = 'app.setAboutPanelOptions({ applicationName: "Gelectron Demo", copyright: "MIT" })' +
|
|
'\napp.getAboutPanelOptions() →\n' + JSON.stringify(o, null, 2);
|
|
break;
|
|
case 'secureKeyboard':
|
|
app.setSecureKeyboardEntryEnabled(true);
|
|
result = 'app.setSecureKeyboardEntryEnabled(true)' +
|
|
'\napp.isSecureKeyboardEntryEnabled() → ' + app.isSecureKeyboardEntryEnabled();
|
|
app.setSecureKeyboardEntryEnabled(false);
|
|
result += '\napp.setSecureKeyboardEntryEnabled(false)' +
|
|
'\napp.isSecureKeyboardEntryEnabled() → ' + app.isSecureKeyboardEntryEnabled();
|
|
break;
|
|
case 'name':
|
|
var old = app.name;
|
|
app.name = 'Gelectron Demo App';
|
|
result = 'app.name = "Gelectron Demo App"' +
|
|
'\napp.name → ' + app.name +
|
|
'\napp.getName() → ' + app.getName();
|
|
app.name = old;
|
|
result += '\n(app.name restored to "' + old + '")';
|
|
break;
|
|
case 'paths':
|
|
result = 'app.getPath("home") → ' + app.getPath('home') +
|
|
'\napp.getPath("userData") → ' + app.getPath('userData') +
|
|
'\napp.getPath("temp") → ' + app.getPath('temp') +
|
|
'\napp.getPath("desktop") → ' + app.getPath('desktop') +
|
|
'\napp.getPath("documents") → ' + app.getPath('documents') +
|
|
'\napp.getPath("downloads") → ' + app.getPath('downloads') +
|
|
'\napp.getPath("logs") → ' + app.getPath('logs');
|
|
break;
|
|
case 'dock':
|
|
if (app.dock) {
|
|
var id = app.dock.bounce();
|
|
result = 'app.dock.bounce() → ' + id +
|
|
'\napp.dock.isVisible() → ' + app.dock.isVisible() +
|
|
'\napp.dock.getBadge() → "' + app.dock.getBadge() + '"';
|
|
} else {
|
|
result = 'app.dock → null (not macOS)';
|
|
}
|
|
break;
|
|
}
|
|
out.textContent = result;
|
|
}
|
|
|
|
// Menu module interactive demo
|
|
function demoMenu(action) {
|
|
var out = document.getElementById('menu-demo-output');
|
|
out.style.display = 'block';
|
|
var electron = window.electron;
|
|
if (!electron || !electron.Menu) {
|
|
out.textContent = 'Error: window.electron.Menu not available';
|
|
return;
|
|
}
|
|
var Menu = electron.Menu;
|
|
var MenuItem = electron.MenuItem;
|
|
var result = '';
|
|
switch (action) {
|
|
case 'build': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ label: 'File', submenu: [
|
|
{ label: 'New', accelerator: 'CmdOrCtrl+N' },
|
|
{ label: 'Open', accelerator: 'CmdOrCtrl+O' },
|
|
{ type: 'separator' },
|
|
{ label: 'Quit', accelerator: 'CmdOrCtrl+Q' },
|
|
]},
|
|
{ label: 'Edit', submenu: [
|
|
{ label: 'Cut', accelerator: 'CmdOrCtrl+X' },
|
|
{ label: 'Copy', accelerator: 'CmdOrCtrl+C' },
|
|
{ label: 'Paste', accelerator: 'CmdOrCtrl+V' },
|
|
]},
|
|
{ label: 'Help', submenu: [
|
|
{ label: 'About Gelectron' },
|
|
]},
|
|
]);
|
|
result = 'Menu.buildFromTemplate([...]) → Menu {\n' +
|
|
' items.length: ' + menu.items.length + '\n' +
|
|
' items[0].label: "' + menu.items[0].label + '"\n' +
|
|
' items[0].submenu.items.length: ' + menu.items[0].submenu.items.length + '\n' +
|
|
' items[1].label: "' + menu.items[1].label + '"\n' +
|
|
' items[2].label: "' + menu.items[2].label + '"\n' +
|
|
'}';
|
|
break;
|
|
}
|
|
case 'set': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ label: 'File', submenu: [
|
|
{ label: 'New Window', accelerator: 'CmdOrCtrl+N' },
|
|
{ type: 'separator' },
|
|
{ label: 'Quit', accelerator: 'CmdOrCtrl+Q' },
|
|
]},
|
|
{ label: 'View', submenu: [
|
|
{ label: 'Reload', accelerator: 'CmdOrCtrl+R' },
|
|
{ label: 'Toggle DevTools', accelerator: 'CmdOrCtrl+Shift+I' },
|
|
]},
|
|
]);
|
|
Menu.setApplicationMenu(menu);
|
|
var current = Menu.getApplicationMenu();
|
|
result = 'Menu.setApplicationMenu(menu) → sent to native bridge' +
|
|
'\nMenu.getApplicationMenu() → ' + (current ? 'Menu { items: ' + current.items.length + ' }' : 'null');
|
|
break;
|
|
}
|
|
case 'get': {
|
|
var current = Menu.getApplicationMenu();
|
|
if (current) {
|
|
var labels = current.items.map(function(i) { return i.label; });
|
|
result = 'Menu.getApplicationMenu() → Menu {\n' +
|
|
' items: [' + labels.join(', ') + ']\n' +
|
|
' items.length: ' + current.items.length + '\n' +
|
|
'}';
|
|
} else {
|
|
result = 'Menu.getApplicationMenu() → null\n(No application menu set yet. Click "Menu.setApplicationMenu()" first.)';
|
|
}
|
|
break;
|
|
}
|
|
case 'findById': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ id: 'file-menu', label: 'File', submenu: [
|
|
{ id: 'new-file', label: 'New File' },
|
|
{ id: 'open-file', label: 'Open File' },
|
|
]},
|
|
{ id: 'edit-menu', label: 'Edit', submenu: [
|
|
{ id: 'copy-item', label: 'Copy' },
|
|
]},
|
|
]);
|
|
var item = menu.getMenuItemById('new-file');
|
|
var item2 = menu.getMenuItemById('copy-item');
|
|
var missing = menu.getMenuItemById('nonexistent');
|
|
result = 'menu.getMenuItemById("new-file") →\n' +
|
|
' label: "' + (item ? item.label : 'null') + '"\n' +
|
|
' id: "' + (item ? item.id : 'null') + '"' +
|
|
'\nmenu.getMenuItemById("copy-item") →\n' +
|
|
' label: "' + (item2 ? item2.label : 'null') + '"' +
|
|
'\nmenu.getMenuItemById("nonexistent") → ' + (missing ? 'found' : 'null');
|
|
break;
|
|
}
|
|
case 'append': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ label: 'Existing Item' },
|
|
]);
|
|
result = 'Before append: items.length = ' + menu.items.length;
|
|
menu.append(new MenuItem({ label: 'Appended Item', type: 'normal' }));
|
|
result += '\nmenu.append(new MenuItem({ label: "Appended Item" }))' +
|
|
'\nAfter append: items.length = ' + menu.items.length +
|
|
'\n items[0].label: "' + menu.items[0].label + '"' +
|
|
'\n items[1].label: "' + menu.items[1].label + '"';
|
|
break;
|
|
}
|
|
case 'serialize': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ label: 'File', submenu: [
|
|
{ label: 'New', accelerator: 'CmdOrCtrl+N' },
|
|
{ type: 'separator' },
|
|
{ label: 'Quit' },
|
|
]},
|
|
{ label: 'Edit', enabled: false },
|
|
]);
|
|
var s = menu._serialize();
|
|
result = 'menu._serialize() →\n' + JSON.stringify(s, null, 2);
|
|
break;
|
|
}
|
|
case 'count': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ label: 'File', submenu: [{ label: 'New' }] },
|
|
{ label: 'Edit' },
|
|
{ label: 'View' },
|
|
{ label: 'Help' },
|
|
]);
|
|
result = 'Menu.buildFromTemplate(4 top-level items)' +
|
|
'\nmenu.items.length → ' + menu.items.length +
|
|
'\nmenu.items.map(i => i.label) → [' +
|
|
menu.items.map(function(i) { return '"' + i.label + '"'; }).join(', ') + ']' +
|
|
'\nmenu.items[0].submenu.items.length → ' + menu.items[0].submenu.items.length;
|
|
break;
|
|
}
|
|
case 'submenu': {
|
|
var menu = Menu.buildFromTemplate([
|
|
{ label: 'Format', submenu: [
|
|
{ label: 'Font', submenu: [
|
|
{ label: 'Bold', type: 'checkbox' },
|
|
{ label: 'Italic', type: 'checkbox' },
|
|
{ label: 'Underline', type: 'checkbox' },
|
|
]},
|
|
{ type: 'separator' },
|
|
{ label: 'Align Left' },
|
|
{ label: 'Align Center' },
|
|
{ label: 'Align Right' },
|
|
]},
|
|
]);
|
|
var fmt = menu.items[0];
|
|
result = 'Menu with nested submenus:' +
|
|
'\nmenu.items[0].label → "' + fmt.label + '"' +
|
|
'\nmenu.items[0].submenu.items.length → ' + fmt.submenu.items.length +
|
|
'\nmenu.items[0].submenu.items[0].label → "' + fmt.submenu.items[0].label + '"' +
|
|
'\nmenu.items[0].submenu.items[0].submenu.items.length → ' +
|
|
fmt.submenu.items[0].submenu.items.length +
|
|
'\n nested items: ' +
|
|
fmt.submenu.items[0].submenu.items.map(function(i) {
|
|
return '"' + i.label + '"';
|
|
}).join(', ');
|
|
break;
|
|
}
|
|
}
|
|
out.textContent = result;
|
|
}
|
|
|
|
// App test results renderer
|
|
function renderAppTests() {
|
|
var results = window.__appTestResults;
|
|
if (!results) return;
|
|
var el = document.getElementById('app-tests');
|
|
var html = '';
|
|
var pass = 0, fail = 0;
|
|
for (var i = 0; i < results.length; i++) {
|
|
var r = results[i];
|
|
var cls = r.status === 'PASS' ? 'test-pass' : 'test-fail';
|
|
var icon = r.status === 'PASS' ? '\u2713' : '\u2717';
|
|
if (r.status === 'PASS') pass++; else fail++;
|
|
html += '<div class="test-row">' +
|
|
'<span class="' + cls + '">' + icon + '</span>' +
|
|
'<span class="test-name">' + r.name + '</span>' +
|
|
'<span class="test-value">' + r.value + '</span>' +
|
|
'</div>';
|
|
}
|
|
html = '<div style="margin-bottom: 12px; font-size: 14px; font-weight: 600;">' +
|
|
'<span class="test-pass">' + pass + ' passed</span> · ' +
|
|
'<span class="test-fail">' + fail + ' failed</span> · ' +
|
|
(pass + fail) + ' total</div>' + html;
|
|
el.innerHTML = html;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|