Added more serious linting for app loader (#451)

master
Gordon Williams 2020-05-28 08:20:41 +01:00
parent 2fd2caaacc
commit 324c93de36
8 changed files with 167 additions and 137 deletions

1
.eslintignore Normal file
View File

@ -0,0 +1 @@
js/espruinotools.js

View File

@ -1 +0,0 @@
espruinotools.js

View File

@ -10,10 +10,40 @@
{
"SwitchCase": 1
}
]
],
"no-undef": "warn",
"no-redeclare": "warn",
"no-var": "warn",
"no-unused-vars":"off" // we define stuff to use in other scripts
},
"env": {
"browser": true,
"node": true
}
},
"extends": "eslint:recommended",
"globals": {
"btoa": "writable",
"Espruino": "writable",
"htmlElement": "readonly",
"Puck": "readonly",
"escapeHtml": "readonly",
"htmlToArray": "readonly",
"heatshrink": "readonly",
"Puck": "readonly",
"Promise": "readonly",
"Comms": "readonly",
"Progress": "readonly",
"showToast": "readonly",
"showPrompt": "readonly",
"httpGet": "readonly",
"getVersionInfo": "readonly",
"AppInfo": "readonly",
"marked": "readonly",
"appSorter": "readonly",
"Uint8Array" : "readonly",
"SETTINGS" : "readonly",
"globToRegex" : "readonly",
"toJS" : "readonly"
}
}

View File

@ -7,16 +7,16 @@ if (typeof btoa==="undefined") {
// Converts a string into most efficient way to send to Espruino (either json, base64, or compressed base64)
function toJS(txt) {
var json = JSON.stringify(txt);
var b64 = "atob("+JSON.stringify(btoa(json))+")";
var js = b64.length < json.length ? b64 : json;
let json = JSON.stringify(txt);
let b64 = "atob("+JSON.stringify(btoa(json))+")";
let js = b64.length < json.length ? b64 : json;
if (typeof heatshrink !== "undefined") {
var ua = new Uint8Array(txt.length);
for (var i=0;i<txt.length;i++) ua[i] = txt.charCodeAt(i);
var c = heatshrink.compress(ua);
var cs = "";
for (var i=0;i<c.length;i++)
let ua = new Uint8Array(txt.length);
for (let i=0;i<txt.length;i++) ua[i] = txt.charCodeAt(i);
let c = heatshrink.compress(ua);
let cs = "";
for (let i=0;i<c.length;i++)
cs += String.fromCharCode(c[i]);
cs = 'require("heatshrink").decompress(atob("'+btoa(cs)+'"))';
// if it's more than a little smaller, use compressed version
@ -30,7 +30,7 @@ function toJS(txt) {
if ("undefined"!=typeof module)
Espruino = require("./espruinotools.js");
var AppInfo = {
let AppInfo = {
/* Get files needed for app.
options = {
fileGetter : callback for getting URL,
@ -79,9 +79,9 @@ var AppInfo = {
} else {
let code = storageFile.content;
// write code in chunks, in case it is too big to fit in RAM (fix #157)
var CHUNKSIZE = 4096;
let CHUNKSIZE = 4096;
storageFile.cmd = `\x10require('Storage').write(${JSON.stringify(storageFile.name)},${toJS(code.substr(0,CHUNKSIZE))},0,${code.length});`;
for (var i=CHUNKSIZE;i<code.length;i+=CHUNKSIZE)
for (let i=CHUNKSIZE;i<code.length;i+=CHUNKSIZE)
storageFile.cmd += `\n\x10require('Storage').write(${JSON.stringify(storageFile.name)},${toJS(code.substr(i,CHUNKSIZE))},${i});`;
}
});
@ -91,12 +91,12 @@ var AppInfo = {
},
createAppJSON : (app, fileContents) => {
return new Promise((resolve,reject) => {
var appJSONName = app.id+".info";
let appJSONName = app.id+".info";
// Check we don't already have a JSON file!
var appJSONFile = fileContents.find(f=>f.name==appJSONName);
let appJSONFile = fileContents.find(f=>f.name==appJSONName);
if (appJSONFile) reject("App JSON file explicitly specified!");
// Now actually create the app JSON
var json = {
let json = {
id : app.id
};
if (app.shortName) json.name = app.shortName;
@ -108,7 +108,7 @@ var AppInfo = {
json.icon = app.id+".img";
if (app.sortorder) json.sortorder = app.sortorder;
if (app.version) json.version = app.version;
var fileList = fileContents.map(storageFile=>storageFile.name);
let fileList = fileContents.map(storageFile=>storageFile.name);
fileList.unshift(appJSONName); // do we want this? makes life easier!
json.files = fileList.join(",");
if ('data' in app) {

View File

@ -1,7 +1,7 @@
Puck.debug=3;
// FIXME: use UART lib so that we handle errors properly
var Comms = {
let Comms = {
reset : (opt) => new Promise((resolve,reject) => {
Puck.write(`\x03\x10reset(${opt=="wipe"?"1":""});\n`, (result) => {
if (result===null) return reject("Connection failed");
@ -16,13 +16,13 @@ var Comms = {
}).then(fileContents => {
return new Promise((resolve,reject) => {
console.log("uploadApp",fileContents.map(f=>f.name).join(", "));
var maxBytes = fileContents.reduce((b,f)=>b+f.cmd.length, 0)||1;
var currentBytes = 0;
let maxBytes = fileContents.reduce((b,f)=>b+f.cmd.length, 0)||1;
let currentBytes = 0;
var appInfoFileName = app.id+".info";
var appInfoFile = fileContents.find(f=>f.name==appInfoFileName);
let appInfoFileName = app.id+".info";
let appInfoFile = fileContents.find(f=>f.name==appInfoFileName);
if (!appInfoFile) reject(`${appInfoFileName} not found`);
var appInfo = JSON.parse(appInfoFile.content);
let appInfo = JSON.parse(appInfoFile.content);
// Upload each file one at a time
function doUploadFiles() {
@ -35,14 +35,14 @@ var Comms = {
});
return;
}
var f = fileContents.shift();
let f = fileContents.shift();
console.log(`Upload ${f.name} => ${JSON.stringify(f.content)}`);
// Chould check CRC here if needed instead of returning 'OK'...
// E.CRC32(require("Storage").read(${JSON.stringify(app.name)}))
var cmds = f.cmd.split("\n");
let cmds = f.cmd.split("\n");
function uploadCmd() {
if (!cmds.length) return doUploadFiles();
var cmd = cmds.shift();
let cmd = cmds.shift();
Progress.show({
min:currentBytes / maxBytes,
max:(currentBytes+cmd.length) / maxBytes});
@ -84,7 +84,7 @@ var Comms = {
Progress.hide({sticky:true});
return reject("");
}
Puck.write('\x10Bluetooth.print("[");require("Storage").list(/\.info$/).forEach(f=>{var j=require("Storage").readJSON(f,1)||{};j.id=f.slice(0,-5);Bluetooth.print(JSON.stringify(j)+",")});Bluetooth.println("0]")\n', (appList,err) => {
Puck.write('\x10Bluetooth.print("[");require("Storage").list(/\\.info$/).forEach(f=>{var j=require("Storage").readJSON(f,1)||{};j.id=f.slice(0,-5);Bluetooth.print(JSON.stringify(j)+",")});Bluetooth.println("0]")\n', (appList,err) => {
Progress.hide({sticky:true});
try {
appList = JSON.parse(appList);
@ -152,9 +152,9 @@ var Comms = {
},
setTime : () => {
return new Promise((resolve,reject) => {
var d = new Date();
var tz = d.getTimezoneOffset()/-60
var cmd = '\x03\x10setTime('+(d.getTime()/1000)+');';
let d = new Date();
let tz = d.getTimezoneOffset()/-60
let cmd = '\x03\x10setTime('+(d.getTime()/1000)+');';
// in 1v93 we have timezones too
cmd += 'E.setTimeZone('+tz+');';
cmd += "(s=>{s&&(s.timezone="+tz+")&&require('Storage').write('setting.json',s);})(require('Storage').readJSON('setting.json',1))\n";
@ -165,17 +165,17 @@ var Comms = {
});
},
disconnectDevice: () => {
var connection = Puck.getConnection();
let connection = Puck.getConnection();
if (!connection) return;
connection.close();
},
watchConnectionChange : cb => {
var connected = Puck.isConnected();
let connected = Puck.isConnected();
//TODO Switch to an event listener when Puck will support it
var interval = setInterval(() => {
let interval = setInterval(() => {
if (connected === Puck.isConnected()) return;
connected = Puck.isConnected();
@ -220,20 +220,20 @@ var Comms = {
readStorageFile : (filename) => { // StorageFiles are different to normal storage entries
return new Promise((resolve,reject) => {
// Use "\xFF" to signal end of file (can't occur in files anyway)
var fileContent = "";
var fileSize = undefined;
var connection = Puck.getConnection();
let fileContent = "";
let fileSize = undefined;
let connection = Puck.getConnection();
connection.received = "";
connection.cb = function(d) {
var finished = false;
var eofIndex = d.indexOf("\xFF");
let finished = false;
let eofIndex = d.indexOf("\xFF");
if (eofIndex>=0) {
finished = true;
d = d.substr(0,eofIndex);
}
fileContent += d;
if (fileSize === undefined) {
var newLineIdx = fileContent.indexOf("\n");
let newLineIdx = fileContent.indexOf("\n");
if (newLineIdx>=0) {
fileSize = parseInt(fileContent.substr(0,newLineIdx));
console.log("File size is "+fileSize);

View File

@ -1,12 +1,12 @@
var appJSON = []; // List of apps and info from apps.json
var appsInstalled = []; // list of app JSON
var appSortInfo = {}; // list of data to sort by, from appdates.csv { created, modified }
var files = []; // list of files on Bangle
var DEFAULTSETTINGS = {
let appJSON = []; // List of apps and info from apps.json
let appsInstalled = []; // list of app JSON
let appSortInfo = {}; // list of data to sort by, from appdates.csv { created, modified }
let files = []; // list of files on Bangle
let DEFAULTSETTINGS = {
pretokenise : true,
favourites : ["boot","launch","setting"]
};
var SETTINGS = JSON.parse(JSON.stringify(DEFAULTSETTINGS)); // clone
let SETTINGS = JSON.parse(JSON.stringify(DEFAULTSETTINGS)); // clone
httpGet("apps.json").then(apps=>{
try {
@ -23,7 +23,7 @@ httpGet("apps.json").then(apps=>{
httpGet("appdates.csv").then(csv=>{
document.querySelector(".sort-nav").classList.remove("hidden");
csv.split("\n").forEach(line=>{
var l = line.split(",");
let l = line.split(",");
appSortInfo[l[0]] = {
created : Date.parse(l[1]),
modified : Date.parse(l[2])
@ -35,7 +35,7 @@ httpGet("appdates.csv").then(csv=>{
// =========================================== Top Navigation
function showChangeLog(appid) {
var app = appNameToApp(appid);
let app = appNameToApp(appid);
function show(contents) {
showPrompt(app.name+" Change Log",contents,{ok:true}).catch(()=>{});
}
@ -43,9 +43,9 @@ function showChangeLog(appid) {
then(show).catch(()=>show("No Change Log available"));
}
function showReadme(appid) {
var app = appNameToApp(appid);
var appPath = `apps/${appid}/`;
var markedOptions = { baseUrl : appPath };
let app = appNameToApp(appid);
let appPath = `apps/${appid}/`;
let markedOptions = { baseUrl : appPath };
function show(contents) {
if (!contents) return;
showPrompt(app.name + " Documentation", marked(contents, markedOptions), {ok: true}, false).catch(() => {});
@ -56,7 +56,7 @@ function handleCustomApp(appTemplate) {
// Pops up an IFRAME that allows an app to be customised
if (!appTemplate.custom) throw new Error("App doesn't have custom HTML");
return new Promise((resolve,reject) => {
var modal = htmlElement(`<div class="modal active">
let modal = htmlElement(`<div class="modal active">
<a href="#close" class="modal-overlay " aria-label="Close"></a>
<div class="modal-container" style="height:100%">
<div class="modal-header">
@ -79,10 +79,10 @@ function handleCustomApp(appTemplate) {
});
});
var iframe = modal.getElementsByTagName("iframe")[0];
let iframe = modal.getElementsByTagName("iframe")[0];
iframe.contentWindow.addEventListener("message", function(event) {
var appFiles = event.data;
var app = JSON.parse(JSON.stringify(appTemplate)); // clone template
let appFiles = event.data;
let app = JSON.parse(JSON.stringify(appTemplate)); // clone template
// copy extra keys from appFiles
Object.keys(appFiles).forEach(k => {
if (k!="storage") app[k] = appFiles[k]
@ -108,7 +108,7 @@ function handleAppInterface(app) {
// IFRAME interface window that can be used to get data from the app
if (!app.interface) throw new Error("App doesn't have interface HTML");
return new Promise((resolve,reject) => {
var modal = htmlElement(`<div class="modal active">
let modal = htmlElement(`<div class="modal active">
<a href="#close" class="modal-overlay " aria-label="Close"></a>
<div class="modal-container" style="height:100%">
<div class="modal-header">
@ -130,11 +130,11 @@ function handleAppInterface(app) {
//reject("Window closed");
});
});
var iframe = modal.getElementsByTagName("iframe")[0];
let iframe = modal.getElementsByTagName("iframe")[0];
iframe.onload = function() {
var iwin = iframe.contentWindow;
let iwin = iframe.contentWindow;
iwin.addEventListener("message", function(event) {
var msg = event.data;
let msg = event.data;
if (msg.type=="eval") {
Puck.eval(msg.data, function(result) {
iwin.postMessage({
@ -168,7 +168,7 @@ function handleAppInterface(app) {
}
function changeAppFavourite(favourite, app) {
var favourites = SETTINGS.favourites;
let favourites = SETTINGS.favourites;
if (favourite) {
SETTINGS.favourites = SETTINGS.favourites.concat([app.id]);
} else {
@ -197,29 +197,29 @@ function showTab(tabname) {
// =========================================== Library
// Can't use chip.attributes.filterid.value here because Safari/Apple's WebView doesn't handle it
var chips = Array.from(document.querySelectorAll('.filter-nav .chip')).map(chip => chip.getAttribute("filterid"));
var hash = window.location.hash ? window.location.hash.slice(1) : '';
let chips = Array.from(document.querySelectorAll('.filter-nav .chip')).map(chip => chip.getAttribute("filterid"));
let hash = window.location.hash ? window.location.hash.slice(1) : '';
var activeFilter = !!~chips.indexOf(hash) ? hash : '';
var activeSort = '';
var currentSearch = activeFilter ? '' : hash;
let activeFilter = ~chips.indexOf(hash) ? hash : '';
let activeSort = '';
let currentSearch = activeFilter ? '' : hash;
function refreshFilter(){
var filtersContainer = document.querySelector("#librarycontainer .filter-nav");
let filtersContainer = document.querySelector("#librarycontainer .filter-nav");
filtersContainer.querySelector('.active').classList.remove('active');
if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active');
else filtersContainer.querySelector('.chip[filterid]').classList.add('active');
}
function refreshSort(){
var sortContainer = document.querySelector("#librarycontainer .sort-nav");
let sortContainer = document.querySelector("#librarycontainer .sort-nav");
sortContainer.querySelector('.active').classList.remove('active');
if(activeSort) sortContainer.querySelector('.chip[sortid="'+activeSort+'"]').classList.add('active');
else sortContainer.querySelector('.chip[sortid]').classList.add('active');
}
function refreshLibrary() {
var panelbody = document.querySelector("#librarycontainer .panel-body");
var visibleApps = appJSON;
var favourites = SETTINGS.favourites;
let panelbody = document.querySelector("#librarycontainer .panel-body");
let visibleApps = appJSON;
let favourites = SETTINGS.favourites;
if (activeFilter) {
if ( activeFilter == "favourites" ) {
@ -241,17 +241,17 @@ function refreshLibrary() {
}
panelbody.innerHTML = visibleApps.map((app,idx) => {
var appInstalled = appsInstalled.find(a=>a.id==app.id);
var version = getVersionInfo(app, appInstalled);
var versionInfo = version.text;
let appInstalled = appsInstalled.find(a=>a.id==app.id);
let version = getVersionInfo(app, appInstalled);
let versionInfo = version.text;
if (versionInfo) versionInfo = " <small>("+versionInfo+")</small>";
var readme = `<a class="c-hand" onclick="showReadme('${app.id}')">Read more...</a>`;
var favourite = favourites.find(e => e == app.id);
let readme = `<a class="c-hand" onclick="showReadme('${app.id}')">Read more...</a>`;
let favourite = favourites.find(e => e == app.id);
var username = "espruino";
var githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
let username = "espruino";
let githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
if(githubMatch) username = githubMatch[1];
var url = `https://github.com/${username}/BangleApps/tree/master/apps/${app.id}`;
let url = `https://github.com/${username}/BangleApps/tree/master/apps/${app.id}`;
return `<div class="tile column col-6 col-sm-12 col-xs-12">
<div class="tile-icon">
@ -274,27 +274,27 @@ function refreshLibrary() {
</div>
`;}).join("");
// set badge up top
var tab = document.querySelector("#tab-librarycontainer a");
let tab = document.querySelector("#tab-librarycontainer a");
tab.classList.add("badge");
tab.setAttribute("data-badge", appJSON.length);
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
button.addEventListener("click",event => {
var button = event.currentTarget;
var icon = button.firstChild;
var appid = button.getAttribute("appid");
var app = appNameToApp(appid);
let button = event.currentTarget;
let icon = button.firstChild;
let appid = button.getAttribute("appid");
let app = appNameToApp(appid);
if (!app) throw new Error("App "+appid+" not found");
// check icon to figure out what we should do
if (icon.classList.contains("icon-share")) {
// emulator
var file = app.storage.find(f=>f.name.endsWith('.js'));
let file = app.storage.find(f=>f.name.endsWith('.js'));
if (!file) {
console.error("No entrypoint found for "+appid);
return;
}
var baseurl = window.location.href;
let baseurl = window.location.href;
baseurl = baseurl.substr(0,baseurl.lastIndexOf("/"));
var url = baseurl+"/apps/"+app.id+"/"+file.url;
let url = baseurl+"/apps/"+app.id+"/"+file.url;
window.open(`https://espruino.com/ide/emulator.html?codeurl=${url}&upload`);
} else if (icon.classList.contains("icon-upload")) {
// upload
@ -421,7 +421,7 @@ function updateApp(app) {
function appNameToApp(appName) {
var app = appJSON.find(app=>app.id==appName);
let app = appJSON.find(app=>app.id==appName);
if (app) return app;
/* If app not known, add just one file
which is the JSON - so we'll remove it from
@ -436,8 +436,8 @@ function appNameToApp(appName) {
}
function showLoadingIndicator(id) {
var panelbody = document.querySelector(`#${id} .panel-body`);
var tab = document.querySelector(`#tab-${id} a`);
let panelbody = document.querySelector(`#${id} .panel-body`);
let tab = document.querySelector(`#tab-${id} a`);
// set badge up top
tab.classList.add("badge");
tab.setAttribute("data-badge", "");
@ -446,9 +446,9 @@ function showLoadingIndicator(id) {
}
function getAppsToUpdate() {
var appsToUpdate = [];
let appsToUpdate = [];
appsInstalled.forEach(appInstalled => {
var app = appNameToApp(appInstalled.id);
let app = appNameToApp(appInstalled.id);
if (app.version != appInstalled.version)
appsToUpdate.push(app);
});
@ -456,14 +456,14 @@ function getAppsToUpdate() {
}
function refreshMyApps() {
var panelbody = document.querySelector("#myappscontainer .panel-body");
let panelbody = document.querySelector("#myappscontainer .panel-body");
panelbody.innerHTML = appsInstalled.map(appInstalled => {
var app = appNameToApp(appInstalled.id);
var version = getVersionInfo(app, appInstalled);
var username = "espruino";
var githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
let app = appNameToApp(appInstalled.id);
let version = getVersionInfo(app, appInstalled);
let username = "espruino";
let githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
if(githubMatch) username = githubMatch[1];
var url = `https://github.com/${username}/BangleApps/tree/master/apps/${app.id}`;
let url = `https://github.com/${username}/BangleApps/tree/master/apps/${app.id}`;
return `<div class="tile column col-6 col-sm-12 col-xs-12">
<div class="tile-icon">
<figure class="avatar"><img src="apps/${app.icon?`${app.id}/${app.icon}`:"unknown.png"}" alt="${escapeHtml(app.name)}"></figure>
@ -482,10 +482,10 @@ function refreshMyApps() {
`}).join("");
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
button.addEventListener("click",event => {
var button = event.currentTarget;
var icon = button.firstChild;
var appid = button.getAttribute("appid");
var app = appNameToApp(appid);
let button = event.currentTarget;
let icon = button.firstChild;
let appid = button.getAttribute("appid");
let app = appNameToApp(appid);
if (!app) throw new Error("App "+appid+" not found");
// check icon to figure out what we should do
if (icon.classList.contains("icon-delete")) removeApp(app);
@ -493,9 +493,9 @@ function refreshMyApps() {
if (icon.classList.contains("icon-download")) handleAppInterface(app);
});
});
var appsToUpdate = getAppsToUpdate();
var tab = document.querySelector("#tab-myappscontainer a");
var updateApps = document.querySelector("#myappscontainer .updateapps");
let appsToUpdate = getAppsToUpdate();
let tab = document.querySelector("#tab-myappscontainer a");
let updateApps = document.querySelector("#myappscontainer .updateapps");
if (appsToUpdate.length) {
updateApps.innerHTML = `Update ${appsToUpdate.length} apps`;
updateApps.classList.remove("hidden");
@ -529,10 +529,10 @@ function getInstalledApps(refresh) {
/// Removes everything and install the given apps, eg: installMultipleApps(["boot","mclock"], "minimal")
function installMultipleApps(appIds, promptName) {
var apps = appIds.map( appid => appJSON.find(app=>app.id==appid) );
let apps = appIds.map( appid => appJSON.find(app=>app.id==appid) );
if (apps.some(x=>x===undefined))
return Promise.reject("Not all apps found");
var appCount = apps.length;
let appCount = apps.length;
return showPrompt("Install Defaults",`Remove everything and install ${promptName} apps?`).then(() => {
return Comms.removeAllApps();
}).then(()=>{
@ -541,7 +541,7 @@ function installMultipleApps(appIds, promptName) {
showToast(`Existing apps removed. Installing ${appCount} apps...`);
return new Promise((resolve,reject) => {
function upload() {
var app = apps.shift();
let app = apps.shift();
if (app===undefined) return resolve();
Progress.show({title:`${app.name} (${appCount-apps.length}/${appCount})`,sticky:true});
Comms.uploadApp(app,"skip_reset").then((appJSON) => {
@ -564,7 +564,7 @@ function installMultipleApps(appIds, promptName) {
});
}
var connectMyDeviceBtn = document.getElementById("connectmydevice");
let connectMyDeviceBtn = document.getElementById("connectmydevice");
function handleConnectionChange(connected) {
connectMyDeviceBtn.textContent = connected ? 'Disconnect' : 'Connect';
@ -577,11 +577,11 @@ htmlToArray(document.querySelectorAll(".btn.refresh")).map(button => button.addE
});
}));
htmlToArray(document.querySelectorAll(".btn.updateapps")).map(button => button.addEventListener("click", () => {
var appsToUpdate = getAppsToUpdate();
var count = appsToUpdate.length;
let appsToUpdate = getAppsToUpdate();
let count = appsToUpdate.length;
function updater() {
if (!appsToUpdate.length) return;
var app = appsToUpdate.pop();
let app = appsToUpdate.pop();
return updateApp(app).then(function() {
return updater();
});
@ -603,7 +603,7 @@ connectMyDeviceBtn.addEventListener("click", () => {
});
Comms.watchConnectionChange(handleConnectionChange);
var filtersContainer = document.querySelector("#librarycontainer .filter-nav");
let filtersContainer = document.querySelector("#librarycontainer .filter-nav");
filtersContainer.addEventListener('click', ({ target }) => {
if (target.classList.contains('active')) return;
@ -613,14 +613,14 @@ filtersContainer.addEventListener('click', ({ target }) => {
window.location.hash = activeFilter;
});
var librarySearchInput = document.querySelector("#searchform input");
let librarySearchInput = document.querySelector("#searchform input");
librarySearchInput.value = currentSearch;
librarySearchInput.addEventListener('input', evt => {
currentSearch = evt.target.value.toLowerCase();
refreshLibrary();
});
var sortContainer = document.querySelector("#librarycontainer .sort-nav");
let sortContainer = document.querySelector("#librarycontainer .sort-nav");
sortContainer.addEventListener('click', ({ target }) => {
if (target.classList.contains('active')) return;
@ -646,13 +646,13 @@ if (window.location.host=="banglejs.com") {
}
// Settings
var SETTINGS_HOOKS = {}; // stuff to get called when a setting is loaded
let SETTINGS_HOOKS = {}; // stuff to get called when a setting is loaded
/// Load settings and update controls
function loadSettings() {
var j = localStorage.getItem("settings");
let j = localStorage.getItem("settings");
if (typeof j != "string") return;
try {
var s = JSON.parse(j);
let s = JSON.parse(j);
Object.keys(s).forEach( k => {
SETTINGS[k]=s[k];
if (SETTINGS_HOOKS[k]) SETTINGS_HOOKS[k]();
@ -668,7 +668,7 @@ function saveSettings() {
}
// Link in settings DOM elements
function settingsCheckbox(id, name) {
var setting = document.getElementById(id);
let setting = document.getElementById(id);
function update() {
setting.checked = SETTINGS[name];
}
@ -720,7 +720,7 @@ document.getElementById("installdefault").addEventListener("click",event=>{
// Install all favourite apps in one go
document.getElementById("installfavourite").addEventListener("click",event=>{
var favApps = SETTINGS.favourites;
let favApps = SETTINGS.favourites;
installMultipleApps(favApps, "favourite").catch(err=>{
Progress.hide({sticky:true});
showToast("App Install failed, "+err,"error");

View File

@ -1,7 +1,7 @@
// General UI tools (progress bar, toast, prompt)
/// Handle progress bars
var Progress = {
let Progress = {
domElement : null, // the DOM element
sticky : false, // Progress.show({..., sticky:true}) don't remove until Progress.hide({sticky:true})
interval : undefined, // the interval used if Progress.show({progress:"animate"})
@ -18,11 +18,11 @@ var Progress = {
}) */
show : function(options) {
options = options||{};
var text = options.title;
let text = options.title;
if (options.sticky) Progress.sticky = true;
if (options.min!==undefined) Progress.min = options.min;
if (options.max!==undefined) Progress.max = options.max;
var percent = options.percent;
let percent = options.percent;
if (percent!==undefined)
percent = Progress.min*100 + (Progress.max-Progress.min)*percent;
if (!Progress.domElement) {
@ -39,7 +39,7 @@ var Progress = {
percent = 0;
}
var toastcontainer = document.getElementById("toastcontainer");
let toastcontainer = document.getElementById("toastcontainer");
Progress.domElement = htmlElement(`<div class="toast">
${text ? `<div>${text}</div>`:``}
<div class="bar bar-sm">
@ -48,7 +48,7 @@ var Progress = {
</div>`);
toastcontainer.append(Progress.domElement);
} else {
var pt=document.getElementById("Progress.domElement");
let pt=document.getElementById("Progress.domElement");
pt.setAttribute("aria-valuenow",percent);
pt.style.width = percent+"%";
}
@ -76,20 +76,20 @@ Puck.writeProgress = function(charsSent, charsTotal) {
Progress.hide();
return;
}
var percent = Math.round(charsSent*100/charsTotal);
let percent = Math.round(charsSent*100/charsTotal);
Progress.show({percent: percent});
}
/// Show a 'toast' message for status
function showToast(message, type) {
// toast-primary, toast-success, toast-warning or toast-error
var style = "toast-primary";
let style = "toast-primary";
if (type=="success") style = "toast-success";
else if (type=="error") style = "toast-error";
else if (type=="warning") style = "toast-warning";
else if (type!==undefined) console.log("showToast: unknown toast "+type);
var toastcontainer = document.getElementById("toastcontainer");
var msgDiv = htmlElement(`<div class="toast ${style}"></div>`);
let toastcontainer = document.getElementById("toastcontainer");
let msgDiv = htmlElement(`<div class="toast ${style}"></div>`);
msgDiv.innerHTML = message;
toastcontainer.append(msgDiv);
setTimeout(function() {
@ -103,7 +103,7 @@ function showPrompt(title, text, buttons, shouldEscapeHtml) {
if (typeof(shouldEscapeHtml) === 'undefined' || shouldEscapeHtml === null) shouldEscapeHtml = true;
return new Promise((resolve,reject) => {
var modal = htmlElement(`<div class="modal active">
let modal = htmlElement(`<div class="modal active">
<!--<a href="#close" class="modal-overlay" aria-label="Close"></a>-->
<div class="modal-container">
<div class="modal-header">
@ -133,7 +133,7 @@ function showPrompt(title, text, buttons, shouldEscapeHtml) {
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
button.addEventListener("click",event => {
event.preventDefault();
var isYes = event.target.getAttribute("isyes")=="1";
let isYes = event.target.getAttribute("isyes")=="1";
if (isYes) resolve();
else reject("User cancelled");
modal.remove();

View File

@ -1,5 +1,5 @@
function escapeHtml(text) {
var map = {
let map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
@ -24,13 +24,13 @@ function htmlToArray(collection) {
return [].slice.call(collection);
}
function htmlElement(str) {
var div = document.createElement('div');
let div = document.createElement('div');
div.innerHTML = str.trim();
return div.firstChild;
}
function httpGet(url) {
return new Promise((resolve,reject) => {
var oReq = new XMLHttpRequest();
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", () => {
if (oReq.status==200) resolve(oReq.responseText)
else reject(oReq.status+" - "+oReq.statusText);
@ -51,8 +51,8 @@ function toJS(txt) {
function appSorter(a,b) {
if (a.unknown || b.unknown)
return (a.unknown)? 1 : -1;
var sa = 0|a.sortorder;
var sb = 0|b.sortorder;
let sa = 0|a.sortorder;
let sb = 0|b.sortorder;
if (sa<sb) return -1;
if (sa>sb) return 1;
return (a.name==b.name) ? 0 : ((a.name<b.name) ? -1 : 1);
@ -61,8 +61,8 @@ function appSorter(a,b) {
/* Given 2 JSON structures (1st from apps.json, 2nd from an installed app)
work out what to display re: versions and if we can update */
function getVersionInfo(appListing, appInstalled) {
var versionText = "";
var canUpdate = false;
let versionText = "";
let canUpdate = false;
function clicky(v) {
return `<a class="c-hand" onclick="showChangeLog('${appListing.id}')">${v}</a>`;
}