Compare commits

..

10 Commits

Author SHA1 Message Date
Harry Stuart
ad53ce97ff Cleaned repo 2022-12-07 20:01:54 +11:00
Harry Stuart
ca7cef992a Merge branch 'master' of github.com:HStuart18/SiteFalconIOWidget 2022-12-07 20:01:31 +11:00
Harry Stuart
00d1cdfc86
Create README.md 2022-12-07 20:00:11 +11:00
Harry Stuart
ce236254d2 fixed z index 2022-12-03 11:34:39 +11:00
Harry Stuart
f3797e0f5f added clear form 2022-12-02 23:57:35 +11:00
Harry Stuart
b3f35d1a81 added snapshot utilities 2022-12-02 23:40:27 +11:00
Harry Stuart
4c4372833e Add snapshot capability 2022-12-02 00:44:55 +11:00
Harry Stuart
60b0b785fc Begin add snapshot 2022-11-30 20:56:37 +11:00
Harry Stuart
78acccd0ac added close button 2022-11-29 22:02:38 +11:00
Harry Stuart
abd8c2536a Slide in complete 2022-11-28 21:32:06 +11:00
9 changed files with 684 additions and 1380 deletions

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# SiteFalconIOWidget
Site Falcon IO was a business ideas that I decided to make open source. It comprises a Web Component widget developed using raw HTML, JS and CSS. This repository is still in testing and not yet publicised.
The widget is a simple web component that can be embedded into any website and allows users to provide feedback by interacting with it. The feedback can also include screenshots of the website. This has proven to be the most challenging component of the project due to cross-origin content. The W3C spec that most browsers implement prohibits the downloading of content originating outside the origin of the current site-hosting server. Thus, any images on a website that are served from a different origin will taint any HTML canvases that are painted with their content. The work-around is to either use a proxy-server or the `getDisplayMedia` JS API. The latter requires asking for user permission each invocation which is sub-optimal. In summary, this project is still ongoing.
In its completed form, this widget will save web developers considerable time and hassle when it comes to ascertaining beta/alpha testing feedback from users because such users can provide feedback directly on the site, thus preventing bogged down email chain discussions.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,143 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<style>
p {
font-size: 24;
}
</style>
<div style="height: 50px; width: 10000px; background-color: blue;"></div>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
v
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
</div>
<div id="widget" style="position: fixed; top: 0px; left: 0px; width: 100px; height: 100px; background-color: red;"></div>
<script type="text/javascript">
let widget = document.getElementById("widget");
let isDown = false;
function onMouseDown(e) {
e.preventDefault();
e.stopPropagation();
isDown = true;
this.setPointerCapture(e.pointerId);
}
function setCorner(anchorX, anchorY, element) {
let offsets = element.getBoundingClientRect();
if (anchorX < window.innerWidth / 2){
// left half
if (anchorY < window.innerHeight / 2) {
// top left
element.style.left = "0px";
element.style.top = "0px";
}
else {
// bottom left
element.style.left = "0px";
element.style.top = window.innerHeight - offsets.height + "px";
}
}
else {
// right half
if (anchorY < window.innerHeight / 2) {
// top right
element.style.left = window.innerWidth - offsets.width + "px";4
element.style.top = "0px";
}
else {
// bottom right
element.style.left = window.innerWidth - offsets.width + "px";
element.style.top = window.innerHeight - offsets.height + "px";
}
}
}
function onMouseMove(e) {
e.preventDefault();
e.stopPropagation();
if (isDown) {
setCorner(e.clientX, e.clientY, this);
}
}
function onMouseUp(e) {
e.preventDefault();
e.stopPropagation();
isDown = false;
this.releasePointerCapture(e.pointerId);
}
function onMouseLeave(e) {
e.preventDefault();
e.stopPropagation();
if (isDown) {
}
}
widget.addEventListener("pointerdown", onMouseDown);
widget.addEventListener("pointermove", onMouseMove);
widget.addEventListener("pointerleave", onMouseLeave);
widget.addEventListener("pointerup", onMouseUp);
window.addEventListener("resize", () => {
let offsets = widget.getBoundingClientRect();
setCorner(offsets.left, offsets.top, widget);
});
</script>
</body>
</html>

View File

@ -1,288 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script src=
"https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.5/dist/html2canvas.min.js">
</script>
</head>
<body>
<div>
<style>
p {
font-size: 24;
}
</style>
<img />
<button id="snapshot-button">Take snapshot</button>
<div style="height: 50px; width: 10000px; background-color: blue;"></div>
<!-- <img width="400px" height="700px" src="alley.jpg" /> -->
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
v
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
</div>
<script type="text/javascript">
let canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.style = "position: fixed; top: 0px; left: 0px; cursor: crosshair;";
function setCanvasDimensions(canvas) {
let bodyMarginLeft = window.getComputedStyle(document.body).getPropertyValue('margin-left');
let bodyMarginRight = window.getComputedStyle(document.body).getPropertyValue('margin-right');
if (bodyMarginLeft || bodyMarginRight) {
canvas.width = document.body.offsetWidth + parseInt(bodyMarginLeft) + parseInt(bodyMarginRight);
}
else {
canvas.width = document.body.offsetWidth;
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.hidden = true;
}
setCanvasDimensions(canvas);
window.addEventListener("resize", () => setCanvasDimensions(canvas))
let ctx = canvas.getContext("2d");
let hiddenCanvas = document.createElement("canvas");
document.body.appendChild(hiddenCanvas);
hiddenCanvas.hidden = true;
let hiddenCtx = hiddenCanvas.getContext("2d");
let initialX;
let initialY;
let isDown = false;
function onMouseDown(e) {
e.preventDefault();
e.stopPropagation();
initialX = e.offsetX;
initialY = e.offsetY;
isDown = true;
this.setPointerCapture(e.pointerId);
}
function onMouseMove(e) {
e.preventDefault();
e.stopPropagation();
if (isDown) {
let offsetX;
let offsetY;
if (e.offsetX < 0) {
offsetX = 0;
}
else if (e.offsetX > canvas.width - 1) {
offsetX = canvas.width - 1;
}
else {
offsetX = e.offsetX;
}
if (e.offsetY < 0) {
offsetY = 0;
}
else if (e.offsetY > canvas.height - 1) {
offsetY = canvas.height - 1;
}
else {
offsetY = e.offsetY;
}
let width = offsetX - initialX;
let height = offsetY - initialY;
setCanvas();
ctx.beginPath();
ctx.clearRect(initialX, initialY, width, height);
ctx.rect(initialX, initialY, width, height);
ctx.stroke();
ctx.closePath();
}
}
async function onMouseUp(e) {
e.preventDefault();
e.stopPropagation();
if (isDown) {
let offsetX;
let offsetY;
if (e.offsetX < 0) {
offsetX = 0;
}
else if (e.offsetX > canvas.width - 1) {
offsetX = canvas.width - 1;
}
else {
offsetX = e.offsetX;
}
if (e.offsetY < 0) {
offsetY = 0;
}
else if (e.offsetY > canvas.height - 1) {
offsetY = canvas.height - 1;
}
else {
offsetY = e.offsetY;
}
unloadCanvas();
this.releasePointerCapture(e.pointerId);
if (Math.abs(offsetX - initialX) > 10 && Math.abs(offsetY - initialY) > 10) {
await takeScreenshot(offsetX, offsetY);
}
initialX = null;
initialY = null;
isDown = false;
}
}
function onMouseLeave(e) {
e.preventDefault();
e.stopPropagation();
if (isDown) {
}
}
async function takeScreenshot(offsetX, offsetY) {
let width = offsetX - initialX;
let height = offsetY - initialY;
let offsetInitialX = initialX;
let offsetInitialY = initialY;
if (width < 0) {
width = width * -1;
offsetInitialX = initialX - width;
}
if (height < 0) {
height = height * -1;
offsetInitialY = initialY - height;
}
let documentCanvas;
await html2canvas(document.body, {
logging: true,
letterRendering: 1,
allowTaint: true,
useCORS: true
}).then(
function (canvas) {
console.log("nice")
documentCanvas = canvas;
});
return;
hiddenCanvas.width = width;
hiddenCanvas.height = height;
hiddenCtx.drawImage(documentCanvas, offsetInitialX, offsetInitialY, width, height, 0, 0, width, height);
let base64image = canvas.toDataURL("image/png");
console.log(base64image);
hiddenCtx.clearRect(0, 0, hiddenCanvas.width, hiddenCanvas.height);
hiddenCanvas.width = 0;
hiddenCanvas.height = 0;
}
function setCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalAlpha = 0.5;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fill();
ctx.closePath();
setBrush();
}
function setBrush() {
ctx.globalAlpha = 1;
ctx.strokeStyle = 'red';
}
canvas.addEventListener("pointerdown", onMouseDown);
canvas.addEventListener("pointermove", onMouseMove);
canvas.addEventListener("pointerleave", onMouseLeave);
canvas.addEventListener("pointerup", onMouseUp);
function loadCanvas() {
setCanvas();
canvas.hidden = false;
}
function unloadCanvas() {
setCanvas();
canvas.hidden = true;
}
let snapshotButton = document.getElementById("snapshot-button");
snapshotButton.addEventListener("click", () => { loadCanvas() });
</script>
</body>
</html>

