The recipe and input are now stored in the hash part of the URL

feature-extract-files
n1474335 2017-06-16 11:04:35 +00:00
parent 61951e76ac
commit 00e7d8a390
4 changed files with 50 additions and 29 deletions

View File

@ -981,6 +981,37 @@ const Utils = {
}, },
/**
* Parses URI parameters into a JSON object.
*
* @param {string} paramStr - The serialised query or hash section of a URI
* @returns {object}
*
* @example
* // returns {a: 'abc', b: '123'}
* Utils.parseURIParams("?a=abc&b=123")
* Utils.parseURIParams("#a=abc&b=123")
*/
parseURIParams: function(paramStr) {
if (paramStr === "") return {};
// Cut off ? or # and split on &
const params = paramStr.substr(1).split("&");
const result = {};
for (let i = 0; i < params.length; i++) {
const param = params[i].split("=");
if (param.length !== 2) {
result[params[i]] = true;
} else {
result[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " "));
}
}
return result;
},
/** /**
* Actual modulo function, since % is actually the remainder function in JS. * Actual modulo function, since % is actually the remainder function in JS.
* *

View File

@ -399,39 +399,28 @@ App.prototype.addFavourite = function(name) {
* Checks for input and recipe in the URI parameters and loads them if present. * Checks for input and recipe in the URI parameters and loads them if present.
*/ */
App.prototype.loadURIParams = function() { App.prototype.loadURIParams = function() {
// Load query string from URI // Load query string or hash from URI (depending on which is populated)
this.queryString = (function(a) { const params = window.location.search || window.location.hash;
if (a === "") return {}; this.uriParams = Utils.parseURIParams(params);
const b = {};
for (let i = 0; i < a.length; i++) {
const p = a[i].split("=");
if (p.length !== 2) {
b[a[i]] = true;
} else {
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
}
return b;
})(window.location.search.substr(1).split("&"));
// Pause auto-bake while loading but don't modify `this.autoBake_` // Pause auto-bake while loading but don't modify `this.autoBake_`
// otherwise `manualBake` cannot trigger. // otherwise `manualBake` cannot trigger.
this.autoBakePause = true; this.autoBakePause = true;
// Read in recipe from query string // Read in recipe from URI params
if (this.queryString.recipe) { if (this.uriParams.recipe) {
try { try {
const recipeConfig = JSON.parse(this.queryString.recipe); const recipeConfig = JSON.parse(this.uriParams.recipe);
this.setRecipeConfig(recipeConfig); this.setRecipeConfig(recipeConfig);
} catch (err) {} } catch (err) {}
} else if (this.queryString.op) { } else if (this.uriParams.op) {
// If there's no recipe, look for single operations // If there's no recipe, look for single operations
this.manager.recipe.clearRecipe(); this.manager.recipe.clearRecipe();
try { try {
this.manager.recipe.addOperation(this.queryString.op); this.manager.recipe.addOperation(this.uriParams.op);
} catch (err) { } catch (err) {
// If no exact match, search for nearest match and add that // If no exact match, search for nearest match and add that
const matchedOps = this.manager.ops.filterOperations(this.queryString.op, false); const matchedOps = this.manager.ops.filterOperations(this.uriParams.op, false);
if (matchedOps.length) { if (matchedOps.length) {
this.manager.recipe.addOperation(matchedOps[0].name); this.manager.recipe.addOperation(matchedOps[0].name);
} }
@ -439,15 +428,15 @@ App.prototype.loadURIParams = function() {
// Populate search with the string // Populate search with the string
const search = document.getElementById("search"); const search = document.getElementById("search");
search.value = this.queryString.op; search.value = this.uriParams.op;
search.dispatchEvent(new Event("search")); search.dispatchEvent(new Event("search"));
} }
} }
// Read in input data from query string // Read in input data from URI params
if (this.queryString.input) { if (this.uriParams.input) {
try { try {
const inputData = Utils.fromBase64(this.queryString.input); const inputData = Utils.fromBase64(this.uriParams.input);
this.setInput(inputData); this.setInput(inputData);
} catch (err) {} } catch (err) {}
} }

View File

@ -174,20 +174,21 @@ ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput
const inputStr = Utils.toBase64(this.app.getInput(), "A-Za-z0-9+/"); // B64 alphabet with no padding const inputStr = Utils.toBase64(this.app.getInput(), "A-Za-z0-9+/"); // B64 alphabet with no padding
includeRecipe = includeRecipe && (recipeConfig.length > 0); includeRecipe = includeRecipe && (recipeConfig.length > 0);
includeInput = includeInput && (inputStr.length > 0) && (inputStr.length < 8000); // Only inlcude input if it is less than 50KB (51200 * 4/3 as it is Base64 encoded)
includeInput = includeInput && (inputStr.length > 0) && (inputStr.length <= 68267);
const params = [ const params = [
includeRecipe ? ["recipe", recipeStr] : undefined, includeRecipe ? ["recipe", recipeStr] : undefined,
includeInput ? ["input", inputStr] : undefined, includeInput ? ["input", inputStr] : undefined,
]; ];
const query = params const hash = params
.filter(v => v) .filter(v => v)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`) .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join("&"); .join("&");
if (query) { if (hash) {
return `${link}?${query}`; return `${link}#${hash}`;
} }
return link; return link;

View File

@ -9,7 +9,7 @@
ga('create', 'UA-85682716-2', 'auto'); ga('create', 'UA-85682716-2', 'auto');
// Specifying location.pathname here overrides the default URL which would include arguments. // Specifying location.pathname here overrides the default URL which could include arguments.
// This method prevents Google Analytics from logging any recipe or input data in the URL. // This method prevents Google Analytics from logging any recipe or input data in the URL.
ga('send', 'pageview', location.pathname); ga('send', 'pageview', location.pathname);