forked from FOSS/BangleApps
Initial stab at app loading tool
commit
4c20d622ea
|
@ -0,0 +1,24 @@
|
|||
[
|
||||
{ "id": "trex",
|
||||
"name": "T-Rex",
|
||||
"icon": "trex.png",
|
||||
"description": "T-Rex game in the style of Chrome's offline game",
|
||||
"tags": "game",
|
||||
"storage": [
|
||||
{"name":"+trex","file":"trex.json"},
|
||||
{"name":"-trex","file":"trex.js"},
|
||||
{"name":"*trex","file":"trex-icon.js"}
|
||||
]
|
||||
},
|
||||
{ "id": "compass",
|
||||
"name": "Compass",
|
||||
"icon": "compass.png",
|
||||
"description": "Simple compass that points North",
|
||||
"tags": "tool,outdoors",
|
||||
"storage": [
|
||||
{"name":"+compass","file":"compass.json"},
|
||||
{"name":"-compass","file":"compass.js"},
|
||||
{"name":"*compass","file":"compass-icon.js"}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWOwcz///mc4DBhFDwYVBAAYYDJJAWJDAoXKCw//+YXJIwWPCQk/Aof4JBAuHC4v/GBBdHC4nzMIZGHCAIOBC4vz75hDJAgXCCgS9CC4fdAYQXGIwsyCAPyl//nvdVQoXFRofzkYXCCwJGBSIgXFQ4kymcykfdIwZgDC5XzkUyCwJGDC6FNCwPTC5i9FmQXCMgLZFC48zLgMilUv/vdkUjBII9BC6HSC55HD1WiklDNIgXIBok61QYBkSBFC5kqCwMjC6RGB1RcCR4gXIx4MC+Wqkfyl70BEQf4C4+DIwYqBC4XzGAc4C4sISAfz0QDCFgUzRwmAC4wQB+QTCC4f/AYJeCC4hIEPQi9FIwwXDbIzVHC4xICSIYXGRoRGFGAgqFXgouGC4iqDLo4XIJAQYHCwZGHGAgYBXQUzCwYuIDAwAHCxRJEAAxFJDBgWNDBAWPAH4AYA="))
|
|
@ -0,0 +1,34 @@
|
|||
g.clear();
|
||||
g.setColor(0,0.5,1);
|
||||
g.fillCircle(120,130,80,80);
|
||||
g.setColor(0,0,0);
|
||||
g.fillCircle(120,130,70,70);
|
||||
|
||||
function arrow(r,c) {
|
||||
r=-r*Math.PI/180;
|
||||
var p = Math.PI/2;
|
||||
g.setColor(c);
|
||||
g.fillPoly([
|
||||
120+60*Math.sin(r), 130-60*Math.cos(r),
|
||||
120+10*Math.sin(r+p), 130-10*Math.cos(r+p),
|
||||
120+10*Math.sin(r+-p), 130-10*Math.cos(r-p),
|
||||
]);
|
||||
}
|
||||
|
||||
var oldHeading = 0;
|
||||
Bangle.on('mag', function(m) {
|
||||
if (!Bangle.isLCDOn()) return;
|
||||
g.setFont("6x8",3);
|
||||
g.setColor(0);
|
||||
g.fillRect(70,0,170,24);
|
||||
g.setColor(0xffff);
|
||||
g.setFontAlign(0,0);
|
||||
g.drawString((m.heading===undefined)?"---":Math.round(m.heading),120,12);
|
||||
g.setColor(0,0,0);
|
||||
arrow(oldHeading,0);
|
||||
arrow(oldHeading+180,0);
|
||||
arrow(m.heading,0xF800);
|
||||
arrow(m.heading+180,0x001F);
|
||||
oldHeading = m.heading;
|
||||
});
|
||||
Bangle.setCompassPower(1);
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name":"Compass",
|
||||
"icon":"*compass",
|
||||
"src":"-compass"
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwgIXUn//4AFI///+AFC+YFKCIoFeHQYFH/4FGhkAgYKCAo8fApEPGggFG4YFBmAFHAgIdDAqA/BAo38K4gFJWIJ7DAoUB/AqC4EDLwIFCh0GFQPD4EYgP/4YABDwfwSggFFgAFCgOAAoYSDAox4BABQA=="))
|
|
@ -0,0 +1,219 @@
|
|||
greal = g;
|
||||
g.clear();
|
||||
g = Graphics.createArrayBuffer(120,64,1,{msb:true});
|
||||
g.flip = function() {
|
||||
greal.drawImage({
|
||||
width:120,
|
||||
height:64,
|
||||
buffer:g.buffer
|
||||
},0,(240-128)/2,{scale:2});
|
||||
};
|
||||
var W = g.getWidth();
|
||||
var BTNL = BTN4;
|
||||
var BTNR = BTN5;
|
||||
var BTNU = BTN1;
|
||||
|
||||
// Images can be added like this in Espruino v2.00
|
||||
var IMG = {
|
||||
rex: [Graphics.createImage(\`
|
||||
########
|
||||
##########
|
||||
## #######
|
||||
##########
|
||||
##########
|
||||
##########
|
||||
#####
|
||||
########
|
||||
# #####
|
||||
# #######
|
||||
## ##########
|
||||
### ######### #
|
||||
##############
|
||||
##############
|
||||
############
|
||||
###########
|
||||
#########
|
||||
#######
|
||||
### ##
|
||||
## #
|
||||
#
|
||||
##
|
||||
\`),Graphics.createImage(\`
|
||||
########
|
||||
##########
|
||||
## #######
|
||||
##########
|
||||
##########
|
||||
##########
|
||||
#####
|
||||
########
|
||||
# #####
|
||||
# #######
|
||||
## ##########
|
||||
### ######### #
|
||||
##############
|
||||
##############
|
||||
############
|
||||
###########
|
||||
#########
|
||||
#######
|
||||
### ##
|
||||
## ##
|
||||
#
|
||||
##
|
||||
\`),Graphics.createImage(\`
|
||||
########
|
||||
# ######
|
||||
# # ######
|
||||
# ######
|
||||
##########
|
||||
##########
|
||||
#####
|
||||
########
|
||||
# #####
|
||||
# #######
|
||||
## ##########
|
||||
### ######### #
|
||||
##############
|
||||
##############
|
||||
############
|
||||
###########
|
||||
#########
|
||||
#######
|
||||
### ##
|
||||
## #
|
||||
# #
|
||||
## ##
|
||||
\`)],
|
||||
cacti: [Graphics.createImage(\`
|
||||
##
|
||||
####
|
||||
####
|
||||
####
|
||||
####
|
||||
#### #
|
||||
# #### ###
|
||||
### #### ###
|
||||
### #### ###
|
||||
### #### ###
|
||||
### #### ###
|
||||
### #### ###
|
||||
### #### ###
|
||||
### #### ###
|
||||
###########
|
||||
#########
|
||||
####
|
||||
####
|
||||
####
|
||||
####
|
||||
####
|
||||
####
|
||||
####
|
||||
####
|
||||
\`),Graphics.createImage(\`
|
||||
##
|
||||
##
|
||||
# ##
|
||||
## ## #
|
||||
## ## #
|
||||
## ## #
|
||||
## ## #
|
||||
##### #
|
||||
#### #
|
||||
#####
|
||||
####
|
||||
##
|
||||
##
|
||||
##
|
||||
##
|
||||
##
|
||||
##
|
||||
##
|
||||
\`)],
|
||||
};
|
||||
IMG.rex.forEach(i=>i.transparent=0);
|
||||
IMG.cacti.forEach(i=>i.transparent=0);
|
||||
var cacti, rex, frame;
|
||||
|
||||
function gameStart() {
|
||||
rex = {
|
||||
alive : true,
|
||||
img : 0,
|
||||
x : 10, y : 0,
|
||||
vy : 0,
|
||||
score : 0
|
||||
};
|
||||
cacti = [ { x:W, img:1 } ];
|
||||
var random = new Uint8Array(128*3/8);
|
||||
for (var i=0;i<50;i++) {
|
||||
var a = 0|(Math.random()*random.length);
|
||||
var b = 0|(Math.random()*8);
|
||||
random[a]|=1<<b;
|
||||
}
|
||||
IMG.ground = { width: 128, height: 3, bpp : 1, buffer : random.buffer };
|
||||
frame = 0;
|
||||
setInterval(onFrame, 50);
|
||||
}
|
||||
function gameStop() {
|
||||
rex.alive = false;
|
||||
rex.img = 2; // dead
|
||||
clearInterval();
|
||||
setTimeout(function() {
|
||||
setWatch(gameStart, BTNU, {repeat:0,debounce:50,edge:"rising"});
|
||||
}, 1000);
|
||||
setTimeout(onFrame, 10);
|
||||
}
|
||||
|
||||
function onFrame() {
|
||||
g.clear();
|
||||
if (rex.alive) {
|
||||
frame++;
|
||||
rex.score++;
|
||||
if (!(frame&3)) rex.img = rex.img?0:1;
|
||||
// move rex
|
||||
if (BTNL.read() && rex.x>0) rex.x--;
|
||||
if (BTNR.read() && rex.x<20) rex.x++;
|
||||
if (BTNU.read() && rex.y==0) rex.vy=4;
|
||||
rex.y += rex.vy;
|
||||
rex.vy -= 0.2;
|
||||
if (rex.y<=0) {rex.y=0; rex.vy=0; }
|
||||
// move cacti
|
||||
var lastCactix = cacti.length?cacti[cacti.length-1].x:W-1;
|
||||
if (lastCactix<W) {
|
||||
cacti.push({
|
||||
x : lastCactix + 24 + Math.random()*W,
|
||||
img : (Math.random()>0.5)?1:0
|
||||
});
|
||||
}
|
||||
cacti.forEach(c=>c.x--);
|
||||
while (cacti.length && cacti[0].x<0) cacti.shift();
|
||||
} else {
|
||||
g.drawString("Game Over!",(W-g.stringWidth("Game Over!"))/2,20);
|
||||
}
|
||||
g.drawLine(0,60,239,60);
|
||||
cacti.forEach(c=>g.drawImage(IMG.cacti[c.img],c.x,60-IMG.cacti[c.img].height));
|
||||
// check against actual pixels
|
||||
var rexx = rex.x;
|
||||
var rexy = 38-rex.y;
|
||||
if (rex.alive &&
|
||||
(g.getPixel(rexx+0, rexy+13) ||
|
||||
g.getPixel(rexx+2, rexy+15) ||
|
||||
g.getPixel(rexx+5, rexy+19) ||
|
||||
g.getPixel(rexx+10, rexy+19) ||
|
||||
g.getPixel(rexx+12, rexy+15) ||
|
||||
g.getPixel(rexx+13, rexy+13) ||
|
||||
g.getPixel(rexx+15, rexy+11) ||
|
||||
g.getPixel(rexx+17, rexy+7) ||
|
||||
g.getPixel(rexx+19, rexy+5) ||
|
||||
g.getPixel(rexx+19, rexy+1))) {
|
||||
return gameStop();
|
||||
}
|
||||
g.drawImage(IMG.rex[rex.img], rexx, rexy);
|
||||
var groundOffset = frame&127;
|
||||
g.drawImage(IMG.ground, -groundOffset, 61);
|
||||
g.drawImage(IMG.ground, 128-groundOffset, 61);
|
||||
g.drawString(rex.score,(W-1)-g.stringWidth(rex.score));
|
||||
g.flip();
|
||||
}
|
||||
|
||||
gameStart();
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name":"T-Rex",
|
||||
"icon":"*trex",
|
||||
"src":"-trex"
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 396 B |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,39 @@
|
|||
Puck.debug=3;
|
||||
|
||||
var Comms = {
|
||||
uploadApp : app => {
|
||||
/* eg
|
||||
{ name: "T-Rex",
|
||||
icon: "trex.png",
|
||||
description: "T-Rex game in the style of Chrome's offline game",
|
||||
storage: [
|
||||
{name:"+trex",file:"trex.json"},
|
||||
{name:"-trex",file:"trex.js"},
|
||||
{name:"*trex",file:"trex-icon.js"}
|
||||
]
|
||||
}
|
||||
*/
|
||||
return new Promise((resolve,reject) => {
|
||||
// Load all files
|
||||
Promise.all(app.storage.map(storageFile => httpGet("apps/"+storageFile.file)
|
||||
// map each file to a command to load into storage
|
||||
.then(contents=>`require('Storage').write(${toJS(storageFile.name)},${toJS(contents)});`)))
|
||||
//
|
||||
.then(function(fileContents) {
|
||||
fileContents = fileContents.join("\n");
|
||||
Puck.write(fileContents,function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
getInstalledApps : () => {
|
||||
return new Promise((resolve,reject) => {
|
||||
Puck.write("\x03",() => {
|
||||
Puck.eval('require("Storage").list().filter(f=>f[0]=="+").map(f=>f.substr(1))', appList => {
|
||||
resolve(appList);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre-exp.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre-icons.min.css">
|
||||
<title>Bangle.js loader</title>
|
||||
</head>
|
||||
<body>
|
||||
<header class="navbar">
|
||||
<section class="navbar-section">
|
||||
<a href="#" class="navbar-brand mr-2">Bangle.js Loader</a>
|
||||
<!-- <a href="#" class="btn btn-link">...</a> -->
|
||||
</section>
|
||||
<!--<section class="navbar-section">
|
||||
<div class="input-group input-inline">
|
||||
<input class="form-input" type="text" placeholder="search">
|
||||
<button class="btn btn-primary input-group-btn">Search</button>
|
||||
</div>
|
||||
</section>-->
|
||||
</header>
|
||||
|
||||
<ul class="tab tab-block" id="tab-navigate">
|
||||
<li class="tab-item active" id="tab-librarycontainer">
|
||||
<a href="javascript:showTab('librarycontainer')">Library</a>
|
||||
</li>
|
||||
<li class="tab-item" id="tab-myappscontainer">
|
||||
<a href="javascript:showTab('myappscontainer')">My Apps</a>
|
||||
</li>
|
||||
<li class="tab-item" id="tab-aboutcontainer">
|
||||
<a href="javascript:showTab('aboutcontainer')">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="container" id="toastcontainer">
|
||||
</div>
|
||||
|
||||
<div class="container bangle-tab" id="librarycontainer">
|
||||
<!--<div class="filter-nav">
|
||||
<label class="chip" filterid="">All</label>
|
||||
<label class="chip" filterid="clock">Clocks</label>
|
||||
<label class="chip" filterid="game">Games</label>
|
||||
<label class="chip" filterid="tool">Tools</label>
|
||||
<label class="chip" filterid="hardware">Hardware</label>
|
||||
</div>-->
|
||||
<div class="panel">
|
||||
<div class="panel-header">
|
||||
<!-- <div class="input-group">
|
||||
<input class="form-input" type="text" placeholder="Keywords...">
|
||||
<button class="btn btn-primary input-group-btn">Search</button>
|
||||
</div>-->
|
||||
</div>
|
||||
<div class="panel-body"><!-- apps go here --></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container bangle-tab" id="myappscontainer" style="display:none">
|
||||
<div class="panel">
|
||||
<div class="panel-header" style="text-align:right">
|
||||
<button class="btn input-group-btn" id="myappsrefresh">Refresh...</button>
|
||||
</div>
|
||||
<div class="panel-body"><!-- apps go here --></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container bangle-tab" id="aboutcontainer" style="display:none">
|
||||
<div class="hero bg-gray">
|
||||
<div class="hero-body">
|
||||
<h1>About Bangle.js loader</h1>
|
||||
<p>A tool for uploading and removing apps from <a href="https://banglejs.com">Bangle.js Smart Watches</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<p>Using <a href="https://espruino.com/">Espruino</a>, Icons from <a href="https://icons8.com/">icons8.com</a></p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="http://www.puck-js.com/puck.js"></script>
|
||||
<script src="utils.js"></script>
|
||||
<script src="comms.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,161 @@
|
|||
var appjson = [];
|
||||
httpGet("apps.json").then(apps=>{
|
||||
appjson = JSON.parse(apps);
|
||||
appjson.sort(appSorter);
|
||||
refreshLibrary();
|
||||
});
|
||||
|
||||
// Status
|
||||
// =========================================== Top Navigation
|
||||
function showToast(message) {
|
||||
// toast-primary, toast-success, toast-warning or toast-error
|
||||
var toastcontainer = document.getElementById("toastcontainer");
|
||||
var msgDiv = htmlElement(`<div class="toast toast-primary"></div>`);
|
||||
msgDiv.innerHTML = message;
|
||||
toastcontainer.append(msgDiv);
|
||||
setTimeout(function() {
|
||||
msgDiv.remove();
|
||||
}, 5000);
|
||||
}
|
||||
function showPrompt(title, text) {
|
||||
return new Promise((resolve,reject) => {
|
||||
var modal = htmlElement(`<div class="modal active">
|
||||
<!--<a href="#close" class="modal-overlay" aria-label="Close"></a>-->
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<a href="#close" class="btn btn-clear float-right" aria-label="Close"></a>
|
||||
<div class="modal-title h5">${escapeHtml(title)}</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="content">
|
||||
${escapeHtml(text)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" isyes="1">Yes</button>
|
||||
<button class="btn" isyes="0">No</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
document.body.append(modal);
|
||||
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
|
||||
button.addEventListener("click",event => {
|
||||
var isYes = event.target.getAttribute("isyes");
|
||||
if (isYes) resolve();
|
||||
else reject();
|
||||
modal.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
// =========================================== Top Navigation
|
||||
function showTab(tabname) {
|
||||
htmlToArray(document.querySelectorAll("#tab-navigate .tab-item")).forEach(tab => {
|
||||
tab.classList.remove("active");
|
||||
});
|
||||
htmlToArray(document.querySelectorAll(".bangle-tab")).forEach(tab => {
|
||||
tab.style.display = "none";
|
||||
});
|
||||
document.getElementById("tab-"+tabname).classList.add("active");
|
||||
document.getElementById(tabname).style.display = "inherit";
|
||||
}
|
||||
|
||||
// =========================================== Library
|
||||
function refreshLibrary() {
|
||||
var panelbody = document.querySelector("#librarycontainer .panel-body");
|
||||
panelbody.innerHTML = appjson.map((app,idx) => `<div class="tile">
|
||||
<div class="tile-icon">
|
||||
<figure class="avatar"><img src="apps/${app.icon}" alt="${escapeHtml(app.name)}"></figure>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<p class="tile-title text-bold">${escapeHtml(app.name)}</p>
|
||||
<p class="tile-subtitle">${escapeHtml(app.description)}</p>
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
<button class="btn btn-link btn-action btn-lg"><i class="icon icon-upload" appid="${app.id}"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
// set badge up top
|
||||
var 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 icon = event.target;
|
||||
var appid = icon.getAttribute("appid");
|
||||
var app = appjson.find(app=>app.id==appid);
|
||||
if (!app) return;
|
||||
icon.classList.remove("icon-upload");
|
||||
icon.classList.add("loading");
|
||||
Comms.uploadApp(app).then(() => {
|
||||
showToast(app.name+" Uploaded!");
|
||||
icon.classList.remove("loading");
|
||||
icon.classList.add("icon-delete");
|
||||
}).catch(() => {
|
||||
icon.classList.remove("loading");
|
||||
icon.classList.add("icon-upload");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
refreshLibrary();
|
||||
// =========================================== My Apps
|
||||
|
||||
function appNameToApp(appName) {
|
||||
var app = appjson.find(app=>app.id==appName);
|
||||
if (app) return app;
|
||||
return { id: "appName",
|
||||
name: "Unknown app "+appName,
|
||||
icon: "unknown.png",
|
||||
description: "Unknown app",
|
||||
storage: [],
|
||||
unknown: true,
|
||||
};
|
||||
}
|
||||
|
||||
function refreshMyApps() {
|
||||
var panelbody = document.querySelector("#myappscontainer .panel-body");
|
||||
var tab = document.querySelector("#tab-myappscontainer a");
|
||||
// set badge up top
|
||||
tab.classList.add("badge");
|
||||
tab.setAttribute("data-badge", "");
|
||||
// Loading indicator
|
||||
panelbody.innerHTML = '<div class="loading loading-lg"></div>';
|
||||
// Get apps
|
||||
Comms.getInstalledApps().then(appIDs => {
|
||||
tab.setAttribute("data-badge", appIDs.length);
|
||||
panelbody.innerHTML = appIDs.map(appNameToApp).sort(appSorter).map(app => `<div class="tile">
|
||||
<div class="tile-icon">
|
||||
<figure class="avatar"><img src="apps/${app.icon}" alt="${escapeHtml(app.name)}"></figure>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<p class="tile-title text-bold">${escapeHtml(app.name)}</p>
|
||||
<p class="tile-subtitle">${escapeHtml(app.description)}</p>
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
<button class="btn btn-link btn-action btn-lg"><i class="icon icon-delete" appid="${app.id}"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
htmlToArray(panelbody.getElementsByTagName("button")).forEach(button => {
|
||||
button.addEventListener("click",event => {
|
||||
var icon = event.target;
|
||||
var appid = icon.getAttribute("appid");
|
||||
var app = appNameToApp(appid);
|
||||
showPrompt("Delete","Really remove app '"+appid+"'?").then(() => {
|
||||
// remove app!
|
||||
refreshMyApps();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
document.getElementById("myappsrefresh").addEventListener("click",event=>{
|
||||
refreshMyApps();
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
function escapeHtml(text) {
|
||||
var map = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
|
||||
}
|
||||
function htmlToArray(collection) {
|
||||
return [].slice.call(collection);
|
||||
}
|
||||
function htmlElement(str) {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = str.trim();
|
||||
return div.firstChild;
|
||||
}
|
||||
function httpGet(url) {
|
||||
return new Promise((resolve,reject) => {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.addEventListener("load", () => resolve(oReq.responseText));
|
||||
oReq.addEventListener("error", () => reject());
|
||||
oReq.addEventListener("abort", () => reject());
|
||||
oReq.open("GET", url);
|
||||
oReq.send();
|
||||
});
|
||||
}
|
||||
function toJS(txt) {
|
||||
return JSON.stringify(txt);
|
||||
}
|
||||
// callback for sorting apps
|
||||
function appSorter(a,b) {
|
||||
if (a.unknown || b.unknown)
|
||||
return (a.unknown)? 1 : -1;
|
||||
return (a.name==b.name) ? 0 : ((a.name<b.name) ? -1 : 1);
|
||||
}
|
Loading…
Reference in New Issue