Added more serious linting for app loader (#451)
parent
2fd2caaacc
commit
324c93de36
|
|
@ -0,0 +1 @@
|
||||||
|
js/espruinotools.js
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
espruinotools.js
|
|
||||||
|
|
@ -10,10 +10,40 @@
|
||||||
{
|
{
|
||||||
"SwitchCase": 1
|
"SwitchCase": 1
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"no-undef": "warn",
|
||||||
|
"no-redeclare": "warn",
|
||||||
|
"no-var": "warn",
|
||||||
|
"no-unused-vars":"off" // we define stuff to use in other scripts
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"node": 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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
// Converts a string into most efficient way to send to Espruino (either json, base64, or compressed base64)
|
||||||
function toJS(txt) {
|
function toJS(txt) {
|
||||||
var json = JSON.stringify(txt);
|
let json = JSON.stringify(txt);
|
||||||
var b64 = "atob("+JSON.stringify(btoa(json))+")";
|
let b64 = "atob("+JSON.stringify(btoa(json))+")";
|
||||||
var js = b64.length < json.length ? b64 : json;
|
let js = b64.length < json.length ? b64 : json;
|
||||||
|
|
||||||
if (typeof heatshrink !== "undefined") {
|
if (typeof heatshrink !== "undefined") {
|
||||||
var ua = new Uint8Array(txt.length);
|
let ua = new Uint8Array(txt.length);
|
||||||
for (var i=0;i<txt.length;i++) ua[i] = txt.charCodeAt(i);
|
for (let i=0;i<txt.length;i++) ua[i] = txt.charCodeAt(i);
|
||||||
var c = heatshrink.compress(ua);
|
let c = heatshrink.compress(ua);
|
||||||
var cs = "";
|
let cs = "";
|
||||||
for (var i=0;i<c.length;i++)
|
for (let i=0;i<c.length;i++)
|
||||||
cs += String.fromCharCode(c[i]);
|
cs += String.fromCharCode(c[i]);
|
||||||
cs = 'require("heatshrink").decompress(atob("'+btoa(cs)+'"))';
|
cs = 'require("heatshrink").decompress(atob("'+btoa(cs)+'"))';
|
||||||
// if it's more than a little smaller, use compressed version
|
// if it's more than a little smaller, use compressed version
|
||||||
|
|
@ -30,7 +30,7 @@ function toJS(txt) {
|
||||||
if ("undefined"!=typeof module)
|
if ("undefined"!=typeof module)
|
||||||
Espruino = require("./espruinotools.js");
|
Espruino = require("./espruinotools.js");
|
||||||
|
|
||||||
var AppInfo = {
|
let AppInfo = {
|
||||||
/* Get files needed for app.
|
/* Get files needed for app.
|
||||||
options = {
|
options = {
|
||||||
fileGetter : callback for getting URL,
|
fileGetter : callback for getting URL,
|
||||||
|
|
@ -79,9 +79,9 @@ var AppInfo = {
|
||||||
} else {
|
} else {
|
||||||
let code = storageFile.content;
|
let code = storageFile.content;
|
||||||
// write code in chunks, in case it is too big to fit in RAM (fix #157)
|
// 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});`;
|
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});`;
|
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) => {
|
createAppJSON : (app, fileContents) => {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
var appJSONName = app.id+".info";
|
let appJSONName = app.id+".info";
|
||||||
// Check we don't already have a JSON file!
|
// 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!");
|
if (appJSONFile) reject("App JSON file explicitly specified!");
|
||||||
// Now actually create the app JSON
|
// Now actually create the app JSON
|
||||||
var json = {
|
let json = {
|
||||||
id : app.id
|
id : app.id
|
||||||
};
|
};
|
||||||
if (app.shortName) json.name = app.shortName;
|
if (app.shortName) json.name = app.shortName;
|
||||||
|
|
@ -108,7 +108,7 @@ var AppInfo = {
|
||||||
json.icon = app.id+".img";
|
json.icon = app.id+".img";
|
||||||
if (app.sortorder) json.sortorder = app.sortorder;
|
if (app.sortorder) json.sortorder = app.sortorder;
|
||||||
if (app.version) json.version = app.version;
|
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!
|
fileList.unshift(appJSONName); // do we want this? makes life easier!
|
||||||
json.files = fileList.join(",");
|
json.files = fileList.join(",");
|
||||||
if ('data' in app) {
|
if ('data' in app) {
|
||||||
|
|
|
||||||
44
js/comms.js
44
js/comms.js
|
|
@ -1,7 +1,7 @@
|
||||||
Puck.debug=3;
|
Puck.debug=3;
|
||||||
|
|
||||||
// FIXME: use UART lib so that we handle errors properly
|
// FIXME: use UART lib so that we handle errors properly
|
||||||
var Comms = {
|
let Comms = {
|
||||||
reset : (opt) => new Promise((resolve,reject) => {
|
reset : (opt) => new Promise((resolve,reject) => {
|
||||||
Puck.write(`\x03\x10reset(${opt=="wipe"?"1":""});\n`, (result) => {
|
Puck.write(`\x03\x10reset(${opt=="wipe"?"1":""});\n`, (result) => {
|
||||||
if (result===null) return reject("Connection failed");
|
if (result===null) return reject("Connection failed");
|
||||||
|
|
@ -16,13 +16,13 @@ var Comms = {
|
||||||
}).then(fileContents => {
|
}).then(fileContents => {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
console.log("uploadApp",fileContents.map(f=>f.name).join(", "));
|
console.log("uploadApp",fileContents.map(f=>f.name).join(", "));
|
||||||
var maxBytes = fileContents.reduce((b,f)=>b+f.cmd.length, 0)||1;
|
let maxBytes = fileContents.reduce((b,f)=>b+f.cmd.length, 0)||1;
|
||||||
var currentBytes = 0;
|
let currentBytes = 0;
|
||||||
|
|
||||||
var appInfoFileName = app.id+".info";
|
let appInfoFileName = app.id+".info";
|
||||||
var appInfoFile = fileContents.find(f=>f.name==appInfoFileName);
|
let appInfoFile = fileContents.find(f=>f.name==appInfoFileName);
|
||||||
if (!appInfoFile) reject(`${appInfoFileName} not found`);
|
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
|
// Upload each file one at a time
|
||||||
function doUploadFiles() {
|
function doUploadFiles() {
|
||||||
|
|
@ -35,14 +35,14 @@ var Comms = {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var f = fileContents.shift();
|
let f = fileContents.shift();
|
||||||
console.log(`Upload ${f.name} => ${JSON.stringify(f.content)}`);
|
console.log(`Upload ${f.name} => ${JSON.stringify(f.content)}`);
|
||||||
// Chould check CRC here if needed instead of returning 'OK'...
|
// Chould check CRC here if needed instead of returning 'OK'...
|
||||||
// E.CRC32(require("Storage").read(${JSON.stringify(app.name)}))
|
// E.CRC32(require("Storage").read(${JSON.stringify(app.name)}))
|
||||||
var cmds = f.cmd.split("\n");
|
let cmds = f.cmd.split("\n");
|
||||||
function uploadCmd() {
|
function uploadCmd() {
|
||||||
if (!cmds.length) return doUploadFiles();
|
if (!cmds.length) return doUploadFiles();
|
||||||
var cmd = cmds.shift();
|
let cmd = cmds.shift();
|
||||||
Progress.show({
|
Progress.show({
|
||||||
min:currentBytes / maxBytes,
|
min:currentBytes / maxBytes,
|
||||||
max:(currentBytes+cmd.length) / maxBytes});
|
max:(currentBytes+cmd.length) / maxBytes});
|
||||||
|
|
@ -84,7 +84,7 @@ var Comms = {
|
||||||
Progress.hide({sticky:true});
|
Progress.hide({sticky:true});
|
||||||
return reject("");
|
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});
|
Progress.hide({sticky:true});
|
||||||
try {
|
try {
|
||||||
appList = JSON.parse(appList);
|
appList = JSON.parse(appList);
|
||||||
|
|
@ -152,9 +152,9 @@ var Comms = {
|
||||||
},
|
},
|
||||||
setTime : () => {
|
setTime : () => {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
var d = new Date();
|
let d = new Date();
|
||||||
var tz = d.getTimezoneOffset()/-60
|
let tz = d.getTimezoneOffset()/-60
|
||||||
var cmd = '\x03\x10setTime('+(d.getTime()/1000)+');';
|
let cmd = '\x03\x10setTime('+(d.getTime()/1000)+');';
|
||||||
// in 1v93 we have timezones too
|
// in 1v93 we have timezones too
|
||||||
cmd += 'E.setTimeZone('+tz+');';
|
cmd += 'E.setTimeZone('+tz+');';
|
||||||
cmd += "(s=>{s&&(s.timezone="+tz+")&&require('Storage').write('setting.json',s);})(require('Storage').readJSON('setting.json',1))\n";
|
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: () => {
|
disconnectDevice: () => {
|
||||||
var connection = Puck.getConnection();
|
let connection = Puck.getConnection();
|
||||||
|
|
||||||
if (!connection) return;
|
if (!connection) return;
|
||||||
|
|
||||||
connection.close();
|
connection.close();
|
||||||
},
|
},
|
||||||
watchConnectionChange : cb => {
|
watchConnectionChange : cb => {
|
||||||
var connected = Puck.isConnected();
|
let connected = Puck.isConnected();
|
||||||
|
|
||||||
//TODO Switch to an event listener when Puck will support it
|
//TODO Switch to an event listener when Puck will support it
|
||||||
var interval = setInterval(() => {
|
let interval = setInterval(() => {
|
||||||
if (connected === Puck.isConnected()) return;
|
if (connected === Puck.isConnected()) return;
|
||||||
|
|
||||||
connected = Puck.isConnected();
|
connected = Puck.isConnected();
|
||||||
|
|
@ -220,20 +220,20 @@ var Comms = {
|
||||||
readStorageFile : (filename) => { // StorageFiles are different to normal storage entries
|
readStorageFile : (filename) => { // StorageFiles are different to normal storage entries
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
// Use "\xFF" to signal end of file (can't occur in files anyway)
|
// Use "\xFF" to signal end of file (can't occur in files anyway)
|
||||||
var fileContent = "";
|
let fileContent = "";
|
||||||
var fileSize = undefined;
|
let fileSize = undefined;
|
||||||
var connection = Puck.getConnection();
|
let connection = Puck.getConnection();
|
||||||
connection.received = "";
|
connection.received = "";
|
||||||
connection.cb = function(d) {
|
connection.cb = function(d) {
|
||||||
var finished = false;
|
let finished = false;
|
||||||
var eofIndex = d.indexOf("\xFF");
|
let eofIndex = d.indexOf("\xFF");
|
||||||
if (eofIndex>=0) {
|
if (eofIndex>=0) {
|
||||||
finished = true;
|
finished = true;
|
||||||
d = d.substr(0,eofIndex);
|
d = d.substr(0,eofIndex);
|
||||||
}
|
}
|
||||||
fileContent += d;
|
fileContent += d;
|
||||||
if (fileSize === undefined) {
|
if (fileSize === undefined) {
|
||||||
var newLineIdx = fileContent.indexOf("\n");
|
let newLineIdx = fileContent.indexOf("\n");
|
||||||
if (newLineIdx>=0) {
|
if (newLineIdx>=0) {
|
||||||
fileSize = parseInt(fileContent.substr(0,newLineIdx));
|
fileSize = parseInt(fileContent.substr(0,newLineIdx));
|
||||||
console.log("File size is "+fileSize);
|
console.log("File size is "+fileSize);
|
||||||
|
|
|
||||||
158
js/index.js
158
js/index.js
|
|
@ -1,12 +1,12 @@
|
||||||
var appJSON = []; // List of apps and info from apps.json
|
let appJSON = []; // List of apps and info from apps.json
|
||||||
var appsInstalled = []; // list of app JSON
|
let appsInstalled = []; // list of app JSON
|
||||||
var appSortInfo = {}; // list of data to sort by, from appdates.csv { created, modified }
|
let appSortInfo = {}; // list of data to sort by, from appdates.csv { created, modified }
|
||||||
var files = []; // list of files on Bangle
|
let files = []; // list of files on Bangle
|
||||||
var DEFAULTSETTINGS = {
|
let DEFAULTSETTINGS = {
|
||||||
pretokenise : true,
|
pretokenise : true,
|
||||||
favourites : ["boot","launch","setting"]
|
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=>{
|
httpGet("apps.json").then(apps=>{
|
||||||
try {
|
try {
|
||||||
|
|
@ -23,7 +23,7 @@ httpGet("apps.json").then(apps=>{
|
||||||
httpGet("appdates.csv").then(csv=>{
|
httpGet("appdates.csv").then(csv=>{
|
||||||
document.querySelector(".sort-nav").classList.remove("hidden");
|
document.querySelector(".sort-nav").classList.remove("hidden");
|
||||||
csv.split("\n").forEach(line=>{
|
csv.split("\n").forEach(line=>{
|
||||||
var l = line.split(",");
|
let l = line.split(",");
|
||||||
appSortInfo[l[0]] = {
|
appSortInfo[l[0]] = {
|
||||||
created : Date.parse(l[1]),
|
created : Date.parse(l[1]),
|
||||||
modified : Date.parse(l[2])
|
modified : Date.parse(l[2])
|
||||||
|
|
@ -35,7 +35,7 @@ httpGet("appdates.csv").then(csv=>{
|
||||||
|
|
||||||
// =========================================== Top Navigation
|
// =========================================== Top Navigation
|
||||||
function showChangeLog(appid) {
|
function showChangeLog(appid) {
|
||||||
var app = appNameToApp(appid);
|
let app = appNameToApp(appid);
|
||||||
function show(contents) {
|
function show(contents) {
|
||||||
showPrompt(app.name+" Change Log",contents,{ok:true}).catch(()=>{});
|
showPrompt(app.name+" Change Log",contents,{ok:true}).catch(()=>{});
|
||||||
}
|
}
|
||||||
|
|
@ -43,9 +43,9 @@ function showChangeLog(appid) {
|
||||||
then(show).catch(()=>show("No Change Log available"));
|
then(show).catch(()=>show("No Change Log available"));
|
||||||
}
|
}
|
||||||
function showReadme(appid) {
|
function showReadme(appid) {
|
||||||
var app = appNameToApp(appid);
|
let app = appNameToApp(appid);
|
||||||
var appPath = `apps/${appid}/`;
|
let appPath = `apps/${appid}/`;
|
||||||
var markedOptions = { baseUrl : appPath };
|
let markedOptions = { baseUrl : appPath };
|
||||||
function show(contents) {
|
function show(contents) {
|
||||||
if (!contents) return;
|
if (!contents) return;
|
||||||
showPrompt(app.name + " Documentation", marked(contents, markedOptions), {ok: true}, false).catch(() => {});
|
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
|
// Pops up an IFRAME that allows an app to be customised
|
||||||
if (!appTemplate.custom) throw new Error("App doesn't have custom HTML");
|
if (!appTemplate.custom) throw new Error("App doesn't have custom HTML");
|
||||||
return new Promise((resolve,reject) => {
|
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>
|
<a href="#close" class="modal-overlay " aria-label="Close"></a>
|
||||||
<div class="modal-container" style="height:100%">
|
<div class="modal-container" style="height:100%">
|
||||||
<div class="modal-header">
|
<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) {
|
iframe.contentWindow.addEventListener("message", function(event) {
|
||||||
var appFiles = event.data;
|
let appFiles = event.data;
|
||||||
var app = JSON.parse(JSON.stringify(appTemplate)); // clone template
|
let app = JSON.parse(JSON.stringify(appTemplate)); // clone template
|
||||||
// copy extra keys from appFiles
|
// copy extra keys from appFiles
|
||||||
Object.keys(appFiles).forEach(k => {
|
Object.keys(appFiles).forEach(k => {
|
||||||
if (k!="storage") app[k] = appFiles[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
|
// 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");
|
if (!app.interface) throw new Error("App doesn't have interface HTML");
|
||||||
return new Promise((resolve,reject) => {
|
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>
|
<a href="#close" class="modal-overlay " aria-label="Close"></a>
|
||||||
<div class="modal-container" style="height:100%">
|
<div class="modal-container" style="height:100%">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -130,11 +130,11 @@ function handleAppInterface(app) {
|
||||||
//reject("Window closed");
|
//reject("Window closed");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
var iframe = modal.getElementsByTagName("iframe")[0];
|
let iframe = modal.getElementsByTagName("iframe")[0];
|
||||||
iframe.onload = function() {
|
iframe.onload = function() {
|
||||||
var iwin = iframe.contentWindow;
|
let iwin = iframe.contentWindow;
|
||||||
iwin.addEventListener("message", function(event) {
|
iwin.addEventListener("message", function(event) {
|
||||||
var msg = event.data;
|
let msg = event.data;
|
||||||
if (msg.type=="eval") {
|
if (msg.type=="eval") {
|
||||||
Puck.eval(msg.data, function(result) {
|
Puck.eval(msg.data, function(result) {
|
||||||
iwin.postMessage({
|
iwin.postMessage({
|
||||||
|
|
@ -168,7 +168,7 @@ function handleAppInterface(app) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeAppFavourite(favourite, app) {
|
function changeAppFavourite(favourite, app) {
|
||||||
var favourites = SETTINGS.favourites;
|
let favourites = SETTINGS.favourites;
|
||||||
if (favourite) {
|
if (favourite) {
|
||||||
SETTINGS.favourites = SETTINGS.favourites.concat([app.id]);
|
SETTINGS.favourites = SETTINGS.favourites.concat([app.id]);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -197,29 +197,29 @@ function showTab(tabname) {
|
||||||
// =========================================== Library
|
// =========================================== Library
|
||||||
|
|
||||||
// Can't use chip.attributes.filterid.value here because Safari/Apple's WebView doesn't handle it
|
// 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"));
|
let chips = Array.from(document.querySelectorAll('.filter-nav .chip')).map(chip => chip.getAttribute("filterid"));
|
||||||
var hash = window.location.hash ? window.location.hash.slice(1) : '';
|
let hash = window.location.hash ? window.location.hash.slice(1) : '';
|
||||||
|
|
||||||
var activeFilter = !!~chips.indexOf(hash) ? hash : '';
|
let activeFilter = ~chips.indexOf(hash) ? hash : '';
|
||||||
var activeSort = '';
|
let activeSort = '';
|
||||||
var currentSearch = activeFilter ? '' : hash;
|
let currentSearch = activeFilter ? '' : hash;
|
||||||
|
|
||||||
function refreshFilter(){
|
function refreshFilter(){
|
||||||
var filtersContainer = document.querySelector("#librarycontainer .filter-nav");
|
let filtersContainer = document.querySelector("#librarycontainer .filter-nav");
|
||||||
filtersContainer.querySelector('.active').classList.remove('active');
|
filtersContainer.querySelector('.active').classList.remove('active');
|
||||||
if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active');
|
if(activeFilter) filtersContainer.querySelector('.chip[filterid="'+activeFilter+'"]').classList.add('active');
|
||||||
else filtersContainer.querySelector('.chip[filterid]').classList.add('active');
|
else filtersContainer.querySelector('.chip[filterid]').classList.add('active');
|
||||||
}
|
}
|
||||||
function refreshSort(){
|
function refreshSort(){
|
||||||
var sortContainer = document.querySelector("#librarycontainer .sort-nav");
|
let sortContainer = document.querySelector("#librarycontainer .sort-nav");
|
||||||
sortContainer.querySelector('.active').classList.remove('active');
|
sortContainer.querySelector('.active').classList.remove('active');
|
||||||
if(activeSort) sortContainer.querySelector('.chip[sortid="'+activeSort+'"]').classList.add('active');
|
if(activeSort) sortContainer.querySelector('.chip[sortid="'+activeSort+'"]').classList.add('active');
|
||||||
else sortContainer.querySelector('.chip[sortid]').classList.add('active');
|
else sortContainer.querySelector('.chip[sortid]').classList.add('active');
|
||||||
}
|
}
|
||||||
function refreshLibrary() {
|
function refreshLibrary() {
|
||||||
var panelbody = document.querySelector("#librarycontainer .panel-body");
|
let panelbody = document.querySelector("#librarycontainer .panel-body");
|
||||||
var visibleApps = appJSON;
|
let visibleApps = appJSON;
|
||||||
var favourites = SETTINGS.favourites;
|
let favourites = SETTINGS.favourites;
|
||||||
|
|
||||||
if (activeFilter) {
|
if (activeFilter) {
|
||||||
if ( activeFilter == "favourites" ) {
|
if ( activeFilter == "favourites" ) {
|
||||||
|
|
@ -241,17 +241,17 @@ function refreshLibrary() {
|
||||||
}
|
}
|
||||||
|
|
||||||
panelbody.innerHTML = visibleApps.map((app,idx) => {
|
panelbody.innerHTML = visibleApps.map((app,idx) => {
|
||||||
var appInstalled = appsInstalled.find(a=>a.id==app.id);
|
let appInstalled = appsInstalled.find(a=>a.id==app.id);
|
||||||
var version = getVersionInfo(app, appInstalled);
|
let version = getVersionInfo(app, appInstalled);
|
||||||
var versionInfo = version.text;
|
let versionInfo = version.text;
|
||||||
if (versionInfo) versionInfo = " <small>("+versionInfo+")</small>";
|
if (versionInfo) versionInfo = " <small>("+versionInfo+")</small>";
|
||||||
var readme = `<a class="c-hand" onclick="showReadme('${app.id}')">Read more...</a>`;
|
let readme = `<a class="c-hand" onclick="showReadme('${app.id}')">Read more...</a>`;
|
||||||
var favourite = favourites.find(e => e == app.id);
|
let favourite = favourites.find(e => e == app.id);
|
||||||
|
|
||||||
var username = "espruino";
|
let username = "espruino";
|
||||||
var githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
|
let githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
|
||||||
if(githubMatch) username = githubMatch[1];
|
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">
|
return `<div class="tile column col-6 col-sm-12 col-xs-12">
|
||||||
<div class="tile-icon">
|
<div class="tile-icon">
|
||||||
|
|
@ -274,27 +274,27 @@ function refreshLibrary() {
|
||||||
</div>
|
</div>
|
||||||
`;}).join("");
|
`;}).join("");
|
||||||
// set badge up top
|
// set badge up top
|
||||||
var tab = document.querySelector("#tab-librarycontainer a");
|
let tab = document.querySelector("#tab-librarycontainer a");
|
||||||
tab.classList.add("badge");
|
tab.classList.add("badge");
|
||||||
tab.setAttribute("data-badge", appJSON.length);
|
tab.setAttribute("data-badge", appJSON.length);
|
||||||
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
|
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
|
||||||
button.addEventListener("click",event => {
|
button.addEventListener("click",event => {
|
||||||
var button = event.currentTarget;
|
let button = event.currentTarget;
|
||||||
var icon = button.firstChild;
|
let icon = button.firstChild;
|
||||||
var appid = button.getAttribute("appid");
|
let appid = button.getAttribute("appid");
|
||||||
var app = appNameToApp(appid);
|
let app = appNameToApp(appid);
|
||||||
if (!app) throw new Error("App "+appid+" not found");
|
if (!app) throw new Error("App "+appid+" not found");
|
||||||
// check icon to figure out what we should do
|
// check icon to figure out what we should do
|
||||||
if (icon.classList.contains("icon-share")) {
|
if (icon.classList.contains("icon-share")) {
|
||||||
// emulator
|
// emulator
|
||||||
var file = app.storage.find(f=>f.name.endsWith('.js'));
|
let file = app.storage.find(f=>f.name.endsWith('.js'));
|
||||||
if (!file) {
|
if (!file) {
|
||||||
console.error("No entrypoint found for "+appid);
|
console.error("No entrypoint found for "+appid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var baseurl = window.location.href;
|
let baseurl = window.location.href;
|
||||||
baseurl = baseurl.substr(0,baseurl.lastIndexOf("/"));
|
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`);
|
window.open(`https://espruino.com/ide/emulator.html?codeurl=${url}&upload`);
|
||||||
} else if (icon.classList.contains("icon-upload")) {
|
} else if (icon.classList.contains("icon-upload")) {
|
||||||
// upload
|
// upload
|
||||||
|
|
@ -421,7 +421,7 @@ function updateApp(app) {
|
||||||
|
|
||||||
|
|
||||||
function appNameToApp(appName) {
|
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) return app;
|
||||||
/* If app not known, add just one file
|
/* If app not known, add just one file
|
||||||
which is the JSON - so we'll remove it from
|
which is the JSON - so we'll remove it from
|
||||||
|
|
@ -436,8 +436,8 @@ function appNameToApp(appName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLoadingIndicator(id) {
|
function showLoadingIndicator(id) {
|
||||||
var panelbody = document.querySelector(`#${id} .panel-body`);
|
let panelbody = document.querySelector(`#${id} .panel-body`);
|
||||||
var tab = document.querySelector(`#tab-${id} a`);
|
let tab = document.querySelector(`#tab-${id} a`);
|
||||||
// set badge up top
|
// set badge up top
|
||||||
tab.classList.add("badge");
|
tab.classList.add("badge");
|
||||||
tab.setAttribute("data-badge", "");
|
tab.setAttribute("data-badge", "");
|
||||||
|
|
@ -446,9 +446,9 @@ function showLoadingIndicator(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAppsToUpdate() {
|
function getAppsToUpdate() {
|
||||||
var appsToUpdate = [];
|
let appsToUpdate = [];
|
||||||
appsInstalled.forEach(appInstalled => {
|
appsInstalled.forEach(appInstalled => {
|
||||||
var app = appNameToApp(appInstalled.id);
|
let app = appNameToApp(appInstalled.id);
|
||||||
if (app.version != appInstalled.version)
|
if (app.version != appInstalled.version)
|
||||||
appsToUpdate.push(app);
|
appsToUpdate.push(app);
|
||||||
});
|
});
|
||||||
|
|
@ -456,14 +456,14 @@ function getAppsToUpdate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshMyApps() {
|
function refreshMyApps() {
|
||||||
var panelbody = document.querySelector("#myappscontainer .panel-body");
|
let panelbody = document.querySelector("#myappscontainer .panel-body");
|
||||||
panelbody.innerHTML = appsInstalled.map(appInstalled => {
|
panelbody.innerHTML = appsInstalled.map(appInstalled => {
|
||||||
var app = appNameToApp(appInstalled.id);
|
let app = appNameToApp(appInstalled.id);
|
||||||
var version = getVersionInfo(app, appInstalled);
|
let version = getVersionInfo(app, appInstalled);
|
||||||
var username = "espruino";
|
let username = "espruino";
|
||||||
var githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
|
let githubMatch = window.location.href.match(/\/(\w+)\.github\.io/);
|
||||||
if(githubMatch) username = githubMatch[1];
|
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">
|
return `<div class="tile column col-6 col-sm-12 col-xs-12">
|
||||||
<div class="tile-icon">
|
<div class="tile-icon">
|
||||||
<figure class="avatar"><img src="apps/${app.icon?`${app.id}/${app.icon}`:"unknown.png"}" alt="${escapeHtml(app.name)}"></figure>
|
<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("");
|
`}).join("");
|
||||||
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
|
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
|
||||||
button.addEventListener("click",event => {
|
button.addEventListener("click",event => {
|
||||||
var button = event.currentTarget;
|
let button = event.currentTarget;
|
||||||
var icon = button.firstChild;
|
let icon = button.firstChild;
|
||||||
var appid = button.getAttribute("appid");
|
let appid = button.getAttribute("appid");
|
||||||
var app = appNameToApp(appid);
|
let app = appNameToApp(appid);
|
||||||
if (!app) throw new Error("App "+appid+" not found");
|
if (!app) throw new Error("App "+appid+" not found");
|
||||||
// check icon to figure out what we should do
|
// check icon to figure out what we should do
|
||||||
if (icon.classList.contains("icon-delete")) removeApp(app);
|
if (icon.classList.contains("icon-delete")) removeApp(app);
|
||||||
|
|
@ -493,9 +493,9 @@ function refreshMyApps() {
|
||||||
if (icon.classList.contains("icon-download")) handleAppInterface(app);
|
if (icon.classList.contains("icon-download")) handleAppInterface(app);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
var appsToUpdate = getAppsToUpdate();
|
let appsToUpdate = getAppsToUpdate();
|
||||||
var tab = document.querySelector("#tab-myappscontainer a");
|
let tab = document.querySelector("#tab-myappscontainer a");
|
||||||
var updateApps = document.querySelector("#myappscontainer .updateapps");
|
let updateApps = document.querySelector("#myappscontainer .updateapps");
|
||||||
if (appsToUpdate.length) {
|
if (appsToUpdate.length) {
|
||||||
updateApps.innerHTML = `Update ${appsToUpdate.length} apps`;
|
updateApps.innerHTML = `Update ${appsToUpdate.length} apps`;
|
||||||
updateApps.classList.remove("hidden");
|
updateApps.classList.remove("hidden");
|
||||||
|
|
@ -529,10 +529,10 @@ function getInstalledApps(refresh) {
|
||||||
|
|
||||||
/// Removes everything and install the given apps, eg: installMultipleApps(["boot","mclock"], "minimal")
|
/// Removes everything and install the given apps, eg: installMultipleApps(["boot","mclock"], "minimal")
|
||||||
function installMultipleApps(appIds, promptName) {
|
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))
|
if (apps.some(x=>x===undefined))
|
||||||
return Promise.reject("Not all apps found");
|
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 showPrompt("Install Defaults",`Remove everything and install ${promptName} apps?`).then(() => {
|
||||||
return Comms.removeAllApps();
|
return Comms.removeAllApps();
|
||||||
}).then(()=>{
|
}).then(()=>{
|
||||||
|
|
@ -541,7 +541,7 @@ function installMultipleApps(appIds, promptName) {
|
||||||
showToast(`Existing apps removed. Installing ${appCount} apps...`);
|
showToast(`Existing apps removed. Installing ${appCount} apps...`);
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
function upload() {
|
function upload() {
|
||||||
var app = apps.shift();
|
let app = apps.shift();
|
||||||
if (app===undefined) return resolve();
|
if (app===undefined) return resolve();
|
||||||
Progress.show({title:`${app.name} (${appCount-apps.length}/${appCount})`,sticky:true});
|
Progress.show({title:`${app.name} (${appCount-apps.length}/${appCount})`,sticky:true});
|
||||||
Comms.uploadApp(app,"skip_reset").then((appJSON) => {
|
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) {
|
function handleConnectionChange(connected) {
|
||||||
connectMyDeviceBtn.textContent = connected ? 'Disconnect' : 'Connect';
|
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", () => {
|
htmlToArray(document.querySelectorAll(".btn.updateapps")).map(button => button.addEventListener("click", () => {
|
||||||
var appsToUpdate = getAppsToUpdate();
|
let appsToUpdate = getAppsToUpdate();
|
||||||
var count = appsToUpdate.length;
|
let count = appsToUpdate.length;
|
||||||
function updater() {
|
function updater() {
|
||||||
if (!appsToUpdate.length) return;
|
if (!appsToUpdate.length) return;
|
||||||
var app = appsToUpdate.pop();
|
let app = appsToUpdate.pop();
|
||||||
return updateApp(app).then(function() {
|
return updateApp(app).then(function() {
|
||||||
return updater();
|
return updater();
|
||||||
});
|
});
|
||||||
|
|
@ -603,7 +603,7 @@ connectMyDeviceBtn.addEventListener("click", () => {
|
||||||
});
|
});
|
||||||
Comms.watchConnectionChange(handleConnectionChange);
|
Comms.watchConnectionChange(handleConnectionChange);
|
||||||
|
|
||||||
var filtersContainer = document.querySelector("#librarycontainer .filter-nav");
|
let filtersContainer = document.querySelector("#librarycontainer .filter-nav");
|
||||||
filtersContainer.addEventListener('click', ({ target }) => {
|
filtersContainer.addEventListener('click', ({ target }) => {
|
||||||
if (target.classList.contains('active')) return;
|
if (target.classList.contains('active')) return;
|
||||||
|
|
||||||
|
|
@ -613,14 +613,14 @@ filtersContainer.addEventListener('click', ({ target }) => {
|
||||||
window.location.hash = activeFilter;
|
window.location.hash = activeFilter;
|
||||||
});
|
});
|
||||||
|
|
||||||
var librarySearchInput = document.querySelector("#searchform input");
|
let librarySearchInput = document.querySelector("#searchform input");
|
||||||
librarySearchInput.value = currentSearch;
|
librarySearchInput.value = currentSearch;
|
||||||
librarySearchInput.addEventListener('input', evt => {
|
librarySearchInput.addEventListener('input', evt => {
|
||||||
currentSearch = evt.target.value.toLowerCase();
|
currentSearch = evt.target.value.toLowerCase();
|
||||||
refreshLibrary();
|
refreshLibrary();
|
||||||
});
|
});
|
||||||
|
|
||||||
var sortContainer = document.querySelector("#librarycontainer .sort-nav");
|
let sortContainer = document.querySelector("#librarycontainer .sort-nav");
|
||||||
sortContainer.addEventListener('click', ({ target }) => {
|
sortContainer.addEventListener('click', ({ target }) => {
|
||||||
if (target.classList.contains('active')) return;
|
if (target.classList.contains('active')) return;
|
||||||
|
|
||||||
|
|
@ -646,13 +646,13 @@ if (window.location.host=="banglejs.com") {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings
|
// 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
|
/// Load settings and update controls
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
var j = localStorage.getItem("settings");
|
let j = localStorage.getItem("settings");
|
||||||
if (typeof j != "string") return;
|
if (typeof j != "string") return;
|
||||||
try {
|
try {
|
||||||
var s = JSON.parse(j);
|
let s = JSON.parse(j);
|
||||||
Object.keys(s).forEach( k => {
|
Object.keys(s).forEach( k => {
|
||||||
SETTINGS[k]=s[k];
|
SETTINGS[k]=s[k];
|
||||||
if (SETTINGS_HOOKS[k]) SETTINGS_HOOKS[k]();
|
if (SETTINGS_HOOKS[k]) SETTINGS_HOOKS[k]();
|
||||||
|
|
@ -668,7 +668,7 @@ function saveSettings() {
|
||||||
}
|
}
|
||||||
// Link in settings DOM elements
|
// Link in settings DOM elements
|
||||||
function settingsCheckbox(id, name) {
|
function settingsCheckbox(id, name) {
|
||||||
var setting = document.getElementById(id);
|
let setting = document.getElementById(id);
|
||||||
function update() {
|
function update() {
|
||||||
setting.checked = SETTINGS[name];
|
setting.checked = SETTINGS[name];
|
||||||
}
|
}
|
||||||
|
|
@ -720,7 +720,7 @@ document.getElementById("installdefault").addEventListener("click",event=>{
|
||||||
|
|
||||||
// Install all favourite apps in one go
|
// Install all favourite apps in one go
|
||||||
document.getElementById("installfavourite").addEventListener("click",event=>{
|
document.getElementById("installfavourite").addEventListener("click",event=>{
|
||||||
var favApps = SETTINGS.favourites;
|
let favApps = SETTINGS.favourites;
|
||||||
installMultipleApps(favApps, "favourite").catch(err=>{
|
installMultipleApps(favApps, "favourite").catch(err=>{
|
||||||
Progress.hide({sticky:true});
|
Progress.hide({sticky:true});
|
||||||
showToast("App Install failed, "+err,"error");
|
showToast("App Install failed, "+err,"error");
|
||||||
|
|
|
||||||
22
js/ui.js
22
js/ui.js
|
|
@ -1,7 +1,7 @@
|
||||||
// General UI tools (progress bar, toast, prompt)
|
// General UI tools (progress bar, toast, prompt)
|
||||||
|
|
||||||
/// Handle progress bars
|
/// Handle progress bars
|
||||||
var Progress = {
|
let Progress = {
|
||||||
domElement : null, // the DOM element
|
domElement : null, // the DOM element
|
||||||
sticky : false, // Progress.show({..., sticky:true}) don't remove until Progress.hide({sticky:true})
|
sticky : false, // Progress.show({..., sticky:true}) don't remove until Progress.hide({sticky:true})
|
||||||
interval : undefined, // the interval used if Progress.show({progress:"animate"})
|
interval : undefined, // the interval used if Progress.show({progress:"animate"})
|
||||||
|
|
@ -18,11 +18,11 @@ var Progress = {
|
||||||
}) */
|
}) */
|
||||||
show : function(options) {
|
show : function(options) {
|
||||||
options = options||{};
|
options = options||{};
|
||||||
var text = options.title;
|
let text = options.title;
|
||||||
if (options.sticky) Progress.sticky = true;
|
if (options.sticky) Progress.sticky = true;
|
||||||
if (options.min!==undefined) Progress.min = options.min;
|
if (options.min!==undefined) Progress.min = options.min;
|
||||||
if (options.max!==undefined) Progress.max = options.max;
|
if (options.max!==undefined) Progress.max = options.max;
|
||||||
var percent = options.percent;
|
let percent = options.percent;
|
||||||
if (percent!==undefined)
|
if (percent!==undefined)
|
||||||
percent = Progress.min*100 + (Progress.max-Progress.min)*percent;
|
percent = Progress.min*100 + (Progress.max-Progress.min)*percent;
|
||||||
if (!Progress.domElement) {
|
if (!Progress.domElement) {
|
||||||
|
|
@ -39,7 +39,7 @@ var Progress = {
|
||||||
percent = 0;
|
percent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var toastcontainer = document.getElementById("toastcontainer");
|
let toastcontainer = document.getElementById("toastcontainer");
|
||||||
Progress.domElement = htmlElement(`<div class="toast">
|
Progress.domElement = htmlElement(`<div class="toast">
|
||||||
${text ? `<div>${text}</div>`:``}
|
${text ? `<div>${text}</div>`:``}
|
||||||
<div class="bar bar-sm">
|
<div class="bar bar-sm">
|
||||||
|
|
@ -48,7 +48,7 @@ var Progress = {
|
||||||
</div>`);
|
</div>`);
|
||||||
toastcontainer.append(Progress.domElement);
|
toastcontainer.append(Progress.domElement);
|
||||||
} else {
|
} else {
|
||||||
var pt=document.getElementById("Progress.domElement");
|
let pt=document.getElementById("Progress.domElement");
|
||||||
pt.setAttribute("aria-valuenow",percent);
|
pt.setAttribute("aria-valuenow",percent);
|
||||||
pt.style.width = percent+"%";
|
pt.style.width = percent+"%";
|
||||||
}
|
}
|
||||||
|
|
@ -76,20 +76,20 @@ Puck.writeProgress = function(charsSent, charsTotal) {
|
||||||
Progress.hide();
|
Progress.hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var percent = Math.round(charsSent*100/charsTotal);
|
let percent = Math.round(charsSent*100/charsTotal);
|
||||||
Progress.show({percent: percent});
|
Progress.show({percent: percent});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show a 'toast' message for status
|
/// Show a 'toast' message for status
|
||||||
function showToast(message, type) {
|
function showToast(message, type) {
|
||||||
// toast-primary, toast-success, toast-warning or toast-error
|
// toast-primary, toast-success, toast-warning or toast-error
|
||||||
var style = "toast-primary";
|
let style = "toast-primary";
|
||||||
if (type=="success") style = "toast-success";
|
if (type=="success") style = "toast-success";
|
||||||
else if (type=="error") style = "toast-error";
|
else if (type=="error") style = "toast-error";
|
||||||
else if (type=="warning") style = "toast-warning";
|
else if (type=="warning") style = "toast-warning";
|
||||||
else if (type!==undefined) console.log("showToast: unknown toast "+type);
|
else if (type!==undefined) console.log("showToast: unknown toast "+type);
|
||||||
var toastcontainer = document.getElementById("toastcontainer");
|
let toastcontainer = document.getElementById("toastcontainer");
|
||||||
var msgDiv = htmlElement(`<div class="toast ${style}"></div>`);
|
let msgDiv = htmlElement(`<div class="toast ${style}"></div>`);
|
||||||
msgDiv.innerHTML = message;
|
msgDiv.innerHTML = message;
|
||||||
toastcontainer.append(msgDiv);
|
toastcontainer.append(msgDiv);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
|
|
@ -103,7 +103,7 @@ function showPrompt(title, text, buttons, shouldEscapeHtml) {
|
||||||
if (typeof(shouldEscapeHtml) === 'undefined' || shouldEscapeHtml === null) shouldEscapeHtml = true;
|
if (typeof(shouldEscapeHtml) === 'undefined' || shouldEscapeHtml === null) shouldEscapeHtml = true;
|
||||||
|
|
||||||
return new Promise((resolve,reject) => {
|
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>-->
|
<!--<a href="#close" class="modal-overlay" aria-label="Close"></a>-->
|
||||||
<div class="modal-container">
|
<div class="modal-container">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -133,7 +133,7 @@ function showPrompt(title, text, buttons, shouldEscapeHtml) {
|
||||||
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
|
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
|
||||||
button.addEventListener("click",event => {
|
button.addEventListener("click",event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var isYes = event.target.getAttribute("isyes")=="1";
|
let isYes = event.target.getAttribute("isyes")=="1";
|
||||||
if (isYes) resolve();
|
if (isYes) resolve();
|
||||||
else reject("User cancelled");
|
else reject("User cancelled");
|
||||||
modal.remove();
|
modal.remove();
|
||||||
|
|
|
||||||
14
js/utils.js
14
js/utils.js
|
|
@ -1,5 +1,5 @@
|
||||||
function escapeHtml(text) {
|
function escapeHtml(text) {
|
||||||
var map = {
|
let map = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
'<': '<',
|
'<': '<',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
|
|
@ -24,13 +24,13 @@ function htmlToArray(collection) {
|
||||||
return [].slice.call(collection);
|
return [].slice.call(collection);
|
||||||
}
|
}
|
||||||
function htmlElement(str) {
|
function htmlElement(str) {
|
||||||
var div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
div.innerHTML = str.trim();
|
div.innerHTML = str.trim();
|
||||||
return div.firstChild;
|
return div.firstChild;
|
||||||
}
|
}
|
||||||
function httpGet(url) {
|
function httpGet(url) {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
var oReq = new XMLHttpRequest();
|
let oReq = new XMLHttpRequest();
|
||||||
oReq.addEventListener("load", () => {
|
oReq.addEventListener("load", () => {
|
||||||
if (oReq.status==200) resolve(oReq.responseText)
|
if (oReq.status==200) resolve(oReq.responseText)
|
||||||
else reject(oReq.status+" - "+oReq.statusText);
|
else reject(oReq.status+" - "+oReq.statusText);
|
||||||
|
|
@ -51,8 +51,8 @@ function toJS(txt) {
|
||||||
function appSorter(a,b) {
|
function appSorter(a,b) {
|
||||||
if (a.unknown || b.unknown)
|
if (a.unknown || b.unknown)
|
||||||
return (a.unknown)? 1 : -1;
|
return (a.unknown)? 1 : -1;
|
||||||
var sa = 0|a.sortorder;
|
let sa = 0|a.sortorder;
|
||||||
var sb = 0|b.sortorder;
|
let sb = 0|b.sortorder;
|
||||||
if (sa<sb) return -1;
|
if (sa<sb) return -1;
|
||||||
if (sa>sb) return 1;
|
if (sa>sb) return 1;
|
||||||
return (a.name==b.name) ? 0 : ((a.name<b.name) ? -1 : 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)
|
/* 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 */
|
work out what to display re: versions and if we can update */
|
||||||
function getVersionInfo(appListing, appInstalled) {
|
function getVersionInfo(appListing, appInstalled) {
|
||||||
var versionText = "";
|
let versionText = "";
|
||||||
var canUpdate = false;
|
let canUpdate = false;
|
||||||
function clicky(v) {
|
function clicky(v) {
|
||||||
return `<a class="c-hand" onclick="showChangeLog('${appListing.id}')">${v}</a>`;
|
return `<a class="c-hand" onclick="showChangeLog('${appListing.id}')">${v}</a>`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue