Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
cacheflowe committed Aug 13, 2024
2 parents 710ab5e + a2aef76 commit e51e761
Show file tree
Hide file tree
Showing 19 changed files with 19,877 additions and 61 deletions.
1 change: 1 addition & 0 deletions demo/demo-mobile-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class MobileUtilDemo extends DemoBase {
MobileUtil.enablePseudoStyles();
MobileUtil.addFullscreenListener();
MobileUtil.addFullscreenEl(document.getElementById("fullscreen"), true);
MobileUtil.addDevPanel();
}

initButtons() {
Expand Down
50 changes: 35 additions & 15 deletions demo/demo-serial-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ class SerialDeviceDemo extends DemoBase {
}

async init() {
this.initSerialWithButton();
this.sendOnClick();
// this.sendOnClick();
this.initSlider();
// EITHER init serial with button or auto-init with index
// this.initSerialWithButton();
this.initSerial(0);
}

initSerialWithButton() {
Expand All @@ -26,23 +29,40 @@ class SerialDeviceDemo extends DemoBase {
// click to init serial device selector
this.startButton.addEventListener("click", (e) => {
this.startButton.parentNode.removeChild(this.startButton);
// init serial device on user interaction
this.serialDevice = new SerialDevice(
115200,
(data) => this.serialRead(data),
(err) => this.serialError(err)
);
this.initSerial();
});
}

initSerial(autoInitIndex = null) {
this.serialDevice = new SerialDevice(
115200,
(data) => this.serialRead(data),
(err) => this.serialError(err),
autoInitIndex
);
}

sendOnClick() {
document.addEventListener("click", (e) => {
if (!!this.serialDevice && this.serialDevice.initialized) {
// test write method
// this.serialDevice.writeDataArray([Math.round(Math.random() * 100)]);
this.serialDevice.writeString(
"a" + Math.round(100 + Math.random() * 300)
);
this.serialDevice.writeString("n" + Math.round(Math.random() * 20));
}
});
}

initSlider() {
// add slider to send data
this.slider = document.createElement("input");
this.slider.type = "range";
this.slider.min = 0;
this.slider.max = 30;
this.slider.value = 0;
this.el.appendChild(this.slider);

// send data on slider change
this.slider.addEventListener("input", (e) => {
if (!!this.serialDevice && this.serialDevice.initialized) {
this.serialDevice.writeString("n" + parseInt(this.slider.value));
}
});
}
Expand All @@ -54,10 +74,10 @@ class SerialDeviceDemo extends DemoBase {
} else if (parseInt(data) > 40) {
this.el.innerHTML = `<p>Distance: ${data}mm</p>`;
} else {
this.debugEl.innerHTML = `<p>Error: ${data}</p>`;
this.debugEl.innerHTML = `<p>Info: ${data}</p>`;
}
} else {
this.debugEl.innerHTML = `<p>Error: ${data}</p>`;
this.debugEl.innerHTML = `<p>Info: ${data}</p>`;
}
}

Expand Down
26 changes: 17 additions & 9 deletions demo/demo-video-download.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class VideoDownloadDemo extends DemoBase {
[],
"Video Download",
"video-download-container",
"Save a video file directly to the camera roll on iOS via the Web Share API. Needs user interaction and https to work! Android and desktop browsers properly respect the <code>download</code> attribute and don't need the Web Share API."
`Save a video file directly to the camera roll on iOS via the Web Share API. Needs user interaction and https to work! Android and desktop browsers properly respect the <code>download</code> attribute and don't need the Web Share API. See <a href="https://macarthur.me/posts/trigger-cross-origin-download/">this article</a> if the file is hosted on another origin and the attribute doesnt work.`
);
}

Expand Down Expand Up @@ -62,23 +62,24 @@ class VideoDownloadDemo extends DemoBase {
linkEl.setAttribute("href", imagePath);
linkEl.setAttribute("download", "bb.jpg");
linkEl.style.setProperty("display", "block");

this.el.appendChild(linkEl);

if (MobileUtil.isIOS()) {
linkEl.innerText =
"Tap & Hold Image to Save - it's the only way to get an image to the iOS photo roll";
}

linkEl.addEventListener("click", (e) => {
if (MobileUtil.isIOS()) {
e.preventDefault();
// maybe someday this will work:
// this.shareFile(imagePath, "image/jpeg", "bb.jpg");
this.shareFile(imagePath, "image/jpeg", "bb.jpg");
} else {
// do nothing - use default browser behavior
}
});

// add another basic download link
let link2 = document.createElement("a");
link2.innerText = "Download image (no Share API override for iOS)";
link2.setAttribute("href", imagePath);
link2.setAttribute("download", "bb.jpg");
link2.style.setProperty("display", "block");
this.el.appendChild(link2);
}

// if (
Expand All @@ -99,6 +100,13 @@ class VideoDownloadDemo extends DemoBase {
files: filesArray,
};
navigator.share(shareData);

// testing with a single file, but the image path doesn't give you a "save image" button... this is why we load a blob
// navigator.share({
// title: "image test",
// text: "yay",
// url: filePath,
// });
}
}