View File

@ -1,27 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script src=
"https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.5/dist/html2canvas.min.js">
</script>
</head>
<body>
<div id="capture" style="padding: 10px; background: #f5da55">
<h4 style="color: #000; ">Hello wytorld!</h4>
<img width="400px" height="700px" src="alley.jpg" />
</div>
<script type="text/javascript">
async function Do() {
await html2canvas(document.body)
.then(
function (canvas) {
document.body.appendChild(canvas);
});
}
Do();
</script>
</body>
</html>

View File

@ -1,197 +0,0 @@
<html>
<head>
</head>
<body>
<div>
<style>
p {
font-size: 24;
}
</style>
<img />
<button id="snapshot-button">Take snapshot</button>
<div style="height: 50px; width: 10000px; background-color: blue;"></div>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
v
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
</div>
<x-widget></x-widget>
<script>
class XWidget extends HTMLElement {
frame;
icon;
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
let frame = document.createElement("div");
frame.style.position = "fixed";
frame.style.top = "0px";
frame.style.left = "0px";
frame.style.right = "0px";
frame.style.bottom = "0px";
frame.style.border = "5px dotted blue";
shadowRoot.append(frame);
this.frame = frame;
let icon = document.createElement("x-widget-icon");
this.frame.appendChild(icon);
this.icon = icon;
}
connectedCallback() {
}
}
class XWidgetIcon extends HTMLElement {
iconContainer;
isPressed;
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
let iconContainer = document.createElement("div");
shadowRoot.append(iconContainer);
this.iconContainer = iconContainer;
}
connectedCallback() {
this.#render();
this.isPressed = false;
this.iconContainer.addEventListener("pointerdown", (e) => {
e.preventDefault();
e.stopPropagation();
this.isPressed = true;
this.iconContainer.setPointerCapture(e.pointerId);
});
this.iconContainer.addEventListener("pointermove", (e) => {
e.preventDefault();
e.stopPropagation();
if (this.isPressed) {
this.#snapToCorner();
}
});
this.iconContainer.addEventListener("pointerleave", (e) => {
if (this.isPressed) {
}
});
this.iconContainer.addEventListener("pointerup", (e) => {
this.isPressed = false;
this.iconContainer.releasePointerCapture(e.pointerId);
});
}
#render() {
this.iconContainer.style.position = "fixed";
this.iconContainer.style.bottom = "0px";
this.iconContainer.style.right = "0px";
this.iconContainer.style.width = "50px";
this.iconContainer.style.height = "50px";
this.iconContainer.style.backgroundColor = "red";
}
#snapToCorner(x, y) {
let maxWidth = window.innerWidth;
let maxHeight = window.innerHeight;
if (x < maxWidth / 2){
// left half
if (y < maxHeight / 2) {
// top left
this.style.left = "0px";
this.style.top = "0px";
this.style.bottom = null;
this.style.right = null;
}
else {
// bottom left
this.style.left = "0px";
this.style.top = null;
this.style.bottom = "0px";
this.style.right = null;
}
}
else {
// right half
if (y < maxHeight / 2) {
// top right
this.style.left = null;
this.style.top = "0px";
this.style.bottom = null;
this.style.right = "0px";
}
else {
// bottom right
this.style.left = null;
this.style.top = null;
this.style.bottom = "0px";
this.style.right = "0px";
}
}
}
}
customElements.define("x-widget", XWidget);
customElements.define("x-widget-icon", XWidgetIcon);
</script>
</body>
</html>

View File

@ -1,131 +0,0 @@
<html>
<head>
</head>
<body>
<div>
<style>
p {
font-size: 24;
}
</style>
<img />
<button id="snapshot-button">Take snapshot</button>
<div style="height: 50px; width: 10000px; background-color: blue;"></div>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
v
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
</div>
<x-widget></x-widget>
<script>
class XWidget extends HTMLElement {
frame;
icon;
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
let frame = document.createElement("div");
frame.style.position = "fixed";
frame.style.top = "0px";
frame.style.left = "0px";
frame.style.right = "0px";
frame.style.bottom = "0px";
frame.style.border = "5px dotted blue";
shadowRoot.append(frame);
this.frame = frame;
let icon = document.createElement("x-widget-icon");
this.frame.appendChild(icon);
this.icon = icon;
frame.addEventListener("click", (e) => {
if (e.target == icon) {
console.log("Clicked on icon");
}
});
}
connectedCallback() {
}
}
class XWidgetIcon extends HTMLElement {
iconContainer;
isPressed;
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
let iconContainer = document.createElement("div");
shadowRoot.append(iconContainer);
this.iconContainer = iconContainer;
}
connectedCallback() {
this.#render();
}
#render() {
this.iconContainer.style.position = "fixed";
this.iconContainer.style.bottom = "0px";
this.iconContainer.style.right = "0px";
this.iconContainer.style.width = "50px";
this.iconContainer.style.height = "50px";
this.iconContainer.style.backgroundColor = "red";
}
}
customElements.define("x-widget", XWidget);
customElements.define("x-widget-icon", XWidgetIcon);
</script>
</body>
</html>

View File

@ -1,406 +0,0 @@
<html>
<head>
</head>
<body>
<div style="height: 50px; width: 10000px; background-color: blue;"></div>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
v
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<p>Nice thanks man awesome</p>
<template>
<h1>yeehaw</h1>
</template>
<script>
loadExternalStyles();
function loadExternalStyles() {
let gfPreconnectLink = document.createElement("link");
gfPreconnectLink.setAttribute("rel", "preconnect");
gfPreconnectLink.setAttribute("href", "https://fonts.googleapis.com");
document.head.appendChild(gfPreconnectLink);
let gfPreconnectCOLink = document.createElement("link");
gfPreconnectCOLink.setAttribute("rel", "preconnect");
gfPreconnectCOLink.setAttribute("href", "https://fonts.gstatic.com");
gfPreconnectCOLink.setAttribute("crossorigin", true);
document.head.appendChild(gfPreconnectCOLink);
let gfLink = document.createElement("link");
gfLink.setAttribute("rel", "stylesheet");
gfLink.setAttribute("href", "https://fonts.googleapis.com/css2?family=Alexandria:wght@300;400;500;600;700&display=swap");
document.head.appendChild(gfLink);
}
class XWidget extends HTMLElement {
#icon;
#form;
#location;
#margin;
#pointerDown;
#moving;
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
this.#icon = this.#createIcon();
shadowRoot.appendChild(this.#icon)
this.#form = this.#createForm();
shadowRoot.appendChild(this.#form);
this.#margin = "20px";
this.#pointerDown = false;
this.#moving = false;
this.#location = "bottom-right";
}
connectedCallback() {
this.#render();
}
#render() {
if (this.isConnected) {
this.#renderIcon({width: "60px", height: "60px", imgSrc: this.#icon.openImgSrc});
this.#renderForm({visibility: "hidden"});
}
}
#createIcon() {
let icon = document.createElement("div");
icon.openImgSrc = "icon_open.png";
icon.closeImgSrc = "icon_close.png";
icon.addEventListener("pointerdown", (e) => this.#onIconPointerDown(e));
icon.addEventListener("pointermove", (e) => this.#onIconPointerMove(e));
icon.addEventListener("pointerup", (e) => this.#onIconPointerUp(e));
icon.addEventListener("pointerover", (e) => this.#onIconPointerOver(e));
icon.addEventListener("pointerout", (e) => this.#onIconPointerOut(e));
let iconImage = document.createElement("img");
iconImage.style.width = "100%";
iconImage.style.height = "100%";
icon.appendChild(iconImage)
return icon;
}
#createForm() {
let form = document.createElement("div");
let header = document.createElement("div");
header.id = "form-header";
form.appendChild(header);
let title = document.createElement("div");
title.id = "form-title";
header.appendChild(title);
// let headerBottom = document.createElement("hr");
// headerBottom.id = "form-header-bottom";
// form.appendChild(headerBottom);
// let nameInput = document.createElement("input");
// nameInput.id = "name-input";
// form.appendChild(nameInput);
// let commentInput = document.createElement("textarea");
// commentInput.id = "comment-input";
// form.appendChild(commentInput);
return form;
}
#renderIcon(parameters={}) {
this.#icon.style.position = "fixed";
this.#icon.style.transition = "scale 0.2s ease";
if (parameters["width"]) {
this.#icon.style.width = parameters["width"];
}
if (parameters["height"]) {
this.#icon.style.height = parameters["height"];
}
if (parameters["scale"]) {
this.#icon.style.scale = parameters["scale"];
}
if (parameters["imgSrc"]) {
this.#icon.querySelector("img").src = parameters["imgSrc"];
}
if (this.#location == "top-left") {
this.#icon.style.left = this.#margin;
this.#icon.style.top = this.#margin;
this.#icon.style.bottom = "auto";
this.#icon.style.right = "auto";
} else if (this.#location == "top-right") {
this.#icon.style.left = "auto";
this.#icon.style.top = this.#margin;
this.#icon.style.bottom = "auto";
this.#icon.style.right = this.#margin;
} else if (this.#location == "bottom-left") {
this.#icon.style.left = this.#margin;
this.#icon.style.top = "auto";
this.#icon.style.bottom = this.#margin;
this.#icon.style.right = "auto";
} else if (this.#location == "bottom-right") {
this.#icon.style.left = "auto";
this.#icon.style.top = "auto";
this.#icon.style.bottom = this.#margin;
this.#icon.style.right = this.#margin;
}
}
#renderForm(parameters={}) {
this.#form.style.width = "350px";
this.#form.style.height = "500px";
this.#form.style.backgroundColor = "white";
this.#form.style.border = "0px";
this.#form.style.borderRadius = "10px 10px 10px 10px"
this.#form.style.boxShadow = "0 4px 16px rgb(0 0 0 / 25%)";
this.#form.style.borderRadius = "15px";
this.#form.style.position = "fixed";
this.#form.style.opacity = "0";
if (this.#location == "top-left") {
this.#form.style.left = this.#margin;
this.#form.style.top = this.#icon.clientHeight + 50 + "px";
this.#form.style.bottom = "auto";
this.#form.style.right = "auto";
} else if (this.#location == "top-right") {
this.#form.style.left = "auto";
this.#form.style.top = this.#icon.clientHeight + 50 + "px";
this.#form.style.bottom = "auto";
this.#form.style.right = this.#margin;
} else if (this.#location == "bottom-left") {
this.#form.style.left = this.#margin;
this.#form.style.top = "auto";
this.#form.style.bottom = this.#icon.clientHeight + 50 + "px";
this.#form.style.right = "auto";
} else if (this.#location == "bottom-right") {
this.#form.style.left = "auto";
this.#form.style.top = "auto";
this.#form.style.bottom = this.#icon.clientHeight + 50 + "px";
this.#form.style.right = this.#margin;
}
if (parameters["visibility"]) {
// This animation feels messy - especially since opacity is always declared above as 0
if (parameters["visibility"] == "visible" && this.#form.style.visibility != "visible") {
this.#form.style.visibility = "visible";
if (parameters["animate"]) {
this.#form.style.opacity = "1";
this.#form.style.transition = "visibility 0s linear 0.1s, opacity 0.1s linear";
this.#form.style.transitionDelay = "0s";
}
else {
this.#form.style.transition = "";
}
}
else if (parameters["visibility"] == "hidden" && this.#form.style.visibility != "hidden") {
this.#form.style.visibility = "hidden";
if (parameters["animate"]) {
this.#form.style.opacity = "0";
this.#form.style.transition = "visibility 0s linear 0.1s, opacity 0.1s linear";
}
else {
this.#form.style.transition = "";
}
}
}
let header = this.#form.querySelector("#form-header");
header.style.top = "0px";
header.style.width = "100%";
header.style.height = "60px";
header.style.backgroundColor = "#AE55E7";
header.style.borderRadius = "15px 15px 0px 0px";
header.style.border = "0px";
header.style.justifyContent = "center";
header.style.alignItems = "center";
header.style.display = "flex";
// let headerBottom = this.#form.querySelector("#form-header-bottom");
// headerBottom.style.width = "100%";
// headerBottom.style.height = "10px";
// headerBottom.style.backgroundColor = "#AE55E7";
// headerBottom.style.margin = "0px";
// headerBottom.style.border = "0px";
// headerBottom.style.boxShadow = "0 0 26px -2px rgba(0, 0, 0, 0.5)";
// headerBottom.style.clipPath = "polygon(0% 0%, 100% 0%, 100% 500%, 0% 500%)";
let title = this.#form.querySelector("#form-title");
title.textContent = "New Ticket";
title.style.fontFamily = "Alexandria, sans-serif";
title.style.fontWeight = "400";
title.style.fontSize = "24px";
title.style.color = "white";
title.style.textAlign = "center";
// let nameInput = this.#form.querySelector("#name-input");
// nameInput.setAttribute("type", "text");
// nameInput.setAttribute("placeholder", "Name");
// nameInput.style.fontFamily = "Alexandria, sans-serif";
// nameInput.style.fontWeight = "300";
// nameInput.style.fontSize = "12px";
// let commentInput = this.#form.querySelector("#comment-input");
// commentInput.setAttribute("resize", "none");
// commentInput.setAttribute("overflow-y", "scroll");
// commentInput.setAttribute("rows", "15");
// commentInput.setAttribute("cols", "30");
}
#onIconPointerOver(e) {
e.preventDefault();
e.stopPropagation();
this.#renderIcon({scale: 1.05});
}
#onIconPointerOut(e) {
e.preventDefault();
e.stopPropagation();
this.#renderIcon({scale: 1});
}
#onIconPointerDown(e) {
e.preventDefault();
e.stopPropagation();
this.#pointerDown = true;
this.#icon.setPointerCapture(e.pointerId);
}
#onIconPointerMove(e) {
e.preventDefault();
e.stopPropagation();
this.#icon.style.cursor = "pointer";
if (this.#pointerDown) {
this.#moving = true;
this.#icon.style.cursor = "grabbing";
this.#snapToCorner(e.clientX, e.clientY);
}
}
#onIconPointerUp(e) {
e.preventDefault();
e.stopPropagation();
this.#icon.style.cursor = "pointer";
if (!this.#moving) {
if (this.#form.style.visibility == "visible") {
this.#renderIcon({imgSrc: this.#icon.openImgSrc});
this.#renderForm({visibility: "hidden", animate: true});
}
else {
this.#renderIcon({imgSrc: this.#icon.closeImgSrc});
this.#renderForm({visibility: "visible", animate: true});
}
}
else {
this.#moving = false;
}
this.#pointerDown = false;
this.#icon.releasePointerCapture(e.pointerId);
}
#toggleDisplayForm() {
let visibility =
this.#form.style.visibility == "visible" ?
"hidden" : "visible";
this.#renderForm({visibility: visibility})
}
#snapToCorner(anchorX, anchorY) {
let locationChanged = false;
if (anchorX < window.innerWidth / 5) {
if (this.#location != "top-left" && anchorY < window.innerHeight / 5) {
this.#location = "top-left";
locationChanged = true;
}
else if (this.#location != "bottom-left" && anchorY > window.innerHeight - window.innerHeight / 5) {
this.#location = "bottom-left";
locationChanged = true;
}
}
else if (anchorX > window.innerWidth - window.innerWidth / 5) {
if (this.#location != "top-right" && anchorY < window.innerHeight / 5) {
this.#location = "top-right";
locationChanged = true;
}
else if (this.#location != "bottom-right" && anchorY > window.innerHeight - window.innerHeight / 5) {
this.#location = "bottom-right";
locationChanged = true;
}
}
if (locationChanged) {
this.#renderIcon({imgSrc: this.#icon.openImgSrc});
this.#renderForm({visibility: "hidden"});
}
}
}
customElements.define("b6d215dc-03ff-4ca5-bc48-879e821a07f0", XWidget);
document.body.appendChild(document.createElement("b6d215dc-03ff-4ca5-bc48-879e821a07f0"));
</script>
</body>
</html>