Browse Source

upload

main
forest 3 months ago
parent
commit
5dd002771f
4 changed files with 414 additions and 275 deletions
  1. +3
    -3
      index.css
  2. +18
    -7
      main.go
  3. +14
    -1
      static/app.css
  4. +379
    -264
      static/app.js

+ 3
- 3
index.css View File

@ -11,11 +11,11 @@ body {
left:0;
width:100%;
height:100%;
z-index: 100;
z-index: 10;
}
.pointer-events-none {
pointer-events: none;
#progress-container {
z-index: 100;
}
.js-requirement-info {


+ 18
- 7
main.go View File

@ -12,7 +12,6 @@ import (
"net/url"
"os"
"path"
"regexp"
"strconv"
"strings"
"text/template"
@ -81,6 +80,7 @@ type Author struct {
var pendingUploadMap = map[string]Post{}
var progressMap = map[string]int{}
var cookieSecureHTTPSOnly = false
func main() {
appVersion := "0.0.0"
@ -121,6 +121,10 @@ func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
if request.URL.Path != "" && request.URL.Path != "/" {
http.Error(response, "Not Found", http.StatusNotFound)
return
}
author := getAuthor(db, request)
displayName := ""
if author != nil {
@ -179,9 +183,15 @@ func main() {
authorsBucket := tx.Bucket([]byte("authors"))
isFirstAuthor := authorsBucket.Stats().KeyN == 0
idOfAuthorWhoCreatedThisInviteCode := bucket.Get([]byte(code))
if idOfAuthorWhoCreatedThisInviteCode != nil || isFirstAuthor {
newAuthorId, err := createAuthor(tx, string(idOfAuthorWhoCreatedThisInviteCode), displayName)
parentAuthorIdBytes := bucket.Get([]byte(code))
parentAuthorId := ""
if parentAuthorIdBytes != nil {
parentAuthorId = string(parentAuthorIdBytes)
}
//log.Printf("parentAuthorId != \"\" || isFirstAuthor: %t || %t", parentAuthorId != "", isFirstAuthor)
if parentAuthorId != "" || isFirstAuthor {
newAuthorId, err := createAuthor(tx, parentAuthorId, displayName)
if err != nil {
return err
}
@ -212,6 +222,7 @@ func main() {
var newPost Post
err := json.NewDecoder(request.Body).Decode(&newPost)
if err != nil {
log.Printf("/upload-meta 400 bad request: json.NewDecoder(request.Body).Decode(): %+v\n", err)
http.Error(response, "Bad Request", http.StatusBadRequest)
return
}
@ -227,8 +238,8 @@ func main() {
newPost.Id = postId
newPost.AuthorId = author.Id
newPost.Filename = regexp.MustCompile(`[^a-zA-Z0-9._-]+`).ReplaceAllString(newPost.Filename, "_")
newPost.Filename = fmt.Sprintf("%s_%s", postId, newPost.Filename)
//newPost.Filename = regexp.MustCompile(`[^a-zA-Z0-9._-]+`).ReplaceAllString(newPost.Filename, "_")
newPost.Filename = postId
if newPost.Type != PostTypeText {
pendingUploadMap[postId] = newPost
@ -381,7 +392,7 @@ func setCookie(response http.ResponseWriter, key, value string, maxAge int) {
http.SetCookie(response, &http.Cookie{
Name: key,
HttpOnly: true,
Secure: true,
Secure: cookieSecureHTTPSOnly,
SameSite: http.SameSiteStrictMode,
Path: "/",
Value: value,


+ 14
- 1
static/app.css View File

@ -149,6 +149,14 @@ textarea {
margin: 1rem;
}
.pointer-events-none {
pointer-events: none;
}
.pointer-events-none button {
pointer-events: all;
}
.registration {
background-color: aliceblue;
}
@ -166,6 +174,11 @@ textarea {
pointer-events: all;
}
.material-style-button > img {
width: 70%;
height: 70%;
}
.material-style-button.post-button {
border-radius: 2.9rem;
right: calc(0% + 1rem);
@ -278,7 +291,7 @@ textarea {
white-space: nowrap;
}
.continue-button {
.basic-button {
border-radius: 1rem;
width: initial;
height: initial;


+ 379
- 264
static/app.js View File

@ -18,7 +18,7 @@
const textLineRandomTranslate = [22,5];
const textLineRandomBezier = [10,1];
const imageUploadTypeIconSize = "100px";
const imagePostMaxDimension = 1024;
const imagePostPreviewCanvasMaxDimension = 1024;
const polaroidBorderTop = 55;
const polaroidBorderLeft = 100;
const polaroidBorderBottom = 229;
@ -35,12 +35,26 @@
const postScale = 0.5;
const edgePanThreshold = window.innerWidth > window.innerHeight ? window.innerHeight * 0.22 : window.innerWidth * 0.22;
const edgePanPower = 2;
const edgePanSpeed = 1.5;
const edgePanSpeed = 1500;
const absorbVelocityRate = 7;
const velocityDamping = 5;
const postTypes = {
Text: 1,
Image: 2,
Video: 3,
}
let loader;
let postElement;
let postIcon;
let openNewPost;
let textPostPreviewContainer;
let imagePostIsTransparent;
let imageFile;
let imageFileWidth;
let imageFileHeight;
let imagePreviewCanvas;
let newPostRandomSeed = Math.random();
let newPostRandomSeed = Math.round(Math.random()*2147483647);
let textPostFontIndex = 0;
let lastMaxLines = 7;
let lastDefaultTextValue = "...";
@ -52,16 +66,17 @@
let positioningPostY = 0;
let edgePanX = 0;
let edgePanY = 0;
let dragPanning = false;
let edgePanning = false;
let wallContainer;
let postsContainer;
window.addEventListener('DOMContentLoaded', () => {
const loader = document.getElementById("progress-container");
loader = document.getElementById("progress-container");
loader.style.display = 'none';
let registrationPage;
let postElement;
let lastTextPostValue;
wallContainer = createElement(document.body, "div", {
@ -84,23 +99,34 @@
{src: "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== "}
);
setupGenericDrag(wallContainer, [wallContainer], (dx, dy) => {
viewX -= dx;
viewY -= dy;
});
setupGenericDrag(
wallContainer,
[wallContainer],
(dx, dy) => {
viewX -= dx;
viewY -= dy;
dragPanning = true;
},
() => {
dragPanning = false;
}
);
let lastTimestamp;
function animationFrame(timestamp) {
if(lastTimestamp) {
update(timestamp-lastTimestamp)
update( (timestamp-lastTimestamp)*0.001 )
}
lastTimestamp = timestamp;
window.requestAnimationFrame(animationFrame);
}
window.requestAnimationFrame(animationFrame);
let lastViewX = viewX;
let lastViewY = viewY;
let velocityX = 0;
let velocityY = 0;
function update(deltaTime) {
if(positioningPost) {
const dx = edgePanX*deltaTime*edgePanSpeed;
const dy = edgePanY*deltaTime*edgePanSpeed;
viewX += dx;
@ -111,10 +137,36 @@
positioningPost.style.transform = `translate(${positioningPostX}px, ${positioningPostY}px) scale(${postScale}) `;
}
velocityX = lerp(velocityX, 0, velocityDamping*deltaTime);
velocityY = lerp(velocityY, 0, velocityDamping*deltaTime);
if(edgePanX == 0 && edgePanY == 0 && !dragPanning) {
viewX += velocityX*deltaTime;
viewY += velocityY*deltaTime;
if(edgePanning) {
positioningPostX += velocityX*deltaTime;
positioningPostY += velocityY*deltaTime;
}
} else {
if(deltaTime != 0) {
realVelocityX = (viewX-lastViewX)/deltaTime;
realVelocityY = (viewY-lastViewY)/deltaTime;
lastViewX = viewX;
lastViewY = viewY;
}
velocityX = lerp(velocityX, realVelocityX, absorbVelocityRate*deltaTime);
velocityY = lerp(velocityY, realVelocityY, absorbVelocityRate*deltaTime);
}
let wallX = -viewX;
let wallY = -viewY;
while(wallX > 0) { wallX -= backgroundImageSize[0]*backgroundScale; }
while(wallY > 0) { wallY -= backgroundImageSize[1]*backgroundScale; }
while(wallX > 0) {
wallX -= backgroundImageSize[0]*backgroundScale;
}
while(wallY > 0) {
wallY -= backgroundImageSize[1]*backgroundScale;
}
wallX = wallX % Math.round(backgroundImageSize[0]*backgroundScale);
wallY = wallY % Math.round(backgroundImageSize[1]*backgroundScale);
wallContainer.style.transform = `translate(${wallX}px, ${wallY}px)`;
@ -145,271 +197,259 @@
button.onclick = () => {
window.location = `/register?displayName=${input.value.trim()}`;
};
} else {
const overlay = createElement(document.body, "div", {class: "fullscreen-flying pointer-events-none"});
if(appState.IsAuthor) {
postElement = createElement(overlay, "div", {class: "post-button material-style-button centered-flex"});
const postIcon = createElement(postElement, "img", {
src: "static/spray-paint.webp",
alt: "create new post",
style: { width: "4.2rem", height: "4.2rem" }
});
const openNewPost = () => {
postElement.onclick = null;
postElement.classList.add("post-expand");
postIcon.style.display = "none";
let continueButton;
const postForm = createElement(document.body, "div", {class: "vertical align-center hidden"});
return
}
const contentPreviewArea = createElement(postForm, "div", {class: "vertical align-center"});
const overlay = createElement(document.body, "div", {class: "fullscreen-flying pointer-events-none"});
if(!appState.IsAuthor) {
createElement(
overlay,
"div",
{class: "registration text-center padding-1 line-height-150"},
`Anyone may post on this graffiti wall, however you have to be invited to be able to post.
Folks already having access can invite you, or you can visit the Cyberia Computer Club table to request an invite.`
);
} else {
postElement = createElement(overlay, "div", {class: "post-button material-style-button centered-flex"});
postIcon = createElement(postElement, "img", {
src: "static/spray-paint.webp",
alt: "create new post"
});
openNewPost = () => {
postElement.onclick = null;
postElement.classList.add("post-expand");
postIcon.style.display = "none";
const animateFormSize = () => {
const rect = postForm.getBoundingClientRect();
postElement.style.width = `420px`;
postElement.style.height = `${rect.height}px`;
};
let continueButton;
const postForm = createElement(document.body, "div", {class: "vertical align-center hidden"});
const validateForm = () => {
if(continueButton) {
continueButton.disabled = Boolean(textInput?.value?.trim?.() == "" && !imagePreviewCanvas);
}
};
const contentPreviewArea = createElement(postForm, "div", {class: "vertical align-center"});
let textInput;
const reRenderTextPostPreview = (maxLines, defaultTextValue) => {
lastMaxLines = maxLines;
lastDefaultTextValue = defaultTextValue;
clearElementContents(textPostPreviewContainer);
const animateFormSize = () => {
const rect = postForm.getBoundingClientRect();
postElement.style.width = `420px`;
postElement.style.height = `${rect.height}px`;
};
const isPolaroid = imagePreviewCanvas && !imagePostIsTransparent;
const maxWidth = isPolaroid ? Number(imagePreviewCanvas.style.width.replace("px", "")) : textPostDefaultMaxWidth;
if(maxWidth == NaN) {
throw new Error("reRenderTextPostPreview(): imagePreviewCanvas must have a defined width in pixels.")
const validateForm = () => {
if(continueButton) {
continueButton.disabled = Boolean(textInput?.value?.trim?.() == "" && !imageFile);
}
};
let textInput;
const reRenderTextPostPreview = (maxLines, defaultTextValue) => {
lastMaxLines = maxLines;
lastDefaultTextValue = defaultTextValue;
clearElementContents(textPostPreviewContainer);
const isPolaroid = imageFile && !imagePostIsTransparent;
const maxWidth = isPolaroid ? Number(imagePreviewCanvas.style.width.replace("px", "")) : textPostDefaultMaxWidth;
if(maxWidth == NaN) {
throw new Error("reRenderTextPostPreview(): imagePreviewCanvas must have a defined width in pixels.")
}
const textPostSVGContainer = createElement(textPostPreviewContainer, "div", {
class: "vertical align-center",
style: {
width: `${maxWidth}px`,
height: `${Math.round(315*(maxLines/textPostMaxLines))}px`,
}
const textPostSVGContainer = createElement(textPostPreviewContainer, "div", {
class: "vertical align-center",
style: {
width: `${maxWidth}px`,
height: `${Math.round(315*(maxLines/textPostMaxLines))}px`,
}
});
});
validateForm();
createText(textPostSVGContainer, textInput.value || defaultTextValue || "", maxLines, newPostRandomSeed, maxWidth);
if(isPolaroid) {
const svg = textPostSVGContainer.querySelector('svg');
if(svg) {
const svgWidth = svg.getBoundingClientRect().width;
const widthFactor = svgWidth/textPostDefaultMaxWidth;
textPostPreviewContainer.style.top = `${Math.round(elementHeightPx+polaroidTextVerticalFudge*widthFactor*polaroidBorderThickness)}px`;
}
validateForm();
createText(textPostSVGContainer, textInput.value || defaultTextValue || "", maxLines, newPostRandomSeed, maxWidth);
if(isPolaroid) {
const svg = textPostSVGContainer.querySelector('svg');
if(svg) {
const svgWidth = svg.getBoundingClientRect().width;
const widthFactor = svgWidth/textPostDefaultMaxWidth;
textPostPreviewContainer.style.top = `${Math.round(elementHeightPx+polaroidTextVerticalFudge*widthFactor*polaroidBorderThickness)}px`;
}
animateFormSize();
};
const createRandomizeButton = (parent, maxLines) => {
const polaroid = parent.querySelector(".polaroid");
const container = createElement(parent, "div", {class: "text-post-randomize-button-container"});
const randomizeButton = createElement(
container,
"div",
{
class: "material-style-button text-post-randomize-button centered-flex",
onclick: () => {
textPostFontIndex ++;
newPostRandomSeed = Math.round(Math.random()*2147483647);
reRenderTextPostPreview(lastMaxLines, lastDefaultTextValue);
if(polaroid) {
const randomBorder = mulberry32(newPostRandomSeed)() > 0.5 ? '1' : '2';
polaroid.style.borderImageSource = `url('static/polaroid-border-${randomBorder}.webp')`;
}
}
animateFormSize();
};
const createRandomizeButton = (parent, maxLines) => {
const polaroid = parent.querySelector(".polaroid");
const container = createElement(parent, "div", {class: "text-post-randomize-button-container"});
const randomizeButton = createElement(
container,
"div",
{
class: "material-style-button text-post-randomize-button centered-flex",
onclick: () => {
textPostFontIndex ++;
newPostRandomSeed = Math.round(Math.random()*2147483647);
reRenderTextPostPreview(lastMaxLines, lastDefaultTextValue);
if(polaroid) {
const randomBorder = mulberry32(newPostRandomSeed)() > 0.5 ? '1' : '2';
polaroid.style.borderImageSource = `url('static/polaroid-border-${randomBorder}.webp')`;
}
}
);
createElement(randomizeButton, "img", {
src: "static/dice.webp",
alt: "randomize",
style: { width: "2.1rem", height: "2.1rem" },
});
return container;
}
}
);
createElement(randomizeButton, "img", {
src: "static/dice.webp",
alt: "randomize",
});
const switchToTextPost = () => {
clearElementContents(contentPreviewArea);
displayUploadOptions();
imagePreviewCanvas = null;
const postPreview = createElement(contentPreviewArea, "div", {class: "text-post-container"});
textPostPreviewContainer = createElement(postPreview, "div", {class: "vertical align-center"});
reRenderTextPostPreview(textPostMaxLines, "...");
createRandomizeButton(postPreview);
validateForm();
};
return container;
}
const onImageSelected = (e) => {
clearElementContents(contentPreviewArea);
const switchToTextPost = () => {
clearElementContents(contentPreviewArea);
displayUploadOptions();
imagePreviewCanvas = null;
imageFile = null;
const postPreview = createElement(contentPreviewArea, "div", {class: "text-post-container"});
textPostPreviewContainer = createElement(postPreview, "div", {class: "vertical align-center"});
reRenderTextPostPreview(textPostMaxLines, "...");
createRandomizeButton(postPreview);
validateForm();
};
const onImageSelected = (e) => {
clearElementContents(contentPreviewArea);
imageFile = e.target.files[0];
createImagePreview(contentPreviewArea, e.target.files[0]).then((canvas) => {
imagePreviewCanvas = canvas;
elementHeightPx = Number(canvas.style.height.replace("px", ""));
if(elementHeightPx == NaN) {
throw new Error("onImageSelected(): Invalid argument canvas: element must have a defined size in pixels.")
}
imagePostIsTransparent = canvasIsTransparent(canvas);
if(imagePostIsTransparent) {
// Transparent images don't get the polaroid border -- just handle it like a text post
// and slam the image in right above the text.
canvas.style.display = 'block';
const postPreview = createElement(contentPreviewArea, "div", {
class: "text-post-container vertical align-center",
style: { paddingTop: '1em' },
});
postPreview.appendChild(canvas);
textPostPreviewContainer = createElement(postPreview, "div", {class: "vertical align-center"});
reRenderTextPostPreview(textPostMaxLines, "...");
createRandomizeButton(contentPreviewArea);
} else {
// opaque images (photos) get the polaroid border with theh text overlayed on the bottom of the border
const randomBorder = mulberry32(newPostRandomSeed)() > 0.5 ? '1' : '2';
const polaroid = createPolaroid(contentPreviewArea, canvas, `polaroid-border-${randomBorder}.webp`);
textPostPreviewContainer = createElement(
createElement(polaroid, "div", {class: "position-absolute "}),
"div", { style: { position: "relative" } }
);
reRenderTextPostPreview(polaroidTextMaxLines, "");
createImagePreview(contentPreviewArea, e.target.files[0]).then((canvas) => {
imagePreviewCanvas = canvas;
elementHeightPx = Number(canvas.style.height.replace("px", ""));
if(elementHeightPx == NaN) {
throw new Error("onImageSelected(): Invalid argument canvas: element must have a defined size in pixels.")
}
imagePostIsTransparent = canvasIsTransparent(canvas);
if(imagePostIsTransparent) {
// Transparent images don't get the polaroid border -- just handle it like a text post
// and slam the image in right above the text.
canvas.style.display = 'block';
const postPreview = createElement(contentPreviewArea, "div", {
class: "text-post-container vertical align-center",
style: { paddingTop: '1em' },
});
postPreview.appendChild(canvas);
const randomizeButton = createRandomizeButton(polaroid);
randomizeButton.style.top = `${Math.round(elementHeightPx+(polaroidBorderBottom+polaroidRandomizeButtonFudge[0])*polaroidBorderThickness)}px`;
randomizeButton.style.left = `${Math.round(polaroidRandomizeButtonFudge[1]*polaroidBorderThickness)}px`;
}
textPostPreviewContainer = createElement(postPreview, "div", {class: "vertical align-center"});
reRenderTextPostPreview(textPostMaxLines, "...");
createRandomizeButton(contentPreviewArea);
validateForm();
});
};
} else {
// opaque images (photos) get the polaroid border with theh text overlayed on the bottom of the border
const randomBorder = mulberry32(newPostRandomSeed)() > 0.5 ? '1' : '2';
const polaroid = createPolaroid(contentPreviewArea, canvas, `polaroid-border-${randomBorder}.webp`);
textPostPreviewContainer = createElement(
createElement(polaroid, "div", {class: "position-absolute "}),
"div", { style: { position: "relative" } }
);
reRenderTextPostPreview(polaroidTextMaxLines, "");
const displayUploadOptions = () => {
const uploadOptions = createElement(contentPreviewArea, "div", {class: "singleselect-bar horizontal margin-2 upload-options"});
const uploadImageLabel = createElement(
uploadOptions,
"label",
{
class: "upload-image-label",
for: "upload-image"
}
);
const randomizeButton = createRandomizeButton(polaroid);
randomizeButton.style.top = `${Math.round(elementHeightPx+(polaroidBorderBottom+polaroidRandomizeButtonFudge[0])*polaroidBorderThickness)}px`;
randomizeButton.style.left = `${Math.round(polaroidRandomizeButtonFudge[1]*polaroidBorderThickness)}px`;
}
createElement(
uploadImageLabel,
"img",
{src: `static/image.svg`, width: imageUploadTypeIconSize, height: imageUploadTypeIconSize}
);
validateForm();
});
};
createElement(
uploadOptions,
"input",
{
accept: "image/*",
id: "upload-image",
type: "file",
class: "display-none",
onchange: onImageSelected,
}
);
const captureVideoButton = createElement(
uploadOptions,
"label",
{
"aria-role": "button",
"onclick": () => {
uploadOptions.style.display = "none";
},
}
);
createElement(
captureVideoButton,
"img",
{src: `static/video.png`, width: imageUploadTypeIconSize, height: imageUploadTypeIconSize}
);
};
const displayUploadOptions = () => {
const uploadOptions = createElement(contentPreviewArea, "div", {class: "singleselect-bar horizontal margin-2 upload-options"});
const uploadImageLabel = createElement(
uploadOptions,
"label",
{
class: "upload-image-label",
for: "upload-image"
}
);
createElement(
uploadImageLabel,
"img",
{src: `static/image.svg`, width: imageUploadTypeIconSize, height: imageUploadTypeIconSize}
);
createElement(
uploadOptions,
"input",
{
accept: "image/*",
id: "upload-image",
type: "file",
class: "display-none",
onchange: onImageSelected,
}
);
const captureVideoButton = createElement(
uploadOptions,
"label",
{
"aria-role": "button",
"onclick": () => {
uploadOptions.style.display = "none";
},
}
);
createElement(
captureVideoButton,
"img",
{src: `static/video.png`, width: imageUploadTypeIconSize, height: imageUploadTypeIconSize}
);
};
const onTextInputChanged = debounce(() => reRenderTextPostPreview(lastMaxLines, lastDefaultTextValue), 250);
const checkIfTextInputChanged = () => {
if(textInput.value != lastTextPostValue) {
onTextInputChanged();
lastTextPostValue = textInput.value;
}
};
textInput = createElement(postForm, 'textarea', {
placeholder: "type your message here...",
onchange: checkIfTextInputChanged,
onkeyup: checkIfTextInputChanged,
});
const onTextInputChanged = debounce(() => reRenderTextPostPreview(lastMaxLines, lastDefaultTextValue), 250);
const checkIfTextInputChanged = () => {
if(textInput.value != lastTextPostValue) {
onTextInputChanged();
lastTextPostValue = textInput.value;
}
};
textInput.focus();
switchToTextPost();
textInput = createElement(postForm, 'textarea', {
placeholder: "type your message here...",
onchange: checkIfTextInputChanged,
onkeyup: checkIfTextInputChanged,
});
continueButton = createElement(postForm, 'button', {
class: "basic-button",
onclick: (e) => {
postElement.classList.remove("post-expand");
postElement.classList.add("post-button-enter-placement-mode");
postElement.style.removeProperty("width");
postElement.style.removeProperty("height");
postElement.removeChild(postForm);
textInput.focus();
switchToTextPost();
continueButton = createElement(postForm, 'button', {
class: "continue-button",
onclick: (e) => {
e.preventDefault();
postElement.classList.remove("post-expand");
postElement.classList.add("post-button-enter-placement-mode");
postElement.style.removeProperty("width");
postElement.style.removeProperty("height");
postElement.removeChild(postForm);
// setTimeout(() => {
// postIcon.style.display = "block";
// postElement.onclick = openNewPost;
// }, 500);
enterPostPositioningMode(textInput.value);
// xhr("POST", "upload-meta", {}, () => {
// imagePreviewCanvas.toBlob((jpegBlob) => {
//
// }, "image/jpeg", 0.9);
// });
},
}, "Continue...");
enterPostPositioningMode(textInput.value);
},
}, "Continue...");
validateForm();
validateForm();
animateFormSize();
animateFormSize();
setTimeout(() => {
postElement.appendChild(postForm);
postForm.classList.remove("hidden");
}, 500);
}
postElement.onclick = openNewPost;
} else {
createElement(
overlay,
"div",
{class: "registration text-center padding-1 line-height-150"},
`Anyone may post on this graffiti wall, however you have to be invited to be able to post.
Folks already having access can invite you, or you can visit the Cyberia Computer Club table to request an invite.`
);
setTimeout(() => {
postElement.appendChild(postForm);
postForm.classList.remove("hidden");
}, 500);
}
postElement.onclick = openNewPost;
}
});
@ -418,7 +458,7 @@
postsContainer.draggable = false;
let width = 0;
let height = 0;
if(imagePreviewCanvas) {
if(imageFile) {
width = Number(imagePreviewCanvas.style.width.replace("px", ""));
height = Number(imagePreviewCanvas.style.height.replace("px", ""));
if(width == NaN || height == NaN) {
@ -427,17 +467,18 @@
}
const metadata = {
Width: width,
Height: height,
Angle: 0,
Width: Math.round(width),
Height: Math.round(height),
Angle: Math.round(0),
RandomSeed: newPostRandomSeed,
TextContent: textContent,
Type: imageFile ? postTypes.Image : postTypes.Text,
TransparentImage: imagePostIsTransparent,
};
positioningPost = createPost(metadata, true);
positioningPostX = Math.round(viewX+(window.innerWidth*0.5));
positioningPostY = Math.round(viewY+(window.innerHeight*0.5));
positioningPostX = viewX+(window.innerWidth*0.5);
positioningPostY = viewY+(window.innerHeight*0.5);
const postContainer = positioningPost.querySelector(".post-container");
postContainer.classList.add("legal");
@ -462,17 +503,87 @@
const magnitude = Math.sqrt(edgePanX*edgePanX + edgePanY*edgePanY);
edgePanX = (edgePanX/magnitude)*edgePanMagnitude;
edgePanY = (edgePanY/magnitude)*edgePanMagnitude;
edgePanning = true;
},
() => {
edgePanX = 0;
edgePanY = 0;
edgePanning = false;
}
);
const overlay = createElement(document.body, "div", {class: "fullscreen-flying pointer-events-none vertical space-between"});
createElement(
overlay,
"div",
{class: "registration text-center padding-1 line-height-150"},
'You may touch and drag to position your post, then click POST! to publish it.'
);
createElement(
overlay,
'button',
{
class: "basic-button",
onclick: (e) => {
loader.style.display = 'block';
const cleanup = () => {
loader.style.display = 'none';
document.body.removeChild(overlay);
postElement.classList.remove("post-button-enter-placement-mode");
setTimeout(() => {
postIcon.style.display = "block";
postElement.onclick = openNewPost;
}, 500);
postContainer.classList.remove("legal");
postContainer.classList.remove("illegal");
postContainer.style.removeProperty("opacity");
// TODO figure out how to make it draggable (to pan) AND clickable (to zoom in).
postContainer.draggable = false;
};
metadata.X = Math.round(positioningPostX);
metadata.Y = Math.round(positioningPostY);
xhr("POST", "upload-meta", metadata, (status, responseText) => {
if(status != 200) {
cleanup();
throw new Error(`POST /upload-meta: server returned HTTP ${status}: ${responseText}`)
}
let uploadPromise = Promise.resolve();
if(metadata.Type == postTypes.Image) {
const postId = responseText;
uploadPromise = new Promise((resolve, reject) => {
const formData = new FormData();
formData.append('file', imageFile);
xhr("POST", `upload/${postId}`, formData, (status, responseText) => {
cleanup();
if(status != 200) {
throw new Error(`POST /upload-meta: server returned HTTP ${status}: ${responseText}`)
}
console.log(status);
});
});
}
});
},
},
"POST!"
);
}
function createPost(metadata, isPreview) {
const isTextPost = (!isPreview && metadata.URL == "") || (isPreview && !imagePreviewCanvas);
const isTextPost = (!isPreview && metadata.URL == "") || (isPreview && !imageFile);
const anchorPoint = createElement(postsContainer, "div", {class: "position-absolute"});
const postContainer = createElement(anchorPoint, "div", {
class: `position-absolute vertical align-center post-container ${(isTextPost || metadata.TransparentImage) ? 'no-polaroid' : ''}`
@ -636,13 +747,13 @@
let newHeight = img.naturalHeight;
if (newWidth > newHeight) {
if (img.naturalWidth > imagePostMaxDimension) {
newHeight *= imagePostMaxDimension / img.naturalWidth;
newWidth = imagePostMaxDimension;
if (img.naturalWidth > imagePostPreviewCanvasMaxDimension) {
newHeight *= imagePostPreviewCanvasMaxDimension / img.naturalWidth;
newWidth = imagePostPreviewCanvasMaxDimension;
}
} else if (img.naturalHeight > imagePostMaxDimension) {
newWidth *= imagePostMaxDimension / img.naturalHeight;
newHeight = imagePostMaxDimension;
} else if (img.naturalHeight > imagePostPreviewCanvasMaxDimension) {
newWidth *= imagePostPreviewCanvasMaxDimension / img.naturalHeight;
newHeight = imagePostPreviewCanvasMaxDimension;
}
const canvasWidth = newWidth > 420 ? Math.round(newWidth*(420/newWidth)) : Math.round(newWidth);
@ -964,10 +1075,10 @@
function xhr(method, url, body, callback) {
var request = new XMLHttpRequest();
request.addEventListener("load", function() {
callback(this.responseText);
callback(this.status, this.responseText);
});
request.open(method, url);
if(body && typeof body === 'object') {
if(body && typeof body === 'object' && !(body instanceof FormData)) {
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
body = JSON.stringify(body);
}
@ -1014,6 +1125,10 @@
function clamp01(x) {
return x > 1 ? 1 : (x < 0 ? 0 : x);
}
function lerp(a,b, lerp) {
lerp = clamp01(lerp);
return a*(1-lerp)+b*lerp;
}
})(window, document, window.graffitiAppState);

Loading…
Cancel
Save