Expand Down
File renamed without changes.
94 changes: 94 additions & 0 deletions server/http-server.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//////////////////////////////////////
// Basic node api server
// - From: https://www.digitalocean.com/community/tutorials/how-to-create-a-web-server-in-node-js-with-the-http-module
// Use nodemon to automatically restart the server when changes are made
// Usage: `nodemon node src/nodejs/backend.js`
//////////////////////////////////////

import http from "http";
import { promises as fs } from "fs";
import { fileURLToPath } from "url";
import { dirname } from "path";

const host = "localhost";
const port = 8000;

// handle incoming requests -------------------

const requestListener = function (req, res) {
// Set CORS headers
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"X-Requested-With,content-type"
);

// grab path and parse path components
const { url } = req;
const path = url.split("/").filter((p) => p && p.length > 0);
console.log(path);
// handle different paths
if (url === "/") {
handleHomeRoute(res);
} else if (path[0] == "html") {
handleHtml(res);
} else if (path[0] == "current") {
handleCurrentMessage(res);
} else {
handleNotFoundRoute(res);
}
};

const handleHomeRoute = (res) => {
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.end("Hello! This is the home route.");
};

const handleHtml = (res) => {
res.setHeader("Content-Type", "text/html");
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
fs.readFile(__dirname + "/index.html").then((contents) => {
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.end(contents);
});
};

const handleCurrentMessage = async (res) => {
try {
const response = await fetch("https://some.api/endpoint", {
body: JSON.stringify({ test: "data" }),
headers: { "Content-Type": "application/json" },
method: "POST",
});
if (!response.ok) {
res.writeHead(500);
res.end({ error: error.message });
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.text();
res.setHeader("Content-Type", "application/json");
res.writeHead(200);
res.end(data);
} catch (error) {
console.error("Fetch failed:", error);
res.writeHead(500);
res.end("Error fetching data from fake API");
}
};

const handleNotFoundRoute = (res) => {
res.setHeader("Content-Type", "text/html");
res.writeHead(404);
res.end("404 Not Found");
};

// start server --------------------------------

const server = http.createServer(requestListener);
server.listen(port, host, () => {
console.log(`Server is on http://${host}:${port}`);
});
17 changes: 17 additions & 0 deletions server/run-shell-script.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { exec, spawn } from "node:child_process";

exec("cmd.exe /c dir", (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});

exec("kill-java.cmd", (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});
4 changes: 4 additions & 0 deletions server/windows-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { activeWindow, openWindows } from "get-windows";

console.log(await activeWindow({}));
console.log(await openWindows({}));
56 changes: 56 additions & 0 deletions src/components/app-state-distributed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import AppStoreDistributed from "../app-store-distributed.js";

// self-registering child components
import "./websocket-indicator.js";
import "./app-store-debug.js";

class AppStateDistributed extends HTMLElement {
connectedCallback() {
this.shadow = this.attachShadow({ mode: "open" });
this.initSharedState();
this.addChildren();
// if (this.isDebug()) this.storeDebug.show();
}

initSharedState() {
// connect to websocket server
this.webSocketHost = "ws://" + document.location.hostname + ":3001/ws";
this.appStore = new AppStoreDistributed(this.webSocketHost);

// listen for data/events
_store.addListener(this);
_store.addListener(this, "AppStoreDistributed_CONNECTED"); // emitted by AppStoreDistributed when connected
}

isDebug() {
return this.hasAttribute("debug");
}

addChildren() {
this.shadow.innerHTML = this.isDebug()
? /*html*/ `
<websocket-indicator></websocket-indicator>
<app-store-debug></app-store-debug>
`
: /*html*/ `
<app-store-debug></app-store-debug>
`;
this.storeDebug = this.shadow.querySelector("app-store-debug");
}

// AppStore listeners

AppStoreDistributed_CONNECTED(val) {
_store.set("CLIENT_CONNECTED", true, true); // let desktop app know that we're here
}

storeUpdated(key, val) {}

static register() {
customElements.define("app-state-distributed", AppStateDistributed);
}
}

AppStateDistributed.register();

export default AppStateDistributed;
53 changes: 53 additions & 0 deletions src/components/app-store-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import MobileUtil from "../mobile-util.js";
import AppStoreElement from "./app-store-element.js";

class AppStoreButton extends AppStoreElement {
storeUpdated(key, value) {
if (key != this.storeKey) return;
// disable button if clicked
if (value == this.storeValue) this.button.setAttribute("disabled", true);
else this.button.removeAttribute("disabled");
}

clickEvent() {
return MobileUtil.isMobileBrowser() ? "touchstart" : "click";
}

initStoreListener() {
this.button = this.el.querySelector("button");
this.button.addEventListener(this.clickEvent(), (e) => {
if (!this.storeKey) return;
// if the storeValue is "true" or "false", send the boolean instead of the string
const value =
this.storeValue == "true"
? true
: this.storeValue == "false"
? false
: this.storeValue;
_store.set(this.storeKey, value, true);
});

super.initStoreListener();
}

css() {
return /*css*/ `
`;
}

html() {
return /*html*/ `
<button>
${this.initialHTML}
</button>
`;
}

static register() {
customElements.define("app-store-button", AppStoreButton);
}
}

AppStoreButton.register();

export default AppStoreButton;
Loading

0 comments on commit e51e761

Please sign in to comment.