Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acfca90836 | ||
|
|
7291ff48f7 |
+22
-4
@@ -3668,17 +3668,35 @@ $('copyAddr').addEventListener('click', () => {
|
|||||||
* is made in their own design tool. The built-in poster page is still there
|
* is made in their own design tool. The built-in poster page is still there
|
||||||
* at /poster for anyone who wants it; it is just not what this button does.
|
* at /poster for anyone who wants it; it is just not what this button does.
|
||||||
*/
|
*/
|
||||||
$('saveQr').addEventListener('click', () => {
|
$('saveQr').addEventListener('click', async () => {
|
||||||
const base = shareBase();
|
const base = shareBase();
|
||||||
if (!base) { log('no address to encode yet', 'err'); return; }
|
if (!base) { log('no address to encode yet', 'err'); return; }
|
||||||
const a = document.createElement('a');
|
/*
|
||||||
a.href = 'http://127.0.0.1:' + state.local.port + '/qr.svg?url=' +
|
* Fetch the code and hand the browser a BLOB rather than linking straight at
|
||||||
|
* the server. This window is served from the asset port and the QR comes off
|
||||||
|
* the congregation port, so a plain <a download> is CROSS-ORIGIN — the
|
||||||
|
* download attribute is ignored and the window navigates to the image
|
||||||
|
* instead. With no back button, no reload item and no address bar, that
|
||||||
|
* strands the operator on a full-screen QR with no way out; build 123 did
|
||||||
|
* exactly that to a booth Mac. A blob: URL is same-origin, so it downloads.
|
||||||
|
*/
|
||||||
|
const url = 'http://127.0.0.1:' + state.local.port + '/qr.svg?url=' +
|
||||||
encodeURIComponent(base + '/');
|
encodeURIComponent(base + '/');
|
||||||
|
try {
|
||||||
|
const r = await fetch(url, { cache: 'no-store' });
|
||||||
|
if (!r.ok) throw new Error('the server answered ' + r.status);
|
||||||
|
const href = URL.createObjectURL(await r.blob());
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = href;
|
||||||
a.download = 'church-translate-qr.svg';
|
a.download = 'church-translate-qr.svg';
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
a.remove();
|
a.remove();
|
||||||
log('saved the QR for ' + base + '/', 'ok');
|
setTimeout(() => URL.revokeObjectURL(href), 10000);
|
||||||
|
log('saved the QR for ' + base + '/ to Downloads', 'ok');
|
||||||
|
} catch (err) {
|
||||||
|
log('could not save the QR: ' + err.message, 'err');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
$('openOperator').addEventListener('click', () => {
|
$('openOperator').addEventListener('click', () => {
|
||||||
window.open('http://127.0.0.1:' + state.local.port + '/operator', '_blank');
|
window.open('http://127.0.0.1:' + state.local.port + '/operator', '_blank');
|
||||||
|
|||||||
+21
@@ -662,6 +662,27 @@ function createWindow() {
|
|||||||
: '/index.html';
|
: '/index.html';
|
||||||
win.loadURL(assetOrigin + page);
|
win.loadURL(assetOrigin + page);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTHING replaces the app in this window. There is no back button, no
|
||||||
|
* reload item and no address bar, so a window that leaves the app page is a
|
||||||
|
* window the operator cannot get back from — which is precisely how build
|
||||||
|
* 123 stranded a booth Mac on a full-screen QR image. Our own pages still
|
||||||
|
* open as their OWN windows through setWindowOpenHandler below; this only
|
||||||
|
* refuses to replace the app itself, and sends anything external to the
|
||||||
|
* browser where it belongs.
|
||||||
|
*/
|
||||||
|
win.webContents.on('will-navigate', (e, url) => {
|
||||||
|
if (url === assetOrigin + page) return; /* reloading ourselves is fine */
|
||||||
|
e.preventDefault();
|
||||||
|
console.error('[main] refused to navigate the app window to ' + url);
|
||||||
|
let local = false;
|
||||||
|
try {
|
||||||
|
const u = new URL(url);
|
||||||
|
local = (u.hostname === '127.0.0.1' || u.hostname === 'localhost');
|
||||||
|
} catch (_) { local = false; }
|
||||||
|
if (!local) shell.openExternal(url).catch(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
win.webContents.on('did-finish-load', () => console.log('[main] page loaded'));
|
win.webContents.on('did-finish-load', () => console.log('[main] page loaded'));
|
||||||
win.webContents.on('did-fail-load', (_e, code, desc, url) =>
|
win.webContents.on('did-fail-load', (_e, code, desc, url) =>
|
||||||
console.error('[main] page FAILED to load: ' + code + ' ' + desc + ' ' + url));
|
console.error('[main] page FAILED to load: ' + code + ' ' + desc + ' ' + url));
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
"name": "church-translate-engine",
|
"name": "church-translate-engine",
|
||||||
"productName": "Church Translate",
|
"productName": "Church Translate",
|
||||||
"version": "3.23.2",
|
"version": "3.23.2",
|
||||||
"buildNumber": 123,
|
"buildNumber": 125,
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Live sermon translation — self-contained: captures audio, transcribes, translates, and serves the congregation page itself",
|
"description": "Live sermon translation — self-contained: captures audio, transcribes, translates, and serves the congregation page itself",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"asar": false,
|
"asar": false,
|
||||||
"buildVersion": "123",
|
"buildVersion": "125",
|
||||||
"win": {
|
"win": {
|
||||||
"target": [
|
"target": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -163,10 +163,21 @@
|
|||||||
function renderFeatured() {
|
function renderFeatured() {
|
||||||
var wrap = $('featured');
|
var wrap = $('featured');
|
||||||
wrap.textContent = '';
|
wrap.textContent = '';
|
||||||
|
/*
|
||||||
|
* THE OPERATOR'S LIST IS THE LIST. This used to unshift the source
|
||||||
|
* language in unconditionally, on the reasoning that plenty of people want
|
||||||
|
* the English captions for accessibility rather than translation — which
|
||||||
|
* is true, and still available, but it is not this code's call to make.
|
||||||
|
* The operator has a switch for every language including English, and for
|
||||||
|
* the source language alone that switch did nothing: English was put back
|
||||||
|
* on every render, so a desk that had deliberately turned it off still
|
||||||
|
* offered it as the first button on the page. A control that silently
|
||||||
|
* refuses is worse than no control.
|
||||||
|
*
|
||||||
|
* Wanting English captions is now one click in Settings, in the same list
|
||||||
|
* as every other language, and it stays where it is put.
|
||||||
|
*/
|
||||||
var list = (app.cfg.featured || []).slice();
|
var list = (app.cfg.featured || []).slice();
|
||||||
/* The source language belongs in the list too — plenty of people want the
|
|
||||||
English captions for accessibility, not translation. */
|
|
||||||
if (list.indexOf(app.cfg.sourceLanguage) === -1) list.unshift(app.cfg.sourceLanguage);
|
|
||||||
list.forEach(function (code) {
|
list.forEach(function (code) {
|
||||||
var b = langButton(code);
|
var b = langButton(code);
|
||||||
if (b) wrap.appendChild(b);
|
if (b) wrap.appendChild(b);
|
||||||
|
|||||||
Reference in New Issue
Block a user