Input and Output encodings are now saved per tab

This commit is contained in:
n1474335 2022-10-21 18:29:52 +01:00
parent 5efd125d9b
commit bdb8c02d5a
9 changed files with 87 additions and 33 deletions

View File

@ -11,6 +11,7 @@ import HTMLCategory from "./HTMLCategory.mjs";
import HTMLOperation from "./HTMLOperation.mjs"; import HTMLOperation from "./HTMLOperation.mjs";
import Split from "split.js"; import Split from "split.js";
import moment from "moment-timezone"; import moment from "moment-timezone";
import cptable from "codepage";
/** /**
@ -41,6 +42,10 @@ class App {
this.autoBakePause = false; this.autoBakePause = false;
this.progress = 0; this.progress = 0;
this.ingId = 0; this.ingId = 0;
this.appLoaded = false;
this.workerLoaded = false;
this.waitersLoaded = false;
} }
@ -59,11 +64,10 @@ class App {
this.manager.output.saveBombe(); this.manager.output.saveBombe();
this.adjustComponentSizes(); this.adjustComponentSizes();
this.setCompileMessage(); this.setCompileMessage();
this.uriParams = this.getURIParams();
log.debug("App loaded"); log.debug("App loaded");
this.appLoaded = true; this.appLoaded = true;
this.loadURIParams();
this.loaded(); this.loaded();
} }
@ -76,9 +80,12 @@ class App {
loaded() { loaded() {
// Check that both the app and the worker have loaded successfully, and that // Check that both the app and the worker have loaded successfully, and that
// we haven't already loaded before attempting to remove the loading screen. // we haven't already loaded before attempting to remove the loading screen.
if (!this.workerLoaded || !this.appLoaded || if (!this.workerLoaded || !this.appLoaded || !this.waitersLoaded ||
!document.getElementById("loader-wrapper")) return; !document.getElementById("loader-wrapper")) return;
// Load state from URI
this.loadURIParams(this.uriParams);
// Trigger CSS animations to remove preloader // Trigger CSS animations to remove preloader
document.body.classList.add("loaded"); document.body.classList.add("loaded");
@ -454,11 +461,12 @@ class App {
* If character encodings are present, sets them appropriately. * If character encodings are present, sets them appropriately.
* If theme is present, uses the theme. * If theme is present, uses the theme.
* *
* @param {Object} params
* @fires Manager#statechange * @fires Manager#statechange
*/ */
loadURIParams() { loadURIParams(params=this.getURIParams()) {
this.autoBakePause = true; this.autoBakePause = true;
this.uriParams = this.getURIParams(); this.uriParams = params;
// Read in recipe from URI params // Read in recipe from URI params
if (this.uriParams.recipe) { if (this.uriParams.recipe) {
@ -483,15 +491,8 @@ class App {
search.dispatchEvent(new Event("search")); search.dispatchEvent(new Event("search"));
} }
// Read in input data from URI params
if (this.uriParams.input) {
try {
const inputData = fromBase64(this.uriParams.input);
this.setInput(inputData);
} catch (err) {}
}
// Input Character Encoding // Input Character Encoding
// Must be set before the input is loaded
if (this.uriParams.ienc) { if (this.uriParams.ienc) {
this.manager.input.chrEncChange(parseInt(this.uriParams.ienc, 10)); this.manager.input.chrEncChange(parseInt(this.uriParams.ienc, 10));
} }
@ -501,6 +502,21 @@ class App {
this.manager.output.chrEncChange(parseInt(this.uriParams.oenc, 10)); this.manager.output.chrEncChange(parseInt(this.uriParams.oenc, 10));
} }
// Read in input data from URI params
if (this.uriParams.input) {
try {
let inputVal;
const inputChrEnc = this.manager.input.getChrEnc();
const inputData = fromBase64(this.uriParams.input);
if (inputChrEnc > 0) {
inputVal= cptable.utils.decode(inputChrEnc, inputData);
} else {
inputVal = Utils.arrayBufferToStr(inputData);
}
this.setInput(inputVal);
} catch (err) {}
}
// Read in theme from URI params // Read in theme from URI params
if (this.uriParams.theme) { if (this.uriParams.theme) {
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme)); this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));

View File

@ -93,6 +93,23 @@ class Manager {
this.bindings.updateKeybList(); this.bindings.updateKeybList();
this.background.registerChefWorker(); this.background.registerChefWorker();
this.seasonal.load(); this.seasonal.load();
this.confirmWaitersLoaded();
}
/**
* Confirms that all Waiters have loaded correctly.
*/
confirmWaitersLoaded() {
if (this.tabs.getActiveTab("input") >= 0 &&
this.tabs.getActiveTab("output") >= 0) {
log.debug("Waiters loaded");
this.app.waitersLoaded = true;
this.app.loaded();
} else {
// Not loaded yet, try again soon
setTimeout(this.confirmWaitersLoaded.bind(this), 10);
}
} }

View File

@ -222,7 +222,7 @@ class StatusBarPanel {
/** /**
* Gets the current character encoding of the document * Sets the current character encoding of the document
*/ */
updateCharEnc() { updateCharEnc() {
const chrEncVal = this.chrEncGetter(); const chrEncVal = this.chrEncGetter();

View File

@ -138,8 +138,8 @@ class ControlsWaiter {
} }
} }
const inputChrEnc = this.manager.input.inputChrEnc; const inputChrEnc = this.manager.input.getChrEnc();
const outputChrEnc = this.manager.output.outputChrEnc; const outputChrEnc = this.manager.output.getChrEnc();
const params = [ const params = [
includeRecipe ? ["recipe", recipeStr] : undefined, includeRecipe ? ["recipe", recipeStr] : undefined,

View File

@ -51,8 +51,8 @@ class HighlighterWaiter {
const selectionRanges = e.state.selection.ranges; const selectionRanges = e.state.selection.ranges;
// Adjust offsets based on the width of the character set // Adjust offsets based on the width of the character set
const inputCharacterWidth = chrEncWidth(this.manager.input.inputChrEnc); const inputCharacterWidth = chrEncWidth(this.manager.input.getChrEnc());
const outputCharacterWidth = chrEncWidth(this.manager.output.outputChrEnc); const outputCharacterWidth = chrEncWidth(this.manager.output.getChrEnc());
let ratio = 1; let ratio = 1;
if (inputCharacterWidth !== outputCharacterWidth && if (inputCharacterWidth !== outputCharacterWidth &&
inputCharacterWidth !== 0 && outputCharacterWidth !== 0) { inputCharacterWidth !== 0 && outputCharacterWidth !== 0) {

View File

@ -469,6 +469,7 @@ class InputWaiter {
* @param {string} file.type * @param {string} file.type
* @param {string} status * @param {string} status
* @param {number} progress * @param {number} progress
* @param {number} encoding
* @param {boolean} [silent=false] - If false, fires the manager statechange event * @param {boolean} [silent=false] - If false, fires the manager statechange event
*/ */
async set(inputNum, inputData, silent=false) { async set(inputNum, inputData, silent=false) {
@ -476,13 +477,14 @@ class InputWaiter {
const activeTab = this.manager.tabs.getActiveTab("input"); const activeTab = this.manager.tabs.getActiveTab("input");
if (inputNum !== activeTab) return; if (inputNum !== activeTab) return;
this.inputChrEnc = inputData.encoding;
if (inputData.file) { if (inputData.file) {
this.setFile(inputNum, inputData); this.setFile(inputNum, inputData);
} else { } else {
this.clearFile(inputNum); this.clearFile(inputNum);
} }
// TODO Per-tab encodings?
let inputVal; let inputVal;
if (this.inputChrEnc > 0) { if (this.inputChrEnc > 0) {
inputVal = cptable.utils.decode(this.inputChrEnc, new Uint8Array(inputData.buffer)); inputVal = cptable.utils.decode(this.inputChrEnc, new Uint8Array(inputData.buffer));
@ -609,8 +611,8 @@ class InputWaiter {
// If value is a string, interpret it using the specified character encoding // If value is a string, interpret it using the specified character encoding
if (typeof value === "string") { if (typeof value === "string") {
stringSample = value.slice(0, 4096); stringSample = value.slice(0, 4096);
if (this.inputChrEnc > 0) { if (this.getChrEnc() > 0) {
buffer = cptable.utils.encode(this.inputChrEnc, value); buffer = cptable.utils.encode(this.getChrEnc(), value);
buffer = new Uint8Array(buffer).buffer; buffer = new Uint8Array(buffer).buffer;
} else { } else {
buffer = Utils.strToArrayBuffer(value); buffer = Utils.strToArrayBuffer(value);
@ -631,7 +633,8 @@ class InputWaiter {
data: { data: {
inputNum: inputNum, inputNum: inputNum,
buffer: buffer, buffer: buffer,
stringSample: stringSample stringSample: stringSample,
encoding: this.getChrEnc()
} }
}, transferable); }, transferable);
} }
@ -924,7 +927,7 @@ class InputWaiter {
* @param {number} inputNum - The inputNum of the tab to change to * @param {number} inputNum - The inputNum of the tab to change to
* @param {boolean} [changeOutput=false] - If true, also changes the output * @param {boolean} [changeOutput=false] - If true, also changes the output
*/ */
changeTab(inputNum, changeOutput) { changeTab(inputNum, changeOutput=false) {
if (this.manager.tabs.getTabItem(inputNum, "input") !== null) { if (this.manager.tabs.getTabItem(inputNum, "input") !== null) {
this.manager.tabs.changeTab(inputNum, "input"); this.manager.tabs.changeTab(inputNum, "input");
this.inputWorker.postMessage({ this.inputWorker.postMessage({

View File

@ -51,7 +51,6 @@ class OutputWaiter {
}; };
// Hold a copy of the currently displayed output so that we don't have to update it unnecessarily // Hold a copy of the currently displayed output so that we don't have to update it unnecessarily
this.currentOutputCache = null; this.currentOutputCache = null;
this.outputChrEnc = 0;
this.initEditor(); this.initEditor();
this.outputs = {}; this.outputs = {};
@ -146,7 +145,14 @@ class OutputWaiter {
*/ */
chrEncChange(chrEncVal) { chrEncChange(chrEncVal) {
if (typeof chrEncVal !== "number") return; if (typeof chrEncVal !== "number") return;
this.outputChrEnc = chrEncVal;
const currentTabNum = this.manager.tabs.getActiveTab("output");
if (currentTabNum >= 0) {
this.outputs[currentTabNum].encoding = chrEncVal;
} else {
throw new Error("Cannot change output chrEnc to " + chrEncVal);
}
// Reset the output, forcing it to re-decode the data with the new character encoding // Reset the output, forcing it to re-decode the data with the new character encoding
this.setOutput(this.currentOutputCache, true); this.setOutput(this.currentOutputCache, true);
// Update the URL manually since we aren't firing a statechange event // Update the URL manually since we aren't firing a statechange event
@ -154,11 +160,15 @@ class OutputWaiter {
} }
/** /**
* Getter for the input character encoding * Getter for the output character encoding
* @returns {number} * @returns {number}
*/ */
getChrEnc() { getChrEnc() {
return this.outputChrEnc; const currentTabNum = this.manager.tabs.getActiveTab("output");
if (currentTabNum < 0) {
return 0;
}
return this.outputs[currentTabNum].encoding;
} }
/** /**
@ -195,11 +205,12 @@ class OutputWaiter {
// If data is an ArrayBuffer, convert to a string in the correct character encoding // If data is an ArrayBuffer, convert to a string in the correct character encoding
if (data instanceof ArrayBuffer) { if (data instanceof ArrayBuffer) {
if (this.outputChrEnc === 0) { const encoding = this.getChrEnc();
if (encoding === 0) {
data = Utils.arrayBufferToStr(data); data = Utils.arrayBufferToStr(data);
} else { } else {
try { try {
data = cptable.utils.decode(this.outputChrEnc, new Uint8Array(data)); data = cptable.utils.decode(encoding, new Uint8Array(data));
} catch (err) { } catch (err) {
data = err; data = err;
} }
@ -324,7 +335,8 @@ class OutputWaiter {
error: null, error: null,
status: "inactive", status: "inactive",
bakeId: -1, bakeId: -1,
progress: false progress: false,
encoding: 0
}; };
this.outputs[inputNum] = newOutput; this.outputs[inputNum] = newOutput;
@ -851,7 +863,7 @@ class OutputWaiter {
if (!this.manager.tabs.getTabItem(inputNum, "output") && numTabs < this.maxTabs) { if (!this.manager.tabs.getTabItem(inputNum, "output") && numTabs < this.maxTabs) {
// Create a new tab element // Create a new tab element
const newTab = this.manager.tabs.reateTabElement(inputNum, changeTab, "output"); const newTab = this.manager.tabs.createTabElement(inputNum, changeTab, "output");
tabsWrapper.appendChild(newTab); tabsWrapper.appendChild(newTab);
} else if (numTabs === this.maxTabs) { } else if (numTabs === this.maxTabs) {
// Can't create a new tab // Can't create a new tab

View File

@ -217,7 +217,7 @@ class WorkerWaiter {
break; break;
case "workerLoaded": case "workerLoaded":
this.app.workerLoaded = true; this.app.workerLoaded = true;
log.debug("ChefWorker loaded."); log.debug("ChefWorker loaded");
if (!this.loaded) { if (!this.loaded) {
this.app.loaded(); this.app.loaded();
this.loaded = true; this.loaded = true;

View File

@ -30,6 +30,7 @@ self.pendingFiles = [];
* @property {string} file.type * @property {string} file.type
* @property {string} status * @property {string} status
* @property {number} progress * @property {number} progress
* @property {number} encoding
*/ */
self.inputs = {}; self.inputs = {};
self.loaderWorkers = []; self.loaderWorkers = [];
@ -512,6 +513,7 @@ self.updateInputProgress = function(inputData) {
* @param {object} inputData * @param {object} inputData
* @param {number} inputData.inputNum - The input that's having its value updated * @param {number} inputData.inputNum - The input that's having its value updated
* @param {ArrayBuffer} inputData.buffer - The new value of the input as a buffer * @param {ArrayBuffer} inputData.buffer - The new value of the input as a buffer
* @param {number} [inputData.encoding] - The character encoding of the input data
* @param {string} [inputData.stringSample] - A sample of the value as a string (truncated to 4096 chars) * @param {string} [inputData.stringSample] - A sample of the value as a string (truncated to 4096 chars)
*/ */
self.updateInputValue = function(inputData) { self.updateInputValue = function(inputData) {
@ -522,6 +524,9 @@ self.updateInputValue = function(inputData) {
throw new Error(`No input with ID ${inputNum} exists`); throw new Error(`No input with ID ${inputNum} exists`);
self.inputs[inputNum].buffer = inputData.buffer; self.inputs[inputNum].buffer = inputData.buffer;
if ("encoding" in inputData) {
self.inputs[inputNum].encoding = inputData.encoding;
}
if (!("stringSample" in inputData)) { if (!("stringSample" in inputData)) {
inputData.stringSample = Utils.arrayBufferToStr(inputData.buffer.slice(0, 4096)); inputData.stringSample = Utils.arrayBufferToStr(inputData.buffer.slice(0, 4096));
} }
@ -756,7 +761,8 @@ self.addInput = function(
stringSample: "", stringSample: "",
file: null, file: null,
status: "pending", status: "pending",
progress: 0 progress: 0,
encoding: 0
}; };
switch (type) { switch (type) {