forked from Netsyms/PackageHelper
Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
424c6b3987 | |||
4d9b4abd19 | |||
771fd271c2 | |||
e1ded04c9b | |||
261b797a85 | |||
bbdf21f8a2 | |||
7c25b8c3b3 | |||
acd0c86447 | |||
5f28ee8a7e | |||
d5e6d7eaee | |||
7d39c12fce | |||
a0cbb0dbe5 | |||
91e31c449e | |||
b50524903d | |||
1f942ecafe | |||
5306f25a97 | |||
78f9c5f31f | |||
c69b8933ab | |||
00600ffee9 | |||
1796e45f92 | |||
5d9944a9c4 | |||
b25a292f34 | |||
13021af8ca | |||
1c8c7cc2e7 | |||
90aeb804ae | |||
31dee00cb1 | |||
8514582bcb | |||
403708572e | |||
09b51d95f0 | |||
faa13a1588 | |||
f3f3653d2c | |||
976f44a4f8 | |||
008ab56ce8 | |||
4c24d8fba8 | |||
9f5caa2593 | |||
c4900d2505 | |||
efd39a2349 | |||
df06534d72 | |||
c1f74e43fe | |||
384dac7b85 | |||
d0c3988566 | |||
70fa409015 | |||
3602f77343 |
@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="com.netsyms.PackageHelper" version="1.2.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<widget id="com.netsyms.PackageHelper" version="1.3.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>PackageHelper</name>
|
||||
<description>
|
||||
Assistant app for door-to-door package delivery.
|
||||
@ -32,7 +32,5 @@
|
||||
<allow-intent href="itms:*" />
|
||||
<allow-intent href="itms-apps:*" />
|
||||
</platform>
|
||||
<hook src="scripts/www_npm_install.sh" type="before_prepare" />
|
||||
<hook src="scripts/generate_credits.sh" type="before_prepare" />
|
||||
<hook src="scripts/remove_bloat.sh" type="before_prepare" />
|
||||
<hook src="scripts/npm_prepare.sh" type="before_prepare" />
|
||||
</widget>
|
||||
|
1179
license-credits.md
1179
license-credits.md
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "com.netsyms.packagehelper",
|
||||
"displayName": "PackageHelper",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"description": "Assistant app for door-to-door package delivery.",
|
||||
"main": "www/index.html",
|
||||
"scripts": {
|
||||
@ -18,7 +18,8 @@
|
||||
"cordova-plugin-inappbrowser": {},
|
||||
"cordova-plugin-powermanagement-netsyms": {},
|
||||
"cordova-plugin-whitelist": {},
|
||||
"phonegap-plugin-barcodescanner": {}
|
||||
"phonegap-plugin-barcodescanner": {},
|
||||
"cordova-plugin-device": {}
|
||||
},
|
||||
"platforms": [
|
||||
"android",
|
||||
@ -28,6 +29,7 @@
|
||||
"dependencies": {
|
||||
"cordova-android": "^8.1.0",
|
||||
"cordova-browser": "^6.0.0",
|
||||
"cordova-plugin-device": "^2.0.3",
|
||||
"cordova-plugin-inappbrowser": "^3.1.0",
|
||||
"cordova-plugin-powermanagement-netsyms": "git+https://source.netsyms.com/Netsyms/cordova-plugin-powermanagement",
|
||||
"cordova-plugin-whitelist": "^1.3.4"
|
||||
|
@ -1,3 +1,4 @@
|
||||
#!/bin/bash
|
||||
cd www
|
||||
yarn licenses generate-disclaimer > ../license-credits.md
|
||||
cd ..
|
||||
|
5
scripts/npm_prepare.sh
Executable file
5
scripts/npm_prepare.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
./scripts/www_npm_install.sh
|
||||
./scripts/generate_credits.sh
|
||||
./scripts/remove_bloat.sh
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# This script removes some stuff in `www/node_modules` that the app doesn't need to run.
|
||||
# It removes about 6MB from the build size.
|
||||
|
||||
@ -7,60 +7,80 @@ echo "Removing bloat in node_modules..."
|
||||
pwd
|
||||
|
||||
cd www/node_modules
|
||||
rm -rf dom7
|
||||
rm -rf path-to-regexp
|
||||
rm -rf ssr-window
|
||||
rm -rf template7
|
||||
rm -rf {ansicolors,buffer-from,cardinal,concat-stream,core-util-is,csscolorparser}
|
||||
rm -rf {dom7,earcut,esprima,geojson-vt,gl-matrix,grid-index,ieee754,inherits,isarray}
|
||||
rm -rf {kdbush,leaflet-geometryutil,@mapbox,minimist,murmurhash-js}
|
||||
rm -rf {path-to-regexp,pbf,potpack,process-nextick-args}
|
||||
rm -rf {protocol-buffers-schema,quickselect,readable-stream,redeyed,resolve-protobuf-schema}
|
||||
rm -rf {rw,safe-buffer,sharkdown,split,ssr-window,string_decoder,supercluster}
|
||||
rm -rf {template7,text-encoding,through,tinyqueue,ts-custom-error,typedarray}
|
||||
rm -rf {util-deprecate,vt-pbf,wgs84}
|
||||
|
||||
# Make npm stop complaining that these don't exist by actually removing them
|
||||
rm -rf .bin/*
|
||||
|
||||
|
||||
cd @fortawesome/fontawesome-free
|
||||
rm -rf js
|
||||
rm -rf less
|
||||
rm -rf scss
|
||||
rm -rf sprites
|
||||
rm -rf svgs
|
||||
rm -rf {js,less,metadata,scss,sprites,svgs}
|
||||
find css -type f -not -name 'all.min.css' -delete
|
||||
cd ../..
|
||||
|
||||
cd jquery
|
||||
rm -rf src
|
||||
rm -rf external
|
||||
cd ..
|
||||
|
||||
cd jsbarcode
|
||||
rm -rf .dockerignore .eslintignore .eslintrcautomation bower.json CONTRIBUTING.md docker-compose.yml Dockerfile example gulpfile.js jsbarcode.d.ts README.md src test .travis.yml
|
||||
rm -rf dist/barcodes
|
||||
rm -rf dist/JsBarcode.all.js
|
||||
|
||||
cd framework7
|
||||
rm -rf components
|
||||
rm -rf lazy-components
|
||||
rm -rf less
|
||||
rm -rf modules
|
||||
rm -rf utils
|
||||
rm -f framework7.*
|
||||
rm -f framework7-lite.*
|
||||
find css -type f -not -name 'framework7.bundle.min.css' -delete
|
||||
find js -type f -not -name 'framework7.bundle.min.js' -delete
|
||||
cd ..
|
||||
|
||||
cd jquery
|
||||
rm -rf src
|
||||
rm -rf external
|
||||
find dist -type f -not -name 'jquery.min.js' -delete
|
||||
cd ..
|
||||
|
||||
cd jsbarcode
|
||||
rm -rf .dockerignore .eslintignore .eslintrcautomation bower.json CONTRIBUTING.md docker-compose.yml Dockerfile example gulpfile.js jsbarcode.d.ts README.md src test .travis.yml
|
||||
rm -rf {automation,bin}
|
||||
rm -rf dist/barcodes
|
||||
rm -rf dist/JsBarcode.all.js
|
||||
cd ..
|
||||
|
||||
cd leaflet
|
||||
rm -rf {CHANGELOG.md,src}
|
||||
find dist -type f -not -name 'leaflet.css' -not -name 'leaflet.js' -delete
|
||||
cd ..
|
||||
|
||||
cd leaflet.locatecontrol
|
||||
rm -rf {CHANGELOG.md,README.md,src}
|
||||
find dist -type f -not -name 'L.Control.Locate.min.css' -not -name 'L.Control.Locate.min.js' -delete
|
||||
cd ..
|
||||
|
||||
cd leaflet.markercluster
|
||||
rm -rf {build,example,spec,src,CHANGELOG.md}
|
||||
find dist -type f -not -name 'leaflet.markercluster.js' -not -name 'MarkerCluster.css' -not -name 'MarkerCluster.Default.css' -delete
|
||||
cd ..
|
||||
|
||||
cd material-design-icons
|
||||
rm -rf action
|
||||
rm -rf alert
|
||||
rm -rf av
|
||||
rm -rf bower.json
|
||||
rm -rf communication
|
||||
rm -rf content
|
||||
rm -rf device
|
||||
rm -rf editor
|
||||
rm -rf file
|
||||
rm -rf gulpfile.babel.js
|
||||
rm -rf hardware
|
||||
rm -rf image
|
||||
rm -rf index.js
|
||||
rm -rf maps
|
||||
rm -rf navigation
|
||||
rm -rf notification
|
||||
rm -rf package.json
|
||||
rm -rf places
|
||||
rm -rf README.md
|
||||
rm -rf social
|
||||
rm -rf sprites
|
||||
rm -rf toggle
|
||||
# Remove everything except the icon font and license, but also exclude the
|
||||
# current and parent folder (. , ..) so rm won't complain about refusing
|
||||
# to delete the whole filesystem
|
||||
find . -maxdepth 1 -not -name '.' -not -name 'LICENSE' -not -name 'iconfont' -exec rm -rf {} \;
|
||||
cd ..
|
||||
|
||||
cd mapbox-gl
|
||||
rm -rf {build,flow-typed,src}
|
||||
find dist -type f -not -name 'mapbox-gl.css' -not -name 'mapbox-gl.js' -delete
|
||||
rm -rf dist/style-spec
|
||||
cd ..
|
||||
|
||||
cd @zxing/library
|
||||
rm -rf {esm,esm5}
|
||||
rm -f umd/index.min.js.map
|
||||
cd ../..
|
||||
|
||||
echo "Cleanup finished"
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
cd www
|
||||
npm install
|
||||
|
@ -18,3 +18,32 @@ Framework7 and FontAwesome both have a .fab class
|
||||
font-size: var(--f7-font-size);
|
||||
line-height: var(--f7-line-height);
|
||||
}
|
||||
|
||||
/*
|
||||
* Material icons are too big and disrupt the flow of text
|
||||
*/
|
||||
.block .material-icons {
|
||||
font-size: var(--f7-block-font-size);
|
||||
}
|
||||
|
||||
.material-icons.material-icons-24px {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.material-icons-intext .material-icons {
|
||||
font-size: var(--f7-block-font-size);
|
||||
}
|
||||
|
||||
#mapbox .package-marker {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
background-image: url(../images/box.png);
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
/* Allow tapping/clicking on package markers
|
||||
* when the location dot is overlapping them
|
||||
*/
|
||||
#mapbox .mapboxgl-user-location-dot {
|
||||
pointer-events: none;
|
||||
}
|
60
www/assets/images/barcode-dashed.svg
Normal file
60
www/assets/images/barcode-dashed.svg
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
class="svg-inline--fa fa-history fa-w-16"
|
||||
aria-hidden="true"
|
||||
data-icon="history"
|
||||
data-prefix="far"
|
||||
focusable="false"
|
||||
role="img"
|
||||
version="1.1"
|
||||
viewBox="0 0 512 512"
|
||||
id="svg877"
|
||||
sodipodi:docname="barcode-dashed.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata883">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs881" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1015"
|
||||
id="namedview879"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.4980469"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="256"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg877" />
|
||||
<path
|
||||
id="path952"
|
||||
d="M 25.36636,428.97523 V 83.02477 h 16.216428 v 345.95046 z m 24.195811,-0.24595 V 83.02477 h 8.237044 v 345.70451 z m 24.453472,0 V 83.02477 h 7.979383 v 345.70451 z m 40.412237,0 V 83.02477 h 7.97938 v 345.70451 z m 32.43286,0 V 83.02477 h 15.95876 v 345.70451 z m 40.41224,0 V 83.02477 h 7.97938 v 345.70451 z m 16.21642,0 V 83.02477 h 7.97939 v 345.70451 z m 16.21643,0 V 83.02477 h 7.97938 v 345.70451 z m 32.1761,0 V 83.02477 h 16.21642 v 345.70451 z m 40.41224,0 V 83.02477 h 16.21642 v 345.70451 z m 32.43195,0 V 83.02477 h 16.21733 v 345.70451 z m 32.43376,0 V 83.02477 h 16.21732 v 345.70451 z m 24.19581,0 V 83.02477 h 16.21642 v 345.70451 z m 40.6699,0 V 83.02477 h 24.19581 v 345.70451 z m 32.17519,0 V 83.02477 h 8.23705 v 345.70451 z m 16.21643,0.24595 V 83.02477 h 16.21643 v 345.95046 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#9e9e9e;fill-opacity:1;stroke:none;stroke-width:10.00063038;stroke-miterlimit:4;stroke-dasharray:5.00031521, 5.00031521;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
@ -76,7 +76,7 @@ function addAutofillEntry(address) {
|
||||
function searchAutofill(q, number) {
|
||||
var byNumber = [];
|
||||
if (typeof number != 'undefined') {
|
||||
byNumber = searchAutofillByNumber(number);
|
||||
byNumber = searchAutofillByNumber(number, q);
|
||||
}
|
||||
|
||||
var byStreet = [];
|
||||
@ -87,7 +87,7 @@ function searchAutofill(q, number) {
|
||||
return byNumber.concat(byStreet.filter((item) => byNumber.indexOf(item) < 0));
|
||||
}
|
||||
|
||||
function searchAutofillByNumber(number) {
|
||||
function searchAutofillByNumber(number, q) {
|
||||
if (typeof autofillDB[number] == 'undefined') {
|
||||
return [];
|
||||
}
|
||||
@ -96,11 +96,19 @@ function searchAutofillByNumber(number) {
|
||||
return b[1] - a[1];
|
||||
});
|
||||
|
||||
var query = false;
|
||||
if (typeof q != 'undefined' && q != "") {
|
||||
query = true;
|
||||
}
|
||||
|
||||
var streets = [];
|
||||
|
||||
for (var i = 0; i < sorted.length; i++) {
|
||||
// if there's no search query OR if the query matches the current item
|
||||
if (!query || (query && sorted[i][0].toLowerCase().includes(q))) {
|
||||
streets.push(sorted[i][0]);
|
||||
}
|
||||
}
|
||||
|
||||
return streets;
|
||||
}
|
||||
@ -112,12 +120,12 @@ function searchAutofillByStreet(q) {
|
||||
return b[1] - a[1];
|
||||
});
|
||||
|
||||
console.log(sortedDB);
|
||||
//console.log(sortedDB);
|
||||
|
||||
q = q.toLowerCase();
|
||||
|
||||
for (var i = 0; i < sortedDB.length; i++) {
|
||||
console.log(sortedDB[i][0].toLowerCase().indexOf(q));
|
||||
//console.log(sortedDB[i][0].toLowerCase().indexOf(q));
|
||||
if (sortedDB[i][0].toLowerCase().includes(q)) {
|
||||
streets.push(sortedDB[i][0]);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ $(".view-main").on("click", "#addresslist .package-list-item .directions-btn", f
|
||||
});
|
||||
|
||||
$(".view-main").on("swipeout:delete", "#addresslist .package-list-item", function () {
|
||||
console.log("Deleting package", $(this).data("packageid"));
|
||||
console.log("Info", "Deleting package", $(this).data("packageid"));
|
||||
deletePackage($(this).data("packageid"));
|
||||
});
|
||||
|
||||
@ -62,8 +62,8 @@ function loadPackageList(sortType) {
|
||||
var anum = parseInt(a.value.address.split(" ", 1)[0], 10);
|
||||
var bnum = parseInt(b.value.address.split(" ", 1)[0], 10);
|
||||
|
||||
console.log("aalpha", aalpha);
|
||||
console.log("balpha", balpha);
|
||||
//console.log("aalpha", aalpha);
|
||||
//console.log("balpha", balpha);
|
||||
switch (sortType) {
|
||||
case "alpha_desc":
|
||||
if (aalpha > balpha) {
|
||||
|
@ -45,14 +45,10 @@ if ("geolocation" in navigator) {
|
||||
localStorage.setItem("user_latitude", userPosition.coords.latitude);
|
||||
localStorage.setItem("user_longitude", userPosition.coords.longitude);
|
||||
if (mapLocationControlStarted) {
|
||||
//setMapLocation(position.coords.latitude, position.coords.longitude);
|
||||
// Don't refresh at an interval less than ten seconds
|
||||
var currentTimestamp = Math.floor(Date.now() / 1000);
|
||||
if (lastGpsUpdateTimestamp < (currentTimestamp - 10)) {
|
||||
updateDistances(position.coords.latitude, position.coords.longitude);
|
||||
if (map != null) {
|
||||
//map.updatePackageLayer(packages);
|
||||
}
|
||||
|
||||
var alertinterval = localStorage.getItem("alertinterval");
|
||||
if (alertinterval == null) {
|
||||
@ -89,7 +85,7 @@ if ("geolocation" in navigator) {
|
||||
}
|
||||
} else {
|
||||
if (map != null) {
|
||||
map.locateControl.start();
|
||||
map.startLocateControl();
|
||||
mapLocationControlStarted = true;
|
||||
}
|
||||
}
|
||||
@ -104,7 +100,7 @@ if ("geolocation" in navigator) {
|
||||
});
|
||||
} else {
|
||||
geoerrorcount++;
|
||||
console.log("Geolocation error #" + geoerrorcount + ": ", error);
|
||||
console.log("Warn", "Geolocation error #" + geoerrorcount + ": ", error);
|
||||
// Stop showing error toasts if they're happening a lot
|
||||
if (geoerrorcount <= 3) {
|
||||
app.toast.show({
|
||||
|
@ -63,10 +63,7 @@ router.on("pageInit", function (pagedata) {
|
||||
});
|
||||
|
||||
router.on("routeChange", function (newRoute) {
|
||||
console.log(newRoute);
|
||||
if (newRoute == "home") {
|
||||
router.refreshPage();
|
||||
}
|
||||
console.log("Info", "Navigating to ", newRoute.path);
|
||||
});
|
||||
|
||||
// Set alert radius to 100 meters by default
|
||||
|
@ -43,7 +43,12 @@ $("#addpackagebtn").click(function () {
|
||||
|
||||
var address = ($("input[name=number]").val() + " " + $("input[name=street]").val()).toUpperCase();
|
||||
$("#no-history").addClass("display-none");
|
||||
addPackageByAddress(address, $("input[name=citystate]").val().toUpperCase(), $("input[name=itemtype]:checked").val(), function (ids) {
|
||||
addPackageByAddress(
|
||||
$("input[name=number]").val().toUpperCase(),
|
||||
$("input[name=street]").val().toUpperCase(),
|
||||
$("input[name=citystate]").val().toUpperCase(),
|
||||
$("input[name=itemtype]:checked").val(),
|
||||
function (ids) {
|
||||
var packageObj = getPackage(ids.packageID);
|
||||
// Reset item type to default
|
||||
$("input[name=itemtype][data-default=1]").prop("checked", true);
|
||||
@ -66,9 +71,9 @@ $("#addpackagebtn").click(function () {
|
||||
$(".view-main").off("click", "#historylist .history-list-item");
|
||||
|
||||
$(".view-main").on("click", "#historylist .history-list-item", function () {
|
||||
console.log("Asking to delete ", $(this).data("package"));
|
||||
console.log("Info", "Asking to delete ", $(this).data("package"));
|
||||
confirmDeletePackage(getPackage($(this).data("package")), function (id) {
|
||||
console.log("Removing history item", id);
|
||||
console.log("Info", "Removing history item", id);
|
||||
$('#historylist .history-list-item[data-package="' + id + '"]').remove();
|
||||
if ($('#historylist .history-list-item').length == 0) {
|
||||
$("#no-history").removeClass("display-none");
|
||||
|
@ -6,8 +6,24 @@
|
||||
|
||||
var map = null;
|
||||
|
||||
var maptype = "mapbox";
|
||||
|
||||
function createMap() {
|
||||
if (localStorage.getItem("maptype") == null) {
|
||||
localStorage.setItem("maptype", "mapbox");
|
||||
}
|
||||
maptype = localStorage.getItem("maptype");
|
||||
if (maptype == "mapbox") {
|
||||
if (mapboxgl.supported()) {
|
||||
map = mapboxMap();
|
||||
} else {
|
||||
console.log("Warn", "mapbox-gl not supported, falling back to Leaflet");
|
||||
maptype = "leaflet";
|
||||
map = leafletMap();
|
||||
}
|
||||
} else {
|
||||
map = leafletMap();
|
||||
}
|
||||
map.updatePackageLayer(packages);
|
||||
}
|
||||
|
||||
@ -20,16 +36,37 @@ function reloadMap() {
|
||||
if (map != null && typeof map != 'undefined') {
|
||||
var mapcenter = map.getCenter();
|
||||
var mapzoom = map.getZoom();
|
||||
if (map.maptype == "mapbox") {
|
||||
var mapbearing = map.getBearing();
|
||||
var mappitch = map.getPitch();
|
||||
}
|
||||
|
||||
map.off();
|
||||
map.remove();
|
||||
map = null;
|
||||
|
||||
if (document.getElementById("mapbox") != null) {
|
||||
createMap();
|
||||
|
||||
if (map.maptype == "mapbox") {
|
||||
map.jumpTo({
|
||||
center: mapcenter,
|
||||
zoom: mapzoom,
|
||||
bearing: mapbearing,
|
||||
pitch: mappitch
|
||||
});
|
||||
} else {
|
||||
map.setView(mapcenter, mapzoom);
|
||||
}
|
||||
} else {
|
||||
console.log("Info", "Not re-creating map because #mapbox is not in DOM. Creation will be automatically triggered when map page is loaded.");
|
||||
}
|
||||
} else {
|
||||
createMap();
|
||||
}
|
||||
} catch (ex) {
|
||||
// oh well ¯\(°_o)/¯
|
||||
console.log(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,12 +85,12 @@ function openPackageInfoSheet(coordid, refreshOnly) {
|
||||
refreshOnly = false;
|
||||
}
|
||||
|
||||
console.log("Packages array: ", packages);
|
||||
//console.log("Packages array: ", packages);
|
||||
|
||||
for (var i = 0; i < packages.length; i++) {
|
||||
if (packages[i].id == coordid) {
|
||||
package = packages[i];
|
||||
console.log("Single Address:", package);
|
||||
//console.log("Single Address:", package);
|
||||
|
||||
$("#package-info-get-directions").attr("href", "geo:" + package.coords[0] + "," + package.coords[1]);
|
||||
$("#package-info-sheet-inner .list ul").html("");
|
||||
|
@ -14,6 +14,8 @@ function leafletMap() {
|
||||
attributionControl: false
|
||||
});
|
||||
|
||||
map.maptype = "leaflet";
|
||||
|
||||
if (localStorage.getItem("mapsource") == null) {
|
||||
localStorage.setItem("mapsource", "liberty");
|
||||
}
|
||||
@ -30,7 +32,7 @@ function leafletMap() {
|
||||
showPopup: false,
|
||||
locateOptions: {
|
||||
enableHighAccuracy: true,
|
||||
maxZoom: 16
|
||||
maxZoom: localStorage.getItem("trackzoom") == null ? 16 : localStorage.getItem("trackzoom") * 1
|
||||
},
|
||||
setView: "untilPanOrZoom",
|
||||
icon: "far fa-compass",
|
||||
@ -43,6 +45,14 @@ function leafletMap() {
|
||||
|
||||
map.setView({lat: userPosition.coords.latitude, lng: userPosition.coords.longitude}, 2);
|
||||
|
||||
map.startLocateControl = function () {
|
||||
map.locateControl.start();
|
||||
}
|
||||
|
||||
map.stopLocateControl = function () {
|
||||
|
||||
}
|
||||
|
||||
map.setMapHeading = function (heading) {
|
||||
|
||||
}
|
||||
@ -57,7 +67,7 @@ function leafletMap() {
|
||||
map.updatePackageLayer = function (data) {
|
||||
map.packagelayer.clearLayers();
|
||||
|
||||
console.log(data);
|
||||
//console.log(data);
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
// JavaScript variable scope and anonymous functions are dumb
|
||||
@ -65,7 +75,7 @@ function leafletMap() {
|
||||
// of the loop, or something like that
|
||||
(function (datai) {
|
||||
var iconName = getMapIconForItems(datai.items);
|
||||
console.log(iconName);
|
||||
//console.log(iconName);
|
||||
|
||||
var icon = L.icon({
|
||||
iconUrl: "assets/images/" + iconName + ".png",
|
||||
|
134
www/assets/js/map_mapbox.js
Normal file
134
www/assets/js/map_mapbox.js
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// If true, we'll do a fancy zoom/pan in
|
||||
// Otherwise we'll just jump to the correct location
|
||||
var firstload = true;
|
||||
|
||||
function mapboxMap() {
|
||||
|
||||
if (localStorage.getItem("mapsource") == null) {
|
||||
localStorage.setItem("mapsource", "liberty");
|
||||
}
|
||||
|
||||
$("#mapbox").css("background-color", SETTINGS.maptileurls[localStorage.getItem("mapsource")].bgcolor);
|
||||
|
||||
mapboxgl.accessToken = '';
|
||||
var map = new mapboxgl.Map({
|
||||
container: 'mapbox',
|
||||
style: SETTINGS.maptileurls[localStorage.getItem("mapsource")].json,
|
||||
attributionControl: false,
|
||||
dragPan: true,
|
||||
pitch: 0,
|
||||
zoom: 2,
|
||||
maxZoom: 19
|
||||
});
|
||||
|
||||
map.maptype = "mapbox";
|
||||
|
||||
map.addControl(new mapboxgl.NavigationControl({
|
||||
visualizePitch: true
|
||||
}), 'top-left');
|
||||
|
||||
map.addControl(
|
||||
new mapboxgl.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10 * 1000
|
||||
},
|
||||
fitBoundsOptions: {
|
||||
maxZoom: localStorage.getItem("trackzoom") == null ? 16 : localStorage.getItem("trackzoom") * 1
|
||||
},
|
||||
trackUserLocation: true
|
||||
}), 'top-left'
|
||||
);
|
||||
|
||||
map.startLocateControl = function () {
|
||||
// stub
|
||||
}
|
||||
|
||||
map.stopLocateControl = function () {
|
||||
// stub
|
||||
}
|
||||
|
||||
map.mapEasing = function (t) {
|
||||
return t * (2 - t);
|
||||
}
|
||||
|
||||
map.setMapHeading = function (heading) {
|
||||
if (typeof heading == 'number') {
|
||||
map.easeTo({
|
||||
bearing: heading,
|
||||
easing: map.mapEasing
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
map.setMapLocation = function (latitude, longitude) {
|
||||
map.easeTo({
|
||||
center: [
|
||||
longitude,
|
||||
latitude
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
map.updatePackageLayer = function (data) {
|
||||
var oldmarkers = document.getElementsByClassName("package-marker");
|
||||
if (oldmarkers.length > 0) {
|
||||
markerparent = oldmarkers[0].parentNode;
|
||||
while (oldmarkers.length > 0) {
|
||||
markerparent.removeChild(oldmarkers[0]);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
// JavaScript variable scope and anonymous functions are dumb
|
||||
// This is necessary, otherwise all the on(click)s will fire for the last iteration
|
||||
// of the loop, or something like that
|
||||
(function (datai) {
|
||||
var iconName = getMapIconForItems(datai.items);
|
||||
//console.log(iconName);
|
||||
|
||||
var el = document.createElement("div");
|
||||
el.className = "package-marker";
|
||||
|
||||
el.style = "background-image: url(assets/images/" + iconName + ".png);";
|
||||
|
||||
el.addEventListener('click', function () {
|
||||
openPackageInfoSheet(datai.id);
|
||||
});
|
||||
|
||||
new mapboxgl.Marker(el)
|
||||
.setLngLat([datai.coords[1], datai.coords[0]])
|
||||
.addTo(map);
|
||||
})(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
map.animateMapIn = function (latitude, longitude, zoom, heading) {
|
||||
if (typeof zoom == 'undefined') {
|
||||
zoom = 16;
|
||||
}
|
||||
if (typeof heading == 'undefined') {
|
||||
heading = 0;
|
||||
}
|
||||
map.flyTo({
|
||||
center: [
|
||||
longitude,
|
||||
latitude
|
||||
],
|
||||
speed: 1,
|
||||
zoom: zoom,
|
||||
heading: heading,
|
||||
pitch: 0
|
||||
});
|
||||
}
|
||||
|
||||
map.animateMapIn(userPosition.coords.latitude, userPosition.coords.longitude, 12);
|
||||
|
||||
return map;
|
||||
}
|
@ -11,14 +11,14 @@ if (localStorage.getItem("packages") != null) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Count how many items are still undelivered for an address.
|
||||
* @param {type} address An item in the packages array.
|
||||
* Count how many items are still undelivered for a location.
|
||||
* @param {type} location An item in the packages array.
|
||||
* @returns {Number}
|
||||
*/
|
||||
function getUndeliveredCount(address) {
|
||||
function getUndeliveredCount(location) {
|
||||
var undelivered = 0;
|
||||
for (var i = 0; i < address.items.length; i++) {
|
||||
if (!address.items[i].delivered) {
|
||||
for (var i = 0; i < location.items.length; i++) {
|
||||
if (!location.items[i].delivered) {
|
||||
undelivered++;
|
||||
}
|
||||
}
|
||||
@ -65,16 +65,16 @@ function getMapIconForItems(items) {
|
||||
// Count how many types we have, and set/overwrite the icon assuming we
|
||||
// only have that type. If we end up with multiple types, we return that
|
||||
// icon instead of a specific one.
|
||||
console.log(types);
|
||||
//console.log(types);
|
||||
for (var type in types) {
|
||||
console.log(type);
|
||||
//console.log(type);
|
||||
item_types++;
|
||||
if (types[type] == 1) {
|
||||
icon = SETTINGS.itemtypes[type].mapicon;
|
||||
} else {
|
||||
icon = SETTINGS.itemtypes[type].pluralmapicon;
|
||||
}
|
||||
console.log(icon);
|
||||
//console.log(icon);
|
||||
}
|
||||
if (item_types > 1) {
|
||||
return "multiple-items";
|
||||
@ -82,22 +82,31 @@ function getMapIconForItems(items) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
function addPackage(address, latitude, longitude, type, callback) {
|
||||
function addPackage(address, latitude, longitude, type, callback, deadline) {
|
||||
var added = false;
|
||||
if (typeof type == 'undefined') {
|
||||
type = "package";
|
||||
type = SETTINGS.itemtypes[0].id;
|
||||
}
|
||||
if (typeof deadline == 'undefined') {
|
||||
deadline = false;
|
||||
}
|
||||
|
||||
// Extra precision makes the map stupider,
|
||||
// and doesn't really increase accuracy since four decimal places ~= 11m
|
||||
latitude = +(parseFloat("" + latitude).toFixed(4));
|
||||
longitude = +(parseFloat("" + longitude).toFixed(4));
|
||||
|
||||
var packageID = uuidv4();
|
||||
var coordsID = "";
|
||||
|
||||
for (var i = 0; i < packages.length; i++) {
|
||||
if (packages[i].coords[0] == latitude && packages[i].coords[1] == longitude && packages[i].address == address) {
|
||||
if (packages[i].coords[0] == latitude && packages[i].coords[1] == longitude) {
|
||||
coordsID = packages[i].id;
|
||||
packages[i].items.push({
|
||||
address: address,
|
||||
delivered: false,
|
||||
type: type,
|
||||
deadline: deadline,
|
||||
id: packageID
|
||||
});
|
||||
added = true;
|
||||
@ -118,6 +127,7 @@ function addPackage(address, latitude, longitude, type, callback) {
|
||||
address: address,
|
||||
delivered: false,
|
||||
type: type,
|
||||
deadline: deadline,
|
||||
id: packageID
|
||||
}
|
||||
]
|
||||
@ -128,7 +138,7 @@ function addPackage(address, latitude, longitude, type, callback) {
|
||||
playSound("ok");
|
||||
|
||||
app.toast.show({
|
||||
text: 'Package Added!<br><span style="font-size: 80%;">' + address + "</span>",
|
||||
text: SETTINGS.itemtypes[type].name + ' Added!<br><span style="font-size: 80%;">' + address + "</span>",
|
||||
position: "bottom",
|
||||
destroyOnClose: true,
|
||||
closeTimeout: 1000 * 3
|
||||
@ -148,6 +158,51 @@ function addPackage(address, latitude, longitude, type, callback) {
|
||||
addAutofillEntry(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a second package list and merge it with the existing one.
|
||||
* @param {type} newlist
|
||||
* @return {number} The number of packages that were skipped because they already exist locally.
|
||||
*/
|
||||
function importPackageList(newlist) {
|
||||
skipped = 0;
|
||||
for (latlng in newlist) {
|
||||
var latitude = newlist[latlng].coords[0];
|
||||
var longitude = newlist[latlng].coords[1];
|
||||
|
||||
latitude = +(parseFloat("" + latitude).toFixed(4));
|
||||
longitude = +(parseFloat("" + longitude).toFixed(4));
|
||||
|
||||
for (pkg in newlist[latlng].items) {
|
||||
var added = false;
|
||||
for (var i = 0; i < packages.length; i++) {
|
||||
if (+(parseFloat("" + packages[i].coords[0]).toFixed(4)) == latitude && +(parseFloat("" + packages[i].coords[1]).toFixed(4)) == longitude) {
|
||||
var newpackage = newlist[latlng].items[pkg];
|
||||
for (var j in packages[i].items) {
|
||||
if (packages[i].items[j].id == newpackage.id) {
|
||||
// This package already exists in the local database.
|
||||
added = true;
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
packages[i].items.push(package);
|
||||
added = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
packages.push(newlist[latlng]);
|
||||
}
|
||||
}
|
||||
}
|
||||
localStorage.setItem("packages", JSON.stringify(packages));
|
||||
if (map != null) {
|
||||
reloadMap();
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
function markDelivered(id, delivered) {
|
||||
for (var i = 0; i < packages.length; i++) {
|
||||
for (var j = 0; j < packages[i].items.length; j++) {
|
||||
@ -173,7 +228,7 @@ function markDelivered(id, delivered) {
|
||||
|
||||
function confirmDeletePackage(package, callback) {
|
||||
app.dialog.confirm(
|
||||
"Delete item at " + package.address + "?",
|
||||
"Delete " + SETTINGS.itemtypes[package.type].name.toLowerCase() + " at " + package.address + "?",
|
||||
"Confirm",
|
||||
function () {
|
||||
// delete
|
||||
@ -229,14 +284,41 @@ function countPackages() {
|
||||
return count;
|
||||
}
|
||||
|
||||
function addPackageByAddress(address, citystate, type, callback) {
|
||||
function addPackageByAddress(number, street, citystate, type, callback) {
|
||||
var requestfinished = false;
|
||||
var searchingdialogopen = false;
|
||||
var deadline = false;
|
||||
|
||||
var ajaxlookup = function () {
|
||||
var geocodecache = localStorage.getItem("geocode_cache");
|
||||
if (geocodecache == null) {
|
||||
geocodecache = "{}";
|
||||
localStorage.setItem("geocode_cache", "{}");
|
||||
}
|
||||
|
||||
geocodecache = JSON.parse(geocodecache);
|
||||
var cachekey = number + " || " + street + " || " + citystate;
|
||||
var cacheitem = geocodecache[cachekey];
|
||||
var timestamp = Math.floor(Date.now() / 1000);
|
||||
if (typeof cacheitem != 'undefined') {
|
||||
if (cacheitem.added + SETTINGS.geocodecacheexpiry < timestamp) {
|
||||
console.log("Info", "Removing expired geocode cache item " + cachekey);
|
||||
delete geocodecache[cachekey];
|
||||
localStorage.setItem("geocode_cache", JSON.stringify(geocodecache));
|
||||
} else {
|
||||
console.log("Info", "Using cached geocode result", cacheitem);
|
||||
addPackage(cacheitem.address, cacheitem.latitude, cacheitem.longitude, type, callback, deadline);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: SETTINGS.geocodeapi,
|
||||
dataType: 'json',
|
||||
data: {
|
||||
address: address + " " + citystate
|
||||
number: number,
|
||||
street: street,
|
||||
citystate: citystate
|
||||
},
|
||||
timeout: 15 * 1000,
|
||||
success: function (resp) {
|
||||
@ -247,7 +329,14 @@ function addPackageByAddress(address, citystate, type, callback) {
|
||||
requestfinished = true;
|
||||
if (resp.status == "OK") {
|
||||
if (resp.accuracy.ok) {
|
||||
addPackage(resp.address.street, resp.coords[0], resp.coords[1], type, callback);
|
||||
addPackage(resp.address.street, resp.coords[0], resp.coords[1], type, callback, deadline);
|
||||
geocodecache[cachekey] = {
|
||||
address: resp.address.street,
|
||||
latitude: resp.coords[0],
|
||||
longitude: resp.coords[1],
|
||||
added: Math.floor(Date.now() / 1000)
|
||||
};
|
||||
localStorage.setItem("geocode_cache", JSON.stringify(geocodecache));
|
||||
} else {
|
||||
playSound("error");
|
||||
app.dialog.confirm(
|
||||
@ -255,9 +344,9 @@ function addPackageByAddress(address, citystate, type, callback) {
|
||||
"Accuracy Warning",
|
||||
function (ok) {
|
||||
if (resp.address.street == "") {
|
||||
addPackage(address, resp.coords[0], resp.coords[1], type, callback);
|
||||
addPackage(address, resp.coords[0], resp.coords[1], type, callback, deadline);
|
||||
} else {
|
||||
addPackage(resp.address.street, resp.coords[0], resp.coords[1], type, callback);
|
||||
addPackage(resp.address.street, resp.coords[0], resp.coords[1], type, callback, deadline);
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -285,4 +374,94 @@ function addPackageByAddress(address, citystate, type, callback) {
|
||||
searchingdialogopen = true;
|
||||
}
|
||||
}, 750);
|
||||
}
|
||||
|
||||
if (type == "express") {
|
||||
if (localStorage.getItem("deadlinealarm_minutes") == null) {
|
||||
localStorage.setItem("deadlinealarm_minutes", 20);
|
||||
}
|
||||
var minutes = localStorage.getItem("deadlinealarm_minutes");
|
||||
app.dialog.create({
|
||||
title: 'Express Item',
|
||||
text: 'Set a reminder for ' + minutes + ' minutes before:',
|
||||
buttons: [
|
||||
{
|
||||
text: '10:30 AM',
|
||||
close: true
|
||||
},
|
||||
{
|
||||
text: '12:00 PM',
|
||||
close: true
|
||||
},
|
||||
{
|
||||
text: '3:00 PM',
|
||||
close: true
|
||||
},
|
||||
{
|
||||
text: "No reminder",
|
||||
color: "red",
|
||||
close: true
|
||||
}
|
||||
],
|
||||
verticalButtons: true,
|
||||
onClick: function (dialog, index) {
|
||||
deadline = new Date();
|
||||
switch (index) {
|
||||
case 0:
|
||||
deadline.setMinutes(30);
|
||||
deadline.setHours(10);
|
||||
break;
|
||||
case 1:
|
||||
deadline.setMinutes(00);
|
||||
deadline.setHours(12);
|
||||
break;
|
||||
case 2:
|
||||
deadline.setMinutes(00);
|
||||
deadline.setHours(12 + 3);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
deadline = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (deadline != false) {
|
||||
deadline = deadline.getTime() / 1000;
|
||||
}
|
||||
ajaxlookup();
|
||||
}
|
||||
}).open();
|
||||
} else {
|
||||
ajaxlookup();
|
||||
}
|
||||
}
|
||||
|
||||
function checkDeadlines() {
|
||||
if (localStorage.getItem("deadlinealarm_minutes") == null) {
|
||||
localStorage.setItem("deadlinealarm_minutes", 20);
|
||||
}
|
||||
var minutes = localStorage.getItem("deadlinealarm_minutes");
|
||||
var currentTime = new Date().getTime() / 1000;
|
||||
var deadlineTime = currentTime + (minutes * 60);
|
||||
for (i in packages) {
|
||||
for (j in packages[i].items) {
|
||||
var item = packages[i].items[j];
|
||||
if (typeof item.deadline != 'undefined' && item.deadline != false && item.delivered != true) {
|
||||
if ((typeof item.deadlinealarmed == 'undefined' || item.deadlinealarmed != true) && item.deadline <= deadlineTime) {
|
||||
playSound("alert");
|
||||
app.dialog.alert(
|
||||
"Item at " + item.address + " needs to be delivered by " + timestampToTimeString(item.deadline) + " (" + Math.floor((item.deadline - currentTime) / 60) + " minutes from now).",
|
||||
"Delivery Alarm",
|
||||
function () {
|
||||
|
||||
}
|
||||
);
|
||||
packages[i].items[j].deadlinealarmed = true;
|
||||
localStorage.setItem("packages", JSON.stringify(packages));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(checkDeadlines, 15 * 1000);
|
@ -64,30 +64,76 @@ var watchLocation = function (success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
function setupHTML5BarcodeScanner() {
|
||||
$("body").append('<script src="node_modules/@zxing/library/umd/index.min.js"></script>');
|
||||
|
||||
scanBarcode = function (success, error) {
|
||||
$("#web-barcode-ui").removeClass("hidden");
|
||||
// Stolen from https://zxing-js.github.io/library/examples/multi-camera/
|
||||
const codeReader = new ZXing.BrowserMultiFormatReader();
|
||||
console.log("Info", 'ZXing code reader initialized');
|
||||
codeReader.getVideoInputDevices()
|
||||
.then((videoInputDevices) => {
|
||||
if (videoInputDevices.length == 0) {
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
error("A camera is required to scan barcodes.");
|
||||
return;
|
||||
}
|
||||
selectedDeviceId = videoInputDevices[0].deviceId;
|
||||
|
||||
codeReader.decodeFromInputVideoDeviceContinuously(selectedDeviceId, 'barcode-viewer', (result, err) => {
|
||||
if (result) {
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
success(result.text);
|
||||
return;
|
||||
}
|
||||
if (err && !(err instanceof ZXing.NotFoundException)) {
|
||||
console.error(err);
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
$("#web-barcode-ui").on("click", function () {
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function initCordova() {
|
||||
platform_type = "cordova";
|
||||
|
||||
// Handle back button to close things
|
||||
document.addEventListener("backbutton", function (event) {
|
||||
// Close map sheet if it's open
|
||||
if ($(".sheet-modal").hasClass("modal-in")) {
|
||||
app.sheet.close();
|
||||
} else {
|
||||
router.back({force: true, ignoreCache: true});
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.addEventListener("deviceready", function () {
|
||||
if (localStorage.getItem("wakelock") == "true") {
|
||||
window.powerManagement.acquire(function () {
|
||||
console.log('Wakelock acquired');
|
||||
console.log("Info", 'Wakelock acquired');
|
||||
}, function () {
|
||||
console.log('Failed to acquire wakelock');
|
||||
console.log("Warn", 'Failed to acquire wakelock');
|
||||
});
|
||||
} else {
|
||||
window.powerManagement.release(function () {
|
||||
console.log('Wakelock released');
|
||||
console.log("Info", 'Wakelock released');
|
||||
}, function () {
|
||||
console.log('Failed to release wakelock');
|
||||
console.log("Warn", 'Failed to release wakelock');
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
|
||||
openBrowser = function (url) {
|
||||
cordova.InAppBrowser.open(url, '_blank', 'location=yes');
|
||||
}
|
||||
@ -96,6 +142,7 @@ function initCordova() {
|
||||
window.open(url, '_system', '');
|
||||
}
|
||||
|
||||
if (typeof device != "undefined" && device.platform != "browser") {
|
||||
scanBarcode = function (success, error) {
|
||||
cordova.plugins.barcodeScanner.scan(
|
||||
function (result) {
|
||||
@ -110,20 +157,22 @@ function initCordova() {
|
||||
},
|
||||
{
|
||||
showTorchButton: true,
|
||||
showFlipCameraButton : true,
|
||||
showFlipCameraButton: true,
|
||||
prompt: "Scan barcode",
|
||||
resultDisplayDuration: 0,
|
||||
disableSuccessBeep: true,
|
||||
formats: "QR_CODE,DATA_MATRIX,CODE_39,CODE_93,CODE_128,CODABAR,PDF_417,AZTEC,MAXICODE"
|
||||
}
|
||||
);
|
||||
};
|
||||
} else {
|
||||
setupHTML5BarcodeScanner();
|
||||
}
|
||||
}
|
||||
|
||||
function initNW() {
|
||||
platform_type = "nw";
|
||||
platform_theme = "md";
|
||||
|
||||
openBrowser = function (url) {
|
||||
nw.Window.open(url, {
|
||||
id: url
|
||||
@ -156,57 +205,22 @@ function initNW() {
|
||||
require('nw.gui').Shell.openExternal(url);
|
||||
}
|
||||
|
||||
$("body").append('<script src="node_modules/@zxing/library/umd/index.min.js"></script>');
|
||||
|
||||
scanBarcode = function (success, error) {
|
||||
$("#web-barcode-ui").removeClass("hidden");
|
||||
// Stolen from https://zxing-js.github.io/library/examples/multi-camera/
|
||||
const codeReader = new ZXing.BrowserMultiFormatReader();
|
||||
console.log('ZXing code reader initialized');
|
||||
codeReader.getVideoInputDevices()
|
||||
.then((videoInputDevices) => {
|
||||
if (videoInputDevices.length == 0) {
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
error("A camera is required to scan barcodes.");
|
||||
return;
|
||||
}
|
||||
selectedDeviceId = videoInputDevices[0].deviceId;
|
||||
|
||||
codeReader.decodeFromInputVideoDeviceContinuously(selectedDeviceId, 'barcode-viewer', (result, err) => {
|
||||
if (result) {
|
||||
console.log(result);
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
success(result.text);
|
||||
return;
|
||||
}
|
||||
if (err && !(err instanceof ZXing.NotFoundException)) {
|
||||
console.error(err);
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
$("#web-barcode-ui").on("click", function () {
|
||||
codeReader.reset();
|
||||
$("#web-barcode-ui").addClass("hidden");
|
||||
});
|
||||
};
|
||||
setupHTML5BarcodeScanner();
|
||||
}
|
||||
|
||||
function initBrowser() {
|
||||
platform_type = "browser";
|
||||
platform_theme = "md";
|
||||
|
||||
openBrowser = function (url) {
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
openExternalBrowser = function (url) {
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
setupHTML5BarcodeScanner();
|
||||
}
|
||||
|
||||
function initPlatform() {
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
$('.item-content[data-setting=darktheme] .toggle input').on("change", function () {
|
||||
var checked = $(this).prop('checked');
|
||||
console.log(checked);
|
||||
localStorage.setItem("darktheme", checked);
|
||||
|
||||
if (localStorage.getItem("darktheme") == "true") {
|
||||
@ -17,27 +16,35 @@ $('.item-content[data-setting=darktheme] .toggle input').on("change", function (
|
||||
}
|
||||
});
|
||||
|
||||
$('.item-content[data-setting=showhelp] .toggle input').on("change", function () {
|
||||
var checked = $(this).prop('checked');
|
||||
localStorage.setItem("show_help", checked);
|
||||
});
|
||||
|
||||
$('.item-link[data-setting=units] select').on("change", function () {
|
||||
localStorage.setItem("units", $('.item-link[data-setting=units] select').val());
|
||||
});
|
||||
|
||||
$('.item-link[data-setting=trackzoom] select').on("change", function () {
|
||||
localStorage.setItem("trackzoom", $('.item-link[data-setting=trackzoom] select').val());
|
||||
});
|
||||
|
||||
$('.item-content[data-setting=wakelock] .toggle input').on("change", function () {
|
||||
var checked = $(this).prop('checked');
|
||||
console.log(checked);
|
||||
localStorage.setItem("wakelock", checked);
|
||||
|
||||
if (platform_type == "cordova") {
|
||||
if (localStorage.getItem("wakelock") == "true") {
|
||||
window.powerManagement.acquire(function () {
|
||||
console.log('Wakelock acquired');
|
||||
console.log("Info", 'Wakelock acquired');
|
||||
}, function () {
|
||||
console.log('Failed to acquire wakelock');
|
||||
console.log("Warn", 'Failed to acquire wakelock');
|
||||
});
|
||||
} else {
|
||||
window.powerManagement.release(function () {
|
||||
console.log('Wakelock released');
|
||||
console.log("Info", 'Wakelock released');
|
||||
}, function () {
|
||||
console.log('Failed to release wakelock');
|
||||
console.log("Warn", 'Failed to release wakelock');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -69,7 +76,16 @@ $('.item-content[data-setting=alertinterval] .range-slider').on('range:changed',
|
||||
|
||||
$('.item-link[data-setting=mapsource] select').on("change", function () {
|
||||
localStorage.setItem("mapsource", $('.item-link[data-setting=mapsource] select').val());
|
||||
// Re-init map to load new style
|
||||
|
||||
reloadMap();
|
||||
});
|
||||
|
||||
$('.item-content[data-setting=maptype] .toggle input').on("change", function () {
|
||||
var checked = $(this).prop('checked');
|
||||
localStorage.setItem("maptype", checked ? "leaflet" : "mapbox");
|
||||
|
||||
maptype = checked ? "leaflet" : "mapbox";
|
||||
|
||||
reloadMap();
|
||||
});
|
||||
|
||||
|
271
www/assets/js/toolbox_scanner.js
Normal file
271
www/assets/js/toolbox_scanner.js
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
var scannerCodes = [];
|
||||
|
||||
function resetScanner() {
|
||||
scannerCodes = [];
|
||||
app.popup.close("#scanEventTypePopup");
|
||||
app.popup.close("#scanEventPopup");
|
||||
router.refreshPage();
|
||||
}
|
||||
|
||||
function brokenScannerEsc() {
|
||||
app.dialog.confirm(
|
||||
"Clear list?",
|
||||
"Confirm",
|
||||
function () {
|
||||
resetScanner();
|
||||
},
|
||||
function () {
|
||||
// cancel
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function brokenScannerScan() {
|
||||
scanBarcode(function (code) {
|
||||
playSound("scan");
|
||||
if (code != "" && code.length > 5 && code.match(/^[0-9A-Z]+$/i)) {
|
||||
addCodeToScannerList(code);
|
||||
} else {
|
||||
app.dialog.alert("That's not a valid tracking code.", "Error");
|
||||
}
|
||||
}, function (error) {
|
||||
app.dialog.alert(error, "Error");
|
||||
});
|
||||
}
|
||||
|
||||
function brokenScannerAddTextEntry() {
|
||||
var code = $("#brokenscannerinput").val();
|
||||
if (code != "" && code.length > 5 && code.match(/^[0-9A-Z]+$/i)) {
|
||||
addCodeToScannerList(code);
|
||||
$("#brokenscannerinput").val("");
|
||||
} else {
|
||||
app.dialog.alert("That's not a valid tracking code.", "Error");
|
||||
}
|
||||
}
|
||||
|
||||
function addCodeToScannerList(code) {
|
||||
code = code.toUpperCase();
|
||||
|
||||
var signatureregexes = [
|
||||
/^E[A-Z][0-9]{9}US$/, // Priority Mail Express
|
||||
/^[RV][A-Z][0-9]{9}[A-Z]{2}$/, // Registered mail
|
||||
/^(420[0-9]{5})?7[0-9]{19}$/ // Certified Mail
|
||||
];
|
||||
|
||||
/**
|
||||
* Regex of IMpb codes that don't need anything special
|
||||
* @type {RegExp}
|
||||
*/
|
||||
var stcregex = /^(420[0-9]{5})?[0-9]{2}(001|023|055|056|112|113|134|135|138|140|141|142|164|209|211|259|265|269|346|361|389|390|419|431|490|502|551|563|612|624|671|701|702|703|704|723|746|748|790|791|793|794|905|906|907|909|971|972)[0-9]+$/;
|
||||
|
||||
var signatureRequired = false;
|
||||
for (var i = 0; i < signatureregexes.length; i++) {
|
||||
if (code.match(signatureregexes[i])) {
|
||||
signatureRequired = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!code.match(stcregex)) {
|
||||
signatureRequired = true;
|
||||
}
|
||||
|
||||
var codeEntryTemplate = Template7.compile('<li class="codelist-entry" data-code="{{code}}">'
|
||||
+ ' <div class="item-content">'
|
||||
+ ' <div class="item-inner">'
|
||||
+ ' <div class="item-title">{{code}}</div>'
|
||||
+ ' </div>'
|
||||
+ ' </div>'
|
||||
+ '</li>');
|
||||
|
||||
if (signatureRequired) {
|
||||
if (code.match(/^E[A-Z][0-9]{9}US$/)) {
|
||||
app.dialog.confirm(
|
||||
"Does this item contain a waiver of signature endorsement?",
|
||||
"Express Item",
|
||||
function () {
|
||||
$("#codelist").append(codeEntryTemplate({
|
||||
code: code
|
||||
}));
|
||||
},
|
||||
function () {
|
||||
// cancel
|
||||
}
|
||||
);
|
||||
} else {
|
||||
app.dialog.confirm(
|
||||
"It looks like this item might require a signature or other special procedures. Add it anyways?",
|
||||
"Signature Item",
|
||||
function () {
|
||||
$("#codelist").append(codeEntryTemplate({
|
||||
code: code
|
||||
}));
|
||||
},
|
||||
function () {
|
||||
// cancel
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$("#codelist").append(codeEntryTemplate({
|
||||
code: code
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function chooseScanEvent() {
|
||||
if ($("#codelist li.codelist-entry").length <= 0) {
|
||||
app.dialog.alert("Nothing was entered!");
|
||||
return;
|
||||
}
|
||||
|
||||
$("#codelist li.codelist-entry").each(function () {
|
||||
scannerCodes.push($(this).data("code"));
|
||||
});
|
||||
|
||||
|
||||
openEventPopup();
|
||||
}
|
||||
|
||||
function openEventPopup() {
|
||||
var eventItemTemplate = Template7.compile('<li data-button="{{button}}" data-title="{{title}}" class="eventbutton" onclick=\'openEventTypePopup("{{title}}");\'>'
|
||||
+ ' <div class="item-link item-content">'
|
||||
+ ' <div class="item-media">{{button}}</div>'
|
||||
+ ' <div class="item-inner">'
|
||||
+ ' <div class="item-title">{{title}}</div>'
|
||||
+ ' </div>'
|
||||
+ ' </div>'
|
||||
+ '</li>');
|
||||
|
||||
$("#scanEventPopup ul.eventlist").html("");
|
||||
for (i in SETTINGS.scannerevents) {
|
||||
var event = SETTINGS.scannerevents[i];
|
||||
$("#scanEventPopup ul.eventlist").append(eventItemTemplate({
|
||||
button: event.button,
|
||||
title: event.title
|
||||
}));
|
||||
}
|
||||
|
||||
app.popup.open("#scanEventPopup");
|
||||
}
|
||||
|
||||
function openEventTypePopup(eventname) {
|
||||
var eventItemTemplate = Template7.compile('<li data-button="{{button}}" data-title="{{title}}" data-parenttitle="{{parenttitle}}" data-form3849="{{form3849}}" class="eventbutton eventtypebutton">'
|
||||
+ ' <div class="item-link item-content">'
|
||||
+ ' <div class="item-media">{{button}}</div>'
|
||||
+ ' <div class="item-inner">'
|
||||
+ ' <div class="item-title">{{title}}</div>'
|
||||
+ ' </div>'
|
||||
+ ' </div>'
|
||||
+ '</li>');
|
||||
|
||||
var eventafter = false;
|
||||
for (i in SETTINGS.scannerevents) {
|
||||
var event = SETTINGS.scannerevents[i];
|
||||
if (event.title == eventname) {
|
||||
eventafter = event.after;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$("#scanEventTypePopup ul.eventlist").html("");
|
||||
for (i in eventafter) {
|
||||
var event = eventafter[i];
|
||||
$("#scanEventTypePopup ul.eventlist").append(eventItemTemplate({
|
||||
button: event.button,
|
||||
title: event.title,
|
||||
parenttitle: eventname,
|
||||
form3849: event.after == "3849" ? "1" : "0"
|
||||
}));
|
||||
}
|
||||
|
||||
app.popup.open("#scanEventTypePopup");
|
||||
}
|
||||
|
||||
function saveScanCode(code) {
|
||||
if (localStorage.getItem("scanevents") == null) {
|
||||
localStorage.setItem("scanevents", "[]");
|
||||
}
|
||||
var events = JSON.parse(localStorage.getItem("scanevents"));
|
||||
events.push(code);
|
||||
localStorage.setItem("scanevents", JSON.stringify(events));
|
||||
}
|
||||
|
||||
$(".view-main").off("click", "#codelist li.codelist-entry");
|
||||
|
||||
$(".view-main").on("click", "#codelist li.codelist-entry", function () {
|
||||
var entry = $(this);
|
||||
var code = entry.data("code");
|
||||
app.dialog.confirm(
|
||||
"Remove " + code + " from list?",
|
||||
"Confirm",
|
||||
function () {
|
||||
// delete
|
||||
entry.remove();
|
||||
},
|
||||
function () {
|
||||
// cancel
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#app").off("click", "ul li.eventtypebutton");
|
||||
$("#app").on("click", "ul li.eventtypebutton", function () {
|
||||
var eventname = $(this).data("parenttitle");
|
||||
var eventtypename = $(this).data("title");
|
||||
|
||||
var scanEvent = [];
|
||||
scanEvent.push(eventname);
|
||||
scanEvent.push(eventtypename);
|
||||
|
||||
if ($(this).data("form3849") == "1") {
|
||||
// TODO: make this not a hack
|
||||
app.dialog.prompt("Key in 3849 form", "3849 Form", function (formcode) {
|
||||
for (i in scannerCodes) {
|
||||
saveScanCode({
|
||||
code: scannerCodes[i],
|
||||
event: scanEvent,
|
||||
form3849: formcode,
|
||||
date: timestampToDateTimeString((new Date).getTime() / 1000)
|
||||
});
|
||||
}
|
||||
app.toast.show({
|
||||
text: 'Information recorded successfully!',
|
||||
position: "center",
|
||||
destroyOnClose: true,
|
||||
closeTimeout: 1000 * 3
|
||||
});
|
||||
resetScanner();
|
||||
}, function () {
|
||||
|
||||
}, "");
|
||||
} else {
|
||||
for (i in scannerCodes) {
|
||||
saveScanCode({
|
||||
code: scannerCodes[i],
|
||||
event: scanEvent,
|
||||
form3849: "",
|
||||
date: timestampToDateTimeString((new Date).getTime() / 1000)
|
||||
});
|
||||
}
|
||||
app.toast.show({
|
||||
text: 'Information recorded successfully!',
|
||||
position: "center",
|
||||
destroyOnClose: true,
|
||||
closeTimeout: 1000 * 3
|
||||
});
|
||||
resetScanner();
|
||||
}
|
||||
});
|
||||
|
||||
$("#brokenscannerinput").on('keypress', function (e) {
|
||||
if (event.key === "Enter") {
|
||||
brokenScannerAddTextEntry();
|
||||
}
|
||||
});
|
23
www/assets/js/toolbox_scannerentries.js
Normal file
23
www/assets/js/toolbox_scannerentries.js
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
function confirmDeleteScanEntries() {
|
||||
app.dialog.confirm(
|
||||
"Really delete all entries from scan list?",
|
||||
"Clear Entries",
|
||||
function () {
|
||||
// clear
|
||||
localStorage.setItem("scanevents", "[]");
|
||||
router.navigate("/toolbox/scanner/entries", {
|
||||
reloadCurrent: true
|
||||
});
|
||||
},
|
||||
function () {
|
||||
// cancel
|
||||
}
|
||||
);
|
||||
}
|
101
www/assets/js/toolbox_sharelist.js
Normal file
101
www/assets/js/toolbox_sharelist.js
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
function uploadList() {
|
||||
if (packages.length == 0) {
|
||||
app.dialog.alert("Your list doesn't have anything to send.", "Empty List");
|
||||
return;
|
||||
}
|
||||
app.dialog.preloader("Uploading...");
|
||||
var uploadlistdialogopen = true;
|
||||
$.ajax({
|
||||
url: SETTINGS.sharelistapi,
|
||||
dataType: 'json',
|
||||
method: 'post',
|
||||
data: {
|
||||
packages: JSON.stringify(packages)
|
||||
},
|
||||
timeout: 15 * 1000,
|
||||
success: function (resp) {
|
||||
if (uploadlistdialogopen) {
|
||||
app.dialog.close();
|
||||
uploadlistdialogopen = false;
|
||||
}
|
||||
if (resp.status == "OK") {
|
||||
JsBarcode("#listidbarcode", resp.uuid, {
|
||||
format: "code128",
|
||||
ean128: false,
|
||||
width: 2,
|
||||
height: 40
|
||||
});
|
||||
$("#listidbarcodeli").css("display", "");
|
||||
} else {
|
||||
app.dialog.alert(resp.message, "Error");
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, status, errorThrown) {
|
||||
if (uploadlistdialogopen) {
|
||||
app.dialog.close();
|
||||
uploadlistdialogopen = false;
|
||||
}
|
||||
app.dialog.alert("There was a network or server issue while uploading the list. Please try again.", "Error");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function downloadItemList(code) {
|
||||
if (typeof code == "undefined") {
|
||||
code = $("#getlistidbox").val();
|
||||
}
|
||||
if (code.match(/^[a-f0-9]{10}$/i)) {
|
||||
app.dialog.preloader("Downloading...");
|
||||
var downloadlistdialogopen = true;
|
||||
$.ajax({
|
||||
url: SETTINGS.sharelistapi,
|
||||
dataType: 'json',
|
||||
method: 'get',
|
||||
data: {
|
||||
uuid: code
|
||||
},
|
||||
timeout: 15 * 1000,
|
||||
success: function (resp) {
|
||||
if (downloadlistdialogopen) {
|
||||
app.dialog.close();
|
||||
downloadlistdialogopen = false;
|
||||
}
|
||||
if (resp.status == "OK") {
|
||||
var skipped = importPackageList(resp.packages);
|
||||
if (skipped > 0) {
|
||||
app.dialog.alert("List imported and merged with the existing one. " + skipped + " items already existed locally and were skipped. Verify their delivery status manually.", "Import Complete");
|
||||
} else {
|
||||
app.dialog.alert("List imported and merged with the existing one.", "Import Complete");
|
||||
}
|
||||
} else {
|
||||
app.dialog.alert(resp.message, "Error");
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, status, errorThrown) {
|
||||
if (downloadlistdialogopen) {
|
||||
app.dialog.close();
|
||||
downloadlistdialogopen = false;
|
||||
}
|
||||
app.dialog.alert("There was a network or server issue while downloading the list. Please try again.", "Error");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
app.dialog.alert("That's not a valid list ID.", "Error");
|
||||
}
|
||||
}
|
||||
|
||||
function scanListIDBarcode() {
|
||||
scanBarcode(function (code) {
|
||||
playSound("scan");
|
||||
downloadItemList(code);
|
||||
}, function (error) {
|
||||
app.dialog.alert(error, "Error");
|
||||
});
|
||||
}
|
@ -86,7 +86,21 @@ function openTrackingHistory(code) {
|
||||
infocontext.history[i].date = timestampToDateTimeString(infocontext.history[i].date);
|
||||
infocontext.history[i].status = trackingStatusToNiceString(infocontext.history[i].status, true);
|
||||
}
|
||||
// TODO: format timestamps as local time
|
||||
|
||||
// Keep last five tracking codes in history
|
||||
var history = localStorage.getItem("trackingcodehistory");
|
||||
if (history == null) {
|
||||
history = [];
|
||||
} else {
|
||||
history = JSON.parse(history);
|
||||
}
|
||||
if (infocontext.code != "" && !history.includes(infocontext.code)) {
|
||||
history.push(infocontext.code);
|
||||
}
|
||||
while (history.length > 5) {
|
||||
history.shift();
|
||||
}
|
||||
localStorage.setItem("trackingcodehistory", JSON.stringify(history));
|
||||
|
||||
if (refresh) {
|
||||
router.navigate("/toolbox/track/info", {
|
||||
@ -136,7 +150,7 @@ function scanTrackingBarcode() {
|
||||
}
|
||||
}, function (error) {
|
||||
app.dialog.alert(error, "Error");
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
$("#trackbtn").click(function () {
|
||||
@ -148,3 +162,9 @@ $("#trackbtn").click(function () {
|
||||
app.dialog.alert("That's not a valid tracking code.", "Error");
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name=trackingcode]").on('keypress', function (e) {
|
||||
if (event.key === "Enter") {
|
||||
$("#trackbtn").click();
|
||||
}
|
||||
});
|
@ -12,6 +12,7 @@
|
||||
<link rel="stylesheet" href="node_modules/leaflet.markercluster/dist/MarkerCluster.css" />
|
||||
<link rel="stylesheet" href="node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css" />
|
||||
<link rel="stylesheet" href="node_modules/leaflet.locatecontrol/dist/L.Control.Locate.min.css" />
|
||||
<link rel="stylesheet" href="node_modules/mapbox-gl/dist/mapbox-gl.css">
|
||||
<link rel="stylesheet" href="assets/css/app.css" />
|
||||
<link rel="stylesheet" href="assets/css/backdrop.css" />
|
||||
<link rel="stylesheet" href="assets/css/oled.css" />
|
||||
@ -36,6 +37,7 @@
|
||||
<script src="node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="node_modules/leaflet/dist/leaflet.js"></script>
|
||||
<script src="node_modules/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
|
||||
<script src="node_modules/mapbox-gl/dist/mapbox-gl.js"></script>
|
||||
<script src="node_modules/jsbarcode/dist/JsBarcode.all.min.js"></script>
|
||||
<script src="node_modules/leaflet.locatecontrol/dist/L.Control.Locate.min.js"></script>
|
||||
|
||||
@ -50,6 +52,7 @@
|
||||
<script src="assets/js/location.js"></script>
|
||||
<script src="assets/js/list.js"></script>
|
||||
<script src="assets/js/map_leaflet.js"></script>
|
||||
<script src="assets/js/map_mapbox.js"></script>
|
||||
<script src="assets/js/map.js"></script>
|
||||
<script src="assets/js/manage.js"></script>
|
||||
|
||||
|
@ -1,18 +1,19 @@
|
||||
{
|
||||
"name": "PackageHelper",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"main": "index.html",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.10.2",
|
||||
"@zxing/library": "^0.15.2",
|
||||
"framework7": "^5.0.2",
|
||||
"framework7": "^5.1.3",
|
||||
"jquery": "^3.4.1",
|
||||
"jsbarcode": "^3.11.0",
|
||||
"leaflet": "^1.5.1",
|
||||
"leaflet-geometryutil": "^0.9.1",
|
||||
"leaflet.locatecontrol": "^0.67.0",
|
||||
"leaflet.markercluster": "^1.4.1",
|
||||
"mapbox-gl": "^1.6.1",
|
||||
"material-design-icons": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {}
|
||||
|
@ -1,90 +0,0 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<div class="page" data-name="alertsettings">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="left">
|
||||
<a href="#" class="link icon-only back">
|
||||
<i class="icon icon-back"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="title">Alert Settings</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="page-content">
|
||||
<div class="list media-list no-hairlines tablet-inset" style="margin-top: 0;">
|
||||
<ul>
|
||||
{{#each settings}}
|
||||
<li>
|
||||
{{#if toggle}}
|
||||
<div class="item-content" data-setting="{{setting}}">
|
||||
<div class="item-inner">
|
||||
<div style="display: flex; justify-content: between;">
|
||||
<div class="item-title">
|
||||
{{title}}
|
||||
</div>
|
||||
<div class="item-after" onclick="{{onclick}}">
|
||||
<label class="toggle toggle-init">
|
||||
<input type="checkbox" {{#if checked}}checked{{/if}}>
|
||||
<span class="toggle-icon"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-text">{{text}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if slider}}
|
||||
<div class="item-content" data-setting="{{setting}}">
|
||||
<div class="item-inner">
|
||||
<div class="item-title" style="background-color: rgba(0,0,0,0);">
|
||||
{{title}}
|
||||
</div>
|
||||
<div class="item-subtitle padding-horizontal padding-top">
|
||||
<div class="range-slider range-slider-init padding-top margin-top" data-label="true">
|
||||
<input type="range" min="{{min}}" max="{{max}}" step="{{step}}" value="{{value}}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if select}}
|
||||
<a class="item-link smart-select smart-select-init" data-open-in="popover" data-setting="{{setting}}">
|
||||
<select>
|
||||
{{#each options}}
|
||||
<option value="{{value}}"{{#if selected}} selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<div class="item-content">
|
||||
<div class="item-inner">
|
||||
<div class="item-title">{{title}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{{else}}
|
||||
<div class="item-content" data-setting="{{setting}}" onclick="{{onclick}}">
|
||||
<div class="item-inner">
|
||||
<div class="item-title-row">
|
||||
<div class="item-title">{{title}}</div>
|
||||
</div>
|
||||
<div class="item-text">{{text}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/settings.js"></script>
|
||||
|
||||
</div>
|
File diff suppressed because it is too large
Load Diff
58
www/pages/help/list.html
Normal file
58
www/pages/help/list.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<div class="panel panel-right panel-cover">
|
||||
<div class="view">
|
||||
<div class="page">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="title">Help</div>
|
||||
<div class="right">
|
||||
<a class="link panel-close">
|
||||
<span>Close</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
<div class="block-title">Manage Items</div>
|
||||
<div class="block">
|
||||
Swipe <i class="fas fa-arrow-right"></i> left-to-right on a list entry
|
||||
to show the actions you can take.
|
||||
These actions are marking the item as delivered/undelivered, or
|
||||
navigating to its location with your device's default maps app.
|
||||
<br />
|
||||
Swipe <i class="fas fa-arrow-left"></i> right-to-left on a list entry
|
||||
and tap
|
||||
<span class="button button-small display-inline button-fill color-red text-color-white"><i class="material-icons">delete</i> Delete</span> to remove it.
|
||||
</div>
|
||||
|
||||
<div class="block-title">Clear the List</div>
|
||||
<div class="block">
|
||||
Tap the <span class="color-red text-color-primary"><i class="material-icons">delete</i></span>
|
||||
button to remove all items from the list. This cannot be undone, so it's
|
||||
a good idea to do it at the end of the day or in the morning before you start.
|
||||
Note that clearing the list does not affect the address autofill.
|
||||
</div>
|
||||
|
||||
<div class="block-title">Search</div>
|
||||
<div class="block">
|
||||
Tap the <i class="material-icons text-color-primary">search</i> button to open a search
|
||||
box. Type in this box to hide any list entries that don't contain your
|
||||
search query.
|
||||
</div>
|
||||
|
||||
<div class="block-title">Sort Items</div>
|
||||
<div class="block">
|
||||
Tap the <i class="material-icons text-color-primary">sort</i> button to sort
|
||||
the list. You can sort by distance from your current
|
||||
location, alphabetically by street name, and numerically by
|
||||
address number.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
77
www/pages/help/map.html
Normal file
77
www/pages/help/map.html
Normal file
@ -0,0 +1,77 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<div class="panel panel-right panel-cover">
|
||||
<div class="view">
|
||||
<div class="page">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="title">Help</div>
|
||||
<div class="right">
|
||||
<a class="link panel-close">
|
||||
<span>Close</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
<div class="block-title">Manage Items</div>
|
||||
<div class="block">
|
||||
Tap on an icon to see the item(s) at that location.
|
||||
Tap on an item to toggle it between delivered and
|
||||
undelivered. If two or more addresses are very close
|
||||
together, their items will be grouped under one icon.
|
||||
</div>
|
||||
|
||||
<div class="block-title">Move the Map</div>
|
||||
<div class="block">
|
||||
Pinch with two fingers or scroll with a mouse to zoom
|
||||
in and out. You can also double-tap to zoom in.
|
||||
Drag with one finger or a mouse to move (pan) the map.
|
||||
|
||||
<br />
|
||||
|
||||
If you prefer, tap or click
|
||||
<span class="button button-small display-inline button-fill color-white text-color-black"><i class="fas fa-plus"></i></span>
|
||||
and
|
||||
<span class="button button-small display-inline button-fill color-white text-color-black"><i class="fas fa-minus"></i></span>
|
||||
to zoom in and out.
|
||||
|
||||
<br />
|
||||
|
||||
Drag on
|
||||
<span class="button button-small display-inline button-fill color-white text-color-black"><i class="fas fa-sort"></i></span>
|
||||
to rotate and tilt the map. Dragging left and right rotates, up and down tilts.
|
||||
You can also rotate with two fingers by twisting them around each other,
|
||||
or with a keyboard by holding Ctrl and dragging the mouse.
|
||||
</div>
|
||||
|
||||
<div class="block-title">Follow Location</div>
|
||||
<div class="block">
|
||||
Tap
|
||||
<span class="button button-small display-inline button-fill color-white text-color-black"><i class='material-icons'>my_location</i></span>
|
||||
or
|
||||
<span class="button button-small display-inline button-fill color-white text-color-black"><i class='far fa-compass'></i></span>
|
||||
to show your current
|
||||
location on the map as a blue dot. The map will follow
|
||||
the dot until you zoom or move the map. If the dot goes
|
||||
off the edge of the map, press the button again to
|
||||
re-center the map. Pressing the button when the dot is
|
||||
visible will hide the dot and stop the map from
|
||||
following your location.
|
||||
</div>
|
||||
|
||||
<div class="block-title">Get Directions</div>
|
||||
<div class="block">
|
||||
<span class="text-color-primary"><i class="material-icons">directions</i></span> will open your
|
||||
default map/navigation app with the item location set as
|
||||
the destination. This is useful if you're having
|
||||
trouble finding the location.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -24,6 +24,12 @@
|
||||
<a class="link text-color-red" onclick="confirmDeleteAllPackages()">
|
||||
<i class="icon material-icons">delete</i>
|
||||
</a>
|
||||
|
||||
{{#if show_help}}
|
||||
<a class="link" href="/help/list">
|
||||
<i class="icon material-icons">help</i>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
<form class="searchbar searchbar-expandable package-list-searchbar">
|
||||
<div class="searchbar-inner">
|
||||
|
@ -15,9 +15,11 @@
|
||||
</div>
|
||||
<div class="title">Map</div>
|
||||
<div class="right">
|
||||
<a class="link" onclick="reloadMap()">
|
||||
<i class="material-icons">refresh</i>
|
||||
{{#if show_help}}
|
||||
<a class="link" href="/help/map">
|
||||
<i class="icon material-icons">help</i>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,13 +12,13 @@
|
||||
<i class="icon icon-back"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="title">Settings</div>
|
||||
<div class="title">{{page_title}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="page-content">
|
||||
<div class="list media-list no-hairlines tablet-inset" style="margin-top: 0;">
|
||||
<div class="list media-list no-hairlines no-margin-top tablet-inset">
|
||||
<ul>
|
||||
{{#each settings}}
|
||||
<li>
|
||||
|
@ -19,6 +19,14 @@
|
||||
<div class="page-content">
|
||||
<div class="list no-hairlines tablet-inset" style="margin-top: 0;">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/toolbox/scanner" class="item-link item-content">
|
||||
<div class="item-media"><i class="icon fas fa-barcode"></i></div>
|
||||
<div class="item-inner">
|
||||
<div class="item-title">Broken Scanner</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/toolbox/track" class="item-link item-content">
|
||||
<div class="item-media"><i class="icon fas fa-search-location"></i></div>
|
||||
@ -35,14 +43,14 @@
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<!--<li>
|
||||
<a href="/toolbox/scanner" class="item-link item-content">
|
||||
<div class="item-media"><i class="icon fas fa-barcode"></i></div>
|
||||
<li>
|
||||
<a href="/toolbox/sharelist" class="item-link item-content">
|
||||
<div class="item-media"><i class="icon fas fa-share-alt"></i></div>
|
||||
<div class="item-inner">
|
||||
<div class="item-title">Scan for Delivery</div>
|
||||
<div class="item-title">Share Item List</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>-->
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
50
www/pages/toolbox/scanner.html
Normal file
50
www/pages/toolbox/scanner.html
Normal file
@ -0,0 +1,50 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<div class="page">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="left">
|
||||
<a href="#" class="link icon-only back">
|
||||
<i class="icon icon-back"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="title">Broken Scanner</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
<div class="list no-hairlines tablet-inset" style="margin-top: 0;">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/toolbox/scanner/scanner" class="item-link item-content">
|
||||
<div class="item-media">1</div>
|
||||
<div class="item-inner">
|
||||
<div class="item-title">Scan Barcode</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/toolbox/scanner/entries" class="item-link item-content">
|
||||
<div class="item-media">2</div>
|
||||
<div class="item-inner">
|
||||
<div class="item-title">Review Entries</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="block text-align-center">
|
||||
<i class="material-icons material-icons-24px">info</i>
|
||||
<br />
|
||||
Scan barcodes while your postal scanner is crashed or restarting.
|
||||
When the scanner is working again, you can scan all the saved
|
||||
barcodes from your phone screen using the scanner's Manual Input or
|
||||
Scan Barcode feature.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
60
www/pages/toolbox/scanner/entries.html
Normal file
60
www/pages/toolbox/scanner/entries.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<div class="page" data-name="scanner">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="left">
|
||||
<a href="#" class="link icon-only back">
|
||||
<i class="icon icon-back"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="title">Review Entries</div>
|
||||
<div class="right">
|
||||
<a class="link text-color-red" onclick="confirmDeleteScanEntries()">
|
||||
<i class="icon material-icons">delete</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
{{#if entries}}
|
||||
<div class="list media-list no-margin-top no-hairlines">
|
||||
<ul>
|
||||
{{#each entries}}
|
||||
<li style="padding-top: 2rem; padding-bottom: 2rem;">
|
||||
<div class="item-content">
|
||||
<div class="item-inner">
|
||||
<div style="background-color: white; display: flex; justify-content: center; padding-left: 1rem; padding-right: 1rem;">
|
||||
<svg class="barcode_entry" id="barcode_{{code}}" data-barcode="{{code}}"></svg>
|
||||
</div>
|
||||
<div class="item-text text-align-center">{{event}}</div>
|
||||
<div class="item-text text-align-center">{{date}}</div>
|
||||
{{#if form3849}}
|
||||
<h2 class="item-text text-align-center">Form 3849:</h2>
|
||||
<div style="background-color: white; display: flex; justify-content: center; padding-left: 1rem; padding-right: 1rem;">
|
||||
<svg class="barcode_entry" id="barcode_{{form3849}}" data-barcode="{{form3849}}"></svg>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="block text-align-center">
|
||||
<img style="width: 60%; max-width: 300px; max-height: 40vh;" src="assets/images/barcode-dashed.svg" class="margin-vertical" />
|
||||
<h2 class="margin-top">
|
||||
No scan entries.
|
||||
</h2>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<script src="assets/js/toolbox_scannerentries.js"></script>
|
||||
</div>
|
107
www/pages/toolbox/scanner/scanner.html
Normal file
107
www/pages/toolbox/scanner/scanner.html
Normal file
@ -0,0 +1,107 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<div class="page" data-name="scanner">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="left">
|
||||
<a href="#" class="link icon-only back">
|
||||
<i class="icon icon-back"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="title">Scan Barcode</div>
|
||||
<div class="subnavbar" style="background-color: var(--f7-searchbar-bg-color,var(--f7-bars-bg-color));">
|
||||
<div class="subnavbar-inner">
|
||||
<div class="searchbar">
|
||||
<div class="searchbar-inner">
|
||||
<div class="searchbar-input-wrap">
|
||||
<input type="text" id="brokenscannerinput" placeholder="Enter Code" autocomplete="off" autocorrect="off" autocapitalize="off" style="padding-left: 1em; padding-right: 1em;" />
|
||||
</div>
|
||||
<a id="brokenscannercodeadd" onclick="brokenScannerAddTextEntry()" style="padding-right: 0.5em; padding-top: 0.3em;">
|
||||
<i class="material-icons">keyboard_return</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fab fab-extended fab-left-bottom">
|
||||
<a href="#" onclick="brokenScannerEsc()">
|
||||
<div class="fab-text">ESC</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="fab fab-extended fab-center-bottom">
|
||||
<a href="#" onclick="brokenScannerScan()">
|
||||
<div class="fab-text">Scan</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="fab fab-extended fab-right-bottom">
|
||||
<a href="#" onclick="chooseScanEvent()">
|
||||
<div class="fab-text">Enter</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="scanEventPopup" style="background-color: var(--f7-page-bg-color);">
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="title">Select Event</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block no-margin-top padding-bottom" style="height: calc(100% - var(--f7-navbar-height)); overflow-y: auto;">
|
||||
<div class="list tablet-inset no-hairlines no-margin-top">
|
||||
<ul class="eventlist">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fab fab-extended fab-left-bottom">
|
||||
<a href="#" onclick="app.popup.close('#scanEventPopup');">
|
||||
<div class="fab-text">ESC</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="scanEventTypePopup" style="background-color: var(--f7-page-bg-color);">
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="title">Event Type</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block no-margin-top padding-bottom" style="height: calc(100% - var(--f7-navbar-height)); overflow-y: auto;">
|
||||
<div class="list tablet-inset no-hairlines no-margin-top">
|
||||
<ul class="eventlist">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fab fab-extended fab-left-bottom">
|
||||
<a href="#" onclick="app.popup.close('#scanEventTypePopup');">
|
||||
<div class="fab-text">ESC</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
<div class="list no-hairlines tablet-inset">
|
||||
<ul id="codelist">
|
||||
</ul>
|
||||
</div>
|
||||
<div style="height: 3rem;"></div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/toolbox_scanner.js"></script>
|
||||
|
||||
</div>
|
68
www/pages/toolbox/sharelist.html
Normal file
68
www/pages/toolbox/sharelist.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<div class="page" data-name="sharelist">
|
||||
|
||||
<div class="navbar">
|
||||
<div class="navbar-bg"></div>
|
||||
<div class="navbar-inner">
|
||||
<div class="left">
|
||||
<a href="#" class="link icon-only back">
|
||||
<i class="icon icon-back"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="title">Share Item List</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
<div class="list media-list no-hairlines tablet-inset no-margin-top">
|
||||
<ul>
|
||||
<li class="item-divider">Send List</li>
|
||||
<li>
|
||||
<div class="item-content">
|
||||
<a class="button button-fill" id="sendlistbtn" onclick="uploadList();"><i class="fas fa-upload"></i> Upload List</a>
|
||||
</div>
|
||||
</li>
|
||||
<li style="display: none;" id="listidbarcodeli">
|
||||
<div class="item-content" style="background-color: white; display: flex; justify-content: center; padding-left: 1rem; padding-right: 1rem;">
|
||||
<svg class="barcode" id="listidbarcode"></svg>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
<li class="item-divider">Receive List</li>
|
||||
<li>
|
||||
<div class="item-content">
|
||||
<div class="item-inner">
|
||||
<div class="item-title item-label">List ID</div>
|
||||
<div class="item-input-wrap">
|
||||
<input type="text" id="getlistidbox" placeholder="" autocomplete="off" autocorrect="off" autocapitalize="off" />
|
||||
<span class="input-clear-button"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item-content">
|
||||
<a class="button button-fill" onclick="downloadItemList();"><i class="fas fa-download"></i> Download List</a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="item-content">
|
||||
<a class="button button-fill" id="scanlistbarcodebtn" onclick="scanListIDBarcode();"><i class="fas fa-barcode"></i> Scan List Barcode</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="block text-align-center">
|
||||
<i class="material-icons material-icons-24px">info</i>
|
||||
<br />
|
||||
Share your delivery list to another device. The sender uploads the list,
|
||||
and the receiver(s) either scan the barcode on the sender's device, or
|
||||
type in the code beneath the barcode.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/toolbox_sharelist.js"></script>
|
||||
</div>
|
@ -40,9 +40,32 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<div class="block text-align-center">
|
||||
<i class="material-icons material-icons-24px">info</i>
|
||||
<br />
|
||||
Compatible with USPS, UPS, FedEx, and DHL tracking codes.
|
||||
Can extract full delivery point address (and sometimes customer phone number)
|
||||
from 2D FedEx and UPS Mail Innovations barcodes.
|
||||
</div>
|
||||
|
||||
{{#if trackingcodehistory}}
|
||||
<div class="list no-hairlines tablet-inset">
|
||||
<ul>
|
||||
<li class="item-divider">
|
||||
History
|
||||
</li>
|
||||
{{#each trackingcodehistory}}
|
||||
<li>
|
||||
<div class="item-link item-content" onclick="openTrackingHistory('{{this}}')">
|
||||
<div class="item-inner">
|
||||
<div class="item-title">{{this}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<script src="assets/js/toolbox_track.js"></script>
|
||||
|
@ -52,12 +52,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<div class="item-content" style="background-color: white; display: flex; justify-content: center; padding-left: 1rem; padding-right: 1rem;">
|
||||
<svg class="barcode"
|
||||
jsbarcode-format="code128"
|
||||
jsbarcode-value="{{#if barcode}}{{barcode}}{{else}}{{code}}{{/if}}"
|
||||
jsbarcode-height="40"
|
||||
jsbarcode-width="2">
|
||||
</svg>
|
||||
<svg class="barcode" id="trackingbarcode"></svg>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item-divider">History</li>
|
||||
@ -84,6 +79,11 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
JsBarcode(".barcode").init();
|
||||
JsBarcode("#trackingbarcode", "{{#if barcode}}{{escape barcode}}{{else}}{{escape code}}{{/if}}", {
|
||||
format: "code128",
|
||||
ean128: true,
|
||||
width: 2,
|
||||
height: 40
|
||||
});
|
||||
</script>
|
||||
</div>
|
278
www/routes.js
278
www/routes.js
@ -4,6 +4,10 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
var show_help = function () {
|
||||
return localStorage.getItem("show_help") != "false";
|
||||
}
|
||||
|
||||
var routes = [
|
||||
{
|
||||
path: '/home',
|
||||
@ -27,13 +31,14 @@ var routes = [
|
||||
},
|
||||
{
|
||||
path: '/manage',
|
||||
name: 'manage',
|
||||
templateUrl: './pages/manage.html',
|
||||
options: {
|
||||
context: {
|
||||
show_help: show_help,
|
||||
itemtypes: SETTINGS.itemtypes
|
||||
}
|
||||
},
|
||||
name: 'manage',
|
||||
on: {
|
||||
pageAfterIn: function () {
|
||||
app.autocomplete.create({
|
||||
@ -56,8 +61,13 @@ var routes = [
|
||||
},
|
||||
{
|
||||
path: '/list',
|
||||
templateUrl: './pages/list.html',
|
||||
name: 'list',
|
||||
templateUrl: './pages/list.html',
|
||||
options: {
|
||||
context: {
|
||||
show_help: show_help
|
||||
}
|
||||
},
|
||||
on: {
|
||||
pageAfterIn: function () {
|
||||
loadPackageList();
|
||||
@ -74,14 +84,17 @@ var routes = [
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/map',
|
||||
url: './pages/map.html',
|
||||
templateUrl: './pages/map.html',
|
||||
name: 'map',
|
||||
keepAlive: true,
|
||||
options: {
|
||||
context: {
|
||||
show_help: show_help
|
||||
}
|
||||
},
|
||||
on: {
|
||||
pageAfterIn: function () {
|
||||
reloadMap();
|
||||
@ -91,15 +104,83 @@ var routes = [
|
||||
{
|
||||
path: '/toolbox',
|
||||
url: './pages/toolbox.html',
|
||||
name: 'toolbox'
|
||||
name: 'toolbox',
|
||||
routes: [
|
||||
{
|
||||
path: '/scanner',
|
||||
templateUrl: './pages/toolbox/scanner.html',
|
||||
routes: [
|
||||
{
|
||||
path: '/scanner',
|
||||
templateUrl: './pages/toolbox/scanner/scanner.html',
|
||||
name: 'scanner'
|
||||
},
|
||||
{
|
||||
path: '/toolbox/track',
|
||||
url: './pages/toolbox/track.html',
|
||||
name: 'track'
|
||||
path: '/entries',
|
||||
name: 'entries',
|
||||
async: function (routeTo, routeFrom, resolve, reject) {
|
||||
if (localStorage.getItem("scanevents") != null && localStorage.getItem("scanevents") != "[]") {
|
||||
var entries = JSON.parse(localStorage.getItem("scanevents"));
|
||||
|
||||
for (i in entries) {
|
||||
entries[i].event = entries[i].event.join(' <i class="fas fa-chevron-right"></i> ');
|
||||
}
|
||||
} else {
|
||||
var entries = false;
|
||||
}
|
||||
|
||||
resolve({
|
||||
templateUrl: './pages/toolbox/scanner/entries.html'
|
||||
}, {
|
||||
context: {
|
||||
entries: entries
|
||||
}
|
||||
});
|
||||
},
|
||||
on: {
|
||||
pageAfterIn: function () {
|
||||
$(".barcode_entry").each(function () {
|
||||
var code = $(this).data("barcode");
|
||||
JsBarcode("#barcode_" + code, code, {
|
||||
format: "code128",
|
||||
ean128: true,
|
||||
width: 2,
|
||||
height: 40
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/toolbox/weather',
|
||||
path: '/track',
|
||||
name: 'track',
|
||||
async: function (routeTo, routeFrom, resolve, reject) {
|
||||
var history = localStorage.getItem("trackingcodehistory");
|
||||
if (history == null) {
|
||||
history = false;
|
||||
} else {
|
||||
history = JSON.parse(history).reverse(); // Most recent on top
|
||||
}
|
||||
resolve({
|
||||
templateUrl: './pages/toolbox/track.html'
|
||||
}, {
|
||||
context: {
|
||||
trackingcodehistory: history
|
||||
}
|
||||
});
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
path: '/info',
|
||||
templateUrl: './pages/toolbox/trackinginfo.html',
|
||||
name: 'trackinginfo'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/weather',
|
||||
url: './pages/toolbox/weather.html',
|
||||
name: 'weather',
|
||||
on: {
|
||||
@ -109,9 +190,28 @@ var routes = [
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/toolbox/track/info',
|
||||
templateUrl: './pages/toolbox/trackinginfo.html',
|
||||
name: 'trackinginfo'
|
||||
path: '/sharelist',
|
||||
url: './pages/toolbox/sharelist.html',
|
||||
name: 'sharelist'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/help',
|
||||
routes: [
|
||||
{
|
||||
path: '/list',
|
||||
panel: {
|
||||
url: './pages/help/list.html'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/map',
|
||||
panel: {
|
||||
url: './pages/help/map.html'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/credits',
|
||||
@ -122,17 +222,6 @@ var routes = [
|
||||
path: '/settings',
|
||||
name: 'settings',
|
||||
async: function (routeTo, routeFrom, resolve, reject) {
|
||||
var mapstyles = [];
|
||||
for (var id in SETTINGS.maptileurls) {
|
||||
if (SETTINGS.maptileurls.hasOwnProperty(id)) {
|
||||
mapstyles.push({
|
||||
value: id,
|
||||
label: SETTINGS.maptileurls[id].name,
|
||||
selected: localStorage.getItem("mapsource") == id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var settings = [
|
||||
{
|
||||
setting: "alerts",
|
||||
@ -140,6 +229,13 @@ var routes = [
|
||||
text: "Change the alert sound, volume, and distance.",
|
||||
onclick: "router.navigate('/settings/alerts')",
|
||||
link: true
|
||||
},
|
||||
{
|
||||
setting: "maps",
|
||||
title: "Map and Navigation",
|
||||
text: "Change map settings and units.",
|
||||
onclick: "router.navigate('/settings/maps')",
|
||||
link: true
|
||||
}
|
||||
];
|
||||
|
||||
@ -164,33 +260,17 @@ var routes = [
|
||||
onclick: ""
|
||||
},
|
||||
{
|
||||
setting: "units",
|
||||
title: "Measurement units",
|
||||
select: true,
|
||||
options: [
|
||||
{
|
||||
value: "metric",
|
||||
label: "Meters/Kilometers",
|
||||
selected: localStorage.getItem("units") == "metric"
|
||||
},
|
||||
{
|
||||
value: "imperial",
|
||||
label: "Feet/Miles",
|
||||
selected: localStorage.getItem("units") == "imperial"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
setting: "mapsource",
|
||||
title: "Map style",
|
||||
select: true,
|
||||
options: mapstyles,
|
||||
text: "Choose which map style to use."
|
||||
setting: "showhelp",
|
||||
title: "Show help",
|
||||
text: "Show the <span class=material-icons-intext><i class=material-icons>help</i></span> icons",
|
||||
toggle: true,
|
||||
checked: localStorage.getItem("show_help") != "false",
|
||||
onclick: ""
|
||||
},
|
||||
{
|
||||
setting: "versions",
|
||||
title: "PackageHelper app v" + app_version,
|
||||
text: "Copyright © 2019 Netsyms Technologies. Licensed under the Mozilla Public License 2.0.",
|
||||
text: "Copyright © 2019-2020 Netsyms Technologies. Licensed under the Mozilla Public License 2.0.",
|
||||
onclick: ""
|
||||
},
|
||||
{
|
||||
@ -204,7 +284,7 @@ var routes = [
|
||||
setting: "privacy",
|
||||
title: "Privacy policy and legal",
|
||||
text: "",
|
||||
onclick: "openBrowser('https://netsyms.com/legal?pk_campaign=PackageHelpterApp')",
|
||||
onclick: "openBrowser('https://netsyms.com/legal?pk_campaign=PackageHelperApp')",
|
||||
link: true
|
||||
});
|
||||
|
||||
@ -212,14 +292,15 @@ var routes = [
|
||||
templateUrl: './pages/settings.html'
|
||||
}, {
|
||||
context: {
|
||||
page_title: "Settings",
|
||||
settings: settings
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
path: '/settings/alerts',
|
||||
name: 'alertsettings',
|
||||
path: '/alerts',
|
||||
name: 'settings',
|
||||
async: function (routeTo, routeFrom, resolve, reject) {
|
||||
var alertsounds = [];
|
||||
for (var id in SETTINGS.alertsounds) {
|
||||
@ -232,7 +313,8 @@ var routes = [
|
||||
}
|
||||
}
|
||||
|
||||
var settings = [{
|
||||
var settings = [
|
||||
{
|
||||
setting: "alertsound",
|
||||
title: "Alert sound",
|
||||
text: "Select which sound to play when a package is nearby.",
|
||||
@ -265,15 +347,101 @@ var routes = [
|
||||
step: 15,
|
||||
value: localStorage.getItem("alertinterval") == null ? 30 : localStorage.getItem("alertinterval"),
|
||||
slider: true
|
||||
}];
|
||||
}
|
||||
];
|
||||
|
||||
resolve({
|
||||
templateUrl: './pages/alertsettings.html'
|
||||
templateUrl: './pages/settings.html'
|
||||
}, {
|
||||
context: {
|
||||
page_title: "Alert Settings",
|
||||
settings: settings
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/maps',
|
||||
name: 'settings',
|
||||
async: function (routeTo, routeFrom, resolve, reject) {
|
||||
var mapstyles = [];
|
||||
for (var id in SETTINGS.maptileurls) {
|
||||
if (SETTINGS.maptileurls.hasOwnProperty(id)) {
|
||||
mapstyles.push({
|
||||
value: id,
|
||||
label: SETTINGS.maptileurls[id].name,
|
||||
selected: localStorage.getItem("mapsource") == id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var settings = [
|
||||
{
|
||||
setting: "mapsource",
|
||||
title: "Map style",
|
||||
select: true,
|
||||
options: mapstyles,
|
||||
text: "Choose which map style to use."
|
||||
},
|
||||
{
|
||||
setting: "units",
|
||||
title: "Measurement units",
|
||||
select: true,
|
||||
options: [
|
||||
{
|
||||
value: "metric",
|
||||
label: "Meters/Kilometers",
|
||||
selected: localStorage.getItem("units") == "metric"
|
||||
},
|
||||
{
|
||||
value: "imperial",
|
||||
label: "Feet/Miles",
|
||||
selected: localStorage.getItem("units") == "imperial"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
setting: "trackzoom",
|
||||
title: "Zoom when tracking location",
|
||||
select: true,
|
||||
options: [
|
||||
{
|
||||
value: 15,
|
||||
label: "Low",
|
||||
selected: localStorage.getItem("trackzoom") == 15
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
label: "Normal",
|
||||
selected: localStorage.getItem("trackzoom") == null || localStorage.getItem("trackzoom") == 16
|
||||
},
|
||||
{
|
||||
value: 17,
|
||||
label: "High",
|
||||
selected: localStorage.getItem("trackzoom") == 17
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
setting: "maptype",
|
||||
title: "Alternative map",
|
||||
text: "Turn this on if you have problems with the map.",
|
||||
toggle: true,
|
||||
checked: localStorage.getItem("maptype") == "leaflet",
|
||||
onclick: ""
|
||||
}
|
||||
];
|
||||
|
||||
resolve({
|
||||
templateUrl: './pages/settings.html'
|
||||
}, {
|
||||
context: {
|
||||
page_title: "Map Settings",
|
||||
settings: settings
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
215
www/settings.js
215
www/settings.js
@ -8,18 +8,27 @@ var SETTINGS = {
|
||||
maptileurls: {
|
||||
liberty: {
|
||||
url: "https://maps.netsyms.net/styles/osm-liberty/{z}/{x}/{y}.png",
|
||||
json: "https://maps.netsyms.net/styles/osm-liberty/style.json",
|
||||
name: "Liberty",
|
||||
bgcolor: "#EFEFEF"
|
||||
},
|
||||
terrain: {
|
||||
url: "https://maps.netsyms.net/styles/klokantech-terrain/{z}/{x}/{y}.png",
|
||||
json: "https://maps.netsyms.net/styles/klokantech-terrain/style.json",
|
||||
name: "Terrain",
|
||||
bgcolor: "#EDF5F3"
|
||||
},
|
||||
fiord: {
|
||||
url: "https://maps.netsyms.net/styles/fiord-color/{z}/{x}/{y}.png",
|
||||
json: "https://maps.netsyms.net/styles/fiord-color/style.json",
|
||||
name: "Dark Fiord",
|
||||
bgcolor: "#45516E"
|
||||
},
|
||||
oledblack: {
|
||||
url: "https://maps.netsyms.net/styles/oled-black/{z}/{x}/{y}.png",
|
||||
json: "https://maps.netsyms.net/styles/oled-black/style.json",
|
||||
name: "OLED Black",
|
||||
bgcolor: "#000000"
|
||||
}
|
||||
},
|
||||
alertsounds: {
|
||||
@ -72,14 +81,14 @@ var SETTINGS = {
|
||||
},
|
||||
signature: {
|
||||
id: "signature",
|
||||
name: "Signature",
|
||||
name: "Signature Item",
|
||||
icon: "fas fa-file-signature fa-fw",
|
||||
mapicon: "signature",
|
||||
pluralmapicon: "signatures"
|
||||
},
|
||||
express: {
|
||||
id: "express",
|
||||
name: "Express",
|
||||
name: "Express Item",
|
||||
icon: "fas fa-shipping-fast fa-fw",
|
||||
mapicon: "express",
|
||||
pluralmapicon: "multiple-items"
|
||||
@ -94,8 +103,208 @@ var SETTINGS = {
|
||||
"windy",
|
||||
"none"
|
||||
],
|
||||
scannerevents: [
|
||||
{
|
||||
button: 1,
|
||||
title: "Delivered",
|
||||
type: "event",
|
||||
after: [
|
||||
{
|
||||
button: 1,
|
||||
title: "In/At Mailbox",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 2,
|
||||
title: "Front Door/Porch",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 3,
|
||||
title: "Left with Individual at Address",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 4,
|
||||
title: "Front Desk/Reception/Mail Room",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 5,
|
||||
title: "Parcel Locker",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 6,
|
||||
title: "Garage or Other Location at Address",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 7,
|
||||
title: "Left with Neighbor",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 'G',
|
||||
title: "Authorized Agent",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 'U',
|
||||
title: "Tendered to Authorized Agent",
|
||||
type: "type",
|
||||
after: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
button: 2,
|
||||
title: "Attempted",
|
||||
type: "event",
|
||||
after: [
|
||||
{
|
||||
button: 2,
|
||||
title: "No Secure Location Available",
|
||||
type: "type",
|
||||
after: "3849"
|
||||
},
|
||||
{
|
||||
button: 3,
|
||||
title: "No Access or Business Closed",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 4,
|
||||
title: "Receptacle Full/Item Oversized",
|
||||
type: "type",
|
||||
after: "3849"
|
||||
},
|
||||
{
|
||||
button: 5,
|
||||
title: "Customer Hold",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 6,
|
||||
title: "Animal Interference",
|
||||
type: "type",
|
||||
after: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
button: 3,
|
||||
title: "Return to Sender or Forward",
|
||||
type: "event",
|
||||
after: [
|
||||
{
|
||||
button: 1,
|
||||
title: "Forwarded",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 2,
|
||||
title: "Insufficient Address",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 3,
|
||||
title: "No Such Number",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 4,
|
||||
title: "Addressee Unknown",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 5,
|
||||
title: "Vacant",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 6,
|
||||
title: "Unable to Forward / Forward Order Expired",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 7,
|
||||
title: "Deceased",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 8,
|
||||
title: "Refused",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 9,
|
||||
title: "Returned for Other Reason",
|
||||
type: "type",
|
||||
after: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
button: 4,
|
||||
title: "Other",
|
||||
type: "event",
|
||||
after: [
|
||||
{
|
||||
button: 'X',
|
||||
title: "Dispatch to Military/Diplomatic PO",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 1,
|
||||
title: "Return to Post Office Not Attempted / Delivery Delay",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 2,
|
||||
title: "Local Weather Delay",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 3,
|
||||
title: "Visible Damage",
|
||||
type: "type",
|
||||
after: false
|
||||
},
|
||||
{
|
||||
button: 4,
|
||||
title: "Out for Delivery",
|
||||
type: "type",
|
||||
after: false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
geocodecacheexpiry: 604800, // One week
|
||||
geocodeapi: "https://apis.netsyms.net/packagehelper/geocode.php",
|
||||
trackingapi: "https://apis.netsyms.net/packagehelper/track.php",
|
||||
weatherapi: "https://apis.netsyms.net/packagehelper/weather.php",
|
||||
geoipapi: "https://apis.netsyms.net/packagehelper/geoip.php"
|
||||
geoipapi: "https://apis.netsyms.net/packagehelper/geoip.php",
|
||||
sharelistapi: "https://apis.netsyms.net/packagehelper/sharepackagelist.php"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user