I am developing a chat application on React JS, and I want an image to be uploaded if I copy paste an image on the chatbox. How do I trigger this?
What I need basically is:
An event that will be triggered when action "Paste" is performed.
A way to upload image into a file type input element from the clipboard.
You need to add an event listener on paste event, and get the items from the clipboard and check if its type is an image.
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML DOM - Paste an image from the clipboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/demo.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter&family=Source+Code+Pro&display=swap"
/>
<style>
.container {
/* Center the content */
align-items: center;
display: flex;
justify-content: center;
/* Misc */
height: 32rem;
padding: 1rem 0;
}
.key {
background-color: #f7fafc;
border: 1px solid #cbd5e0;
border-radius: 0.25rem;
padding: 0.25rem;
}
.preview {
align-items: center;
border: 1px solid #cbd5e0;
display: flex;
justify-content: center;
margin-top: 1rem;
max-height: 16rem;
max-width: 42rem;
}
</style>
</head>
<body>
<div class="container">
<div>
<div><kbd class="key">Ctrl</kbd> + <kbd class="key">V</kbd> in this window.</div>
<img class="preview" id="preview" />
<input id="file_input" type="file" />
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('paste', function (evt) {
const clipboardItems = evt.clipboardData.items;
const items = [].slice.call(clipboardItems).filter(function (item) {
// Filter the image items only
return /^image\//.test(item.type);
});
if (items.length === 0) {
return;
}
const item = items[0];
const blob = item.getAsFile();
const imageEle = document.getElementById('preview');
imageEle.src = URL.createObjectURL(blob);
let file = new File([blob], "file name",{type:"image/jpeg", lastModified:new Date().getTime()}, 'utf-8');
let container = new DataTransfer();
container.items.add(file);
document.querySelector('#file_input').files = container.files;
});
});
</script>
</body>
</html>
Resources
Pase an image from the clipboard
Set file value from blob
Related
I made grid 16x16 with borders for each cell, then i added a button to toggle on/off borders of those cells, but it also changes overall size of my grid. how do i prevent this?
in the future i want to implement "change size" button that will increase numbers of cells but not change grid size. I'm sure i need to define grid size somehow but i don know how. Whatever i try either messes up grid size or cell size or both
here is my code
const grid = document.getElementById('grid');
const size = document.getElementById('size');
const eraser = document.getElementById('eraser');
const color = document.getElementById('color');
const gridBorder = document.getElementById('grid-borders');
// grid
function makeGrid(number) {
grid.style.gridTemplateColumns = `repeat(${number}, 1fr)`;
grid.style.gridTemplateRows = `repeat(${number}, 1fr)`;
for (let i = 0; i < number * number; i++) {
let cell = document.createElement('div');
grid.appendChild(cell).setAttribute('id', 'box');
}
}
makeGrid(16);
// drawing on hover
color.addEventListener('click', function () {
grid.addEventListener('mouseover', function (e) {
e.target.style.backgroundColor = 'black';
});
});
// erase functionality
eraser.addEventListener('click', function () {
grid.addEventListener('mouseover', function (e) {
e.target.style.backgroundColor = 'white';
});
});
// gird borders
const allBoxes = document.querySelectorAll('#box');
gridBorder.addEventListener('click', function () {
for (let i = 0; i < allBoxes.length; i++) {
if (allBoxes[i].style.border === '1px solid black') {
allBoxes[i].style.border = 'none';
} else {
allBoxes[i].style.border = '1px solid black';
}
}
});
body {
height: 100vh;
}
#grid {
display: grid;
justify-content: center;
border: 1px solid #ccc;
}
#box {
padding: 1em;
border: 1px solid black;
}
#title {
display: flex;
align-items: flex-end;
justify-content: center;
height: 230px;
}
#container {
display: flex;
height: 60%;
width: 1204px;
align-items: flex-start;
justify-content: flex-end;
gap: 20px;
}
#menu {
display: flex;
flex-direction: column;
gap: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Etch-a-Sketch</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<div id="title">
<h1>Etch-a-Sketch</h1>
</div>
<main id="container">
<div id="menu">
<button id="size">Canvas Size</button>
<button id="color">Color</button>
<button id="eraser">Eraser</button>
<button id="grid-borders">Grid Borders</button>
</div>
<div id="grid"></div>
</main>
</body>
</html>
You can use outline instead of border. Change your CSS box definition and remove the border there as it will be used to query your box class.
NOTE: I added a box and border class initially when creating your boxes as querying multiple elements should be targeted using a class and not a unique ID.
Now that you have the class targeted, you can simple toggle classes with the click event and use css to add/remove -> toggle the outlines state using its corresponding toggled class style.
I also added a conditional to check which event is being fired in your hover state listener, this will prevent the grid from being toggled so only its children, then boxes are toggled.
Let me know if you have any issues with the code or if this isn't working for your needs and I can either remove this answer or edit to tailor any other issues you may be having.
const grid = document.getElementById('grid');
const size = document.getElementById('size');
const eraser = document.getElementById('eraser');
const color = document.getElementById('color');
const gridBorder = document.getElementById('grid-borders');
// grid
function makeGrid(number) {
grid.style.gridTemplateColumns = `repeat(${number}, 1fr)`;
grid.style.gridTemplateRows = `repeat(${number}, 1fr)`;
for (let i = 0; i < number * number; i++) {
let cell = document.createElement('div');
grid.appendChild(cell).id = 'box';
// added class border and box
cell.classList.add('border'); //--> border will be used to toggle outline in css
cell.classList.add('box') //--> box used to query all the dynamically created box elements
}
}
makeGrid(16);
// drawing on hover
color.addEventListener('click', function() {
grid.addEventListener('mouseover', function(e) {
// make sure event.target is not the grid itself
e.target !== grid ? e.target.style.backgroundColor = 'black' : null;
});
});
// erase functionality
eraser.addEventListener('click', function() {
grid.addEventListener('mouseover', function(e) {
// make sure event.target is not the grid itself
e.target !== grid ? e.target.style.backgroundColor = 'white' : null;
});
});
// grid borders
const allBoxes = document.querySelectorAll('.box');
gridBorder.addEventListener('click', function() {
// added a forEach method to toggle classes in order to track click state and style using css styling
allBoxes.forEach(box => {
box.classList.toggle('no-border');
box.classList.toggle('border');
})
});
body {
height: 100vh;
}
#grid {
display: grid;
justify-content: center;
border: 1px solid #ccc;
}
.box {
/* removed the initial outline &/or border property here so it can be added and removed (toggled) using JS el.classList.toggle */
padding: 1em;
}
#title {
display: flex;
align-items: flex-end;
justify-content: center;
height: 230px;
}
#container {
display: flex;
height: 60%;
width: 1204px;
align-items: flex-start;
justify-content: flex-end;
gap: 20px;
}
#menu {
display: flex;
flex-direction: column;
gap: 10px;
}
/* added the following classes to be toggled using JS depending on state of gridBorders button */
.border {
outline: 1px solid black;
}
.no-border {
outline: none;
}
.black-bg {
background: black;
}
.white-bg {
background: white;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Etch-a-Sketch</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<div id="title">
<h1>Etch-a-Sketch</h1>
</div>
<main id="container">
<div id="menu">
<button id="size">Canvas Size</button>
<button id="color">Color</button>
<button id="eraser">Eraser</button>
<button id="grid-borders">Grid Borders</button>
</div>
<div id="grid"></div>
</main>
</body>
</html>
Instead of using an actual border around grid items, use grid-gap prop along with background-color of the grid itself:
#grid {
...
grid-gap: 1px;
background-color: black;
}
Refer to the documentation for more info.
I am trying to get an input type-file, append it to unordered list and make it show up in browser
But it's not showing up and browser not showing any errors
Please help. I am trying to solve this problem already 3 days. I recently started coding, please don't make fun of me
This is my own project in order to learn better JavaScript
My html
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>javascripttutorial</title>
<style>
.name-div {
color: aliceblue;
}
.photo-div {
color: aliceblue;
}
.date-div {
color: aliceblue;
}
.box-1 {
border: 1px solid black;
padding: 10px;
display: flex;
flex-direction: column;
height: 500px;
width: 100px;
float: left;
}
.box-2 {
border: 1px solid black;
padding: 10px;
display: flex;
flex-direction: column;
height: 500px;
width: 200px;
float: left;
}
.box-3 {
border: 1px solid black;
padding: 10px;
display: flex;
flex-direction: column;
height: 500px;
width: 150px;
float: left;
}
body {
margin-left: 20px;
margin-right: 20px;
}</style> <script src="script.js"></script></head><body>
<div style="margin: 10px;" class="name-div">
<input id="input-name" type="text" placeholder="Your name">
</div>
<div style="margin: 10px;" class="photo-div">
<input id="input-photo" type="file" onchange="previewFile()"><br>
<img src="" height="100" alt="Image preview...">
</div>
<div style="margin: 10px;" class="date-div">
<input id="input-date" type="date" placeholder="Your birthday">
</div>
<div style="margin: 10px;" class="button-div">
<button id="button">Submit</button>
</div>
<span class="box-1">
<ul id="messages-1">Name: </ul>
</span>
<span class="box-2">
<ul id="messages-2">Photo: </ul>
</span>
<span class="box-3">
<ul id="messages-3">Date: </ul>
</span>
<script async src="script.js"></script></body></html>>
My script
window.onload=function(){
var inputName = document.getElementById('input-name');
var inputPhoto = document.getElementById('input-photo');
var inputDate = document.getElementById('input-date');
var button = document.getElementById('button');
var messages1 = document.getElementById('messages-1');
var messages2 = document.getElementById('messages-2');
var messages3 = document.getElementById('messages-3');
button.addEventListener("click", function(){
var newMessage1 = document.createElement("li");
var newMessage2 = document.createElement("li");
var photo = document.createElement("img");
var newMessage3 = document.createElement("li");
newMessage1.innerHTML = inputName.value;
photo.setAttribute("style", "height: 30px; widht: 30px;");
var reader1 = new FileReader();
reader1.addEventListener("onloadend", function(){
reader1.readAsDataURL(inputPhoto);
photo.src = reader1.result;
});
newMessage3.innerHTML = inputDate.value;
messages1.appendChild(newMessage1);
messages2.appendChild(newMessage2)
messages3.appendChild(newMessage3);
newMessage2.appendChild(photo);
inputName.value = "";
inputDate.value = "";
});
}
function previewFile() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
Steps to Follow
Listen to the change event fire by the image file upload input on an image upload.
Grab the file from the parameter that receives to the event listener callback.
Then pass it to the FileReader.
That's it in here.
inputPhoto.addEventListener("change", (e) => {
var file = e.target.files[0];
fileReader.readAsDataURL(file);
});
Now listen to the load event fire by the FileReader.
Get the base64 from the parameter.
Create an image element to preview the uploaded image.
Then set the base64 to that image src attribute.
fileReader.addEventListener("load", (e) => {
var imgUploadWrap = document.getElementsByClassName("photo-div")[0];
var img = document.createElement("img");
var base64 = e.target.result;
img.setAttribute("id", "uploaded-img");
img.height = 100;
img.src = base64;
imgUploadWrap.append(img);
});
Notes:
I create a new image element on upload because it will be easier to reset it.
If you listen to the load event, not loadend, then you don't have to handle the file empty scenario because the load event is fired only if the upload is successful.
Finally when clicking the submit button, set the preview image element's src attribute to the image element inside the message.
if (uploadedImg) {
photo.height = 60;
photo.src = uploadedImg.src;
uploadedImg.remove();
}
Full Code - https://codesandbox.io/s/input-type-file-not-showing-up-even-with-filereader-71891729-u5bvft?file=/script.js
I am pretty new to js, and I am building a color scheme generator as a solo project.
I am now stuck on select the html element that created from dynamically.
I tried to select both label and input element below, using document.getElementByClassName but it gives me 'undefined'
I wanna select both label and input elements and add an click eventListner so that they can copy the result color code from that elements.
<label for='${resultColor}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor}' type="text" value='${resultColor}'/>`
const colorPickerModes = [ 'monochrome', 'monochrome-dark', 'monochrome-light', 'analogic', 'complement', 'analogic-complement', 'triad quad']
const colorPickerForm = document.getElementById("colorPick-form");
const colorPickerInput = document.getElementById("colorPicker");
const colorPickerModeDropDown = document.getElementById("colorPick-mode");
const resultColorDiv = document.getElementById("result-color-div");
const resultColorCodeDiv = document.getElementById("result-code-div");
let colorPicked = "";
let modePicked = "";
let resultColorDivHtml =''
let resultCodeDivHtml=''
let colorSchemeSetStrings = [];
let resultColorSchemeSet = [];
fetchToRender()
renderDropDownList();
//listen when user change the color input and save that data in global variable
colorPickerInput.addEventListener(
"change",
(event) => {
//to remove # from the color hex code data we got from the user
colorPicked = event.target.value.slice(1, 7);
},
false
);
//listen when user change the scheme mode dropdownlist value and save that data in global variable
colorPickerModeDropDown.addEventListener('change', (event)=>{
modePicked =
colorPickerModeDropDown.options[colorPickerModeDropDown.selectedIndex].text;
})
//whe user click submit btn get data from user's input
colorPickerForm.addEventListener("submit", (event) => {
event.preventDefault();
// To get options in dropdown list
modePicked =
colorPickerModeDropDown.options[colorPickerModeDropDown.selectedIndex].text;
fetchToRender()
});
//when first load, and when user request a new set of color scheme
function fetchToRender(){
if (!colorPicked) {
//initialize the color and mode value if user is not selected anything
colorPicked = colorPickerInput.value.slice(1, 7);
modePicked = colorPickerModes[0]
}
fetch(
`https://www.thecolorapi.com/scheme?hex=${colorPicked}&mode=${modePicked}`
)
.then((res) => res.json())
.then((data) => {
let colorSchemeSetArray = data.colors;
for (let i = 0; i < 5; i++) {
colorSchemeSetStrings.push(colorSchemeSetArray[i]);
}
// to store each object's hex value
for (let i = 0; i < colorSchemeSetStrings.length; i++) {
resultColorSchemeSet.push(colorSchemeSetStrings[i].hex.value);
}
renderColor();
colorSchemeSetStrings = []
resultColorSchemeSet = [];
});
}
function renderColor(){
//to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet.map((resultColorItem) => {
return `<div class="result-color"
style="background-color: ${resultColorItem};"></div>`;
}).join('')
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor}' class='copy-label'>
Click to copy!</label>
<input class='result-code' id='${resultColor}'
type="text" value='${resultColor}'/>`;
})
.join("");
resultColorDiv.innerHTML = resultColorDivHtml;
resultColorCodeDiv.innerHTML = resultCodeDivHtml;
}
function renderDropDownList() {
const colorPickerModeOptionsHtml = colorPickerModes
.map((colorPickerMode) => {
return `<option class='colorSchemeOptions' value="#">${colorPickerMode}</option>`;
})
.join("");
colorPickerModeDropDown.innerHTML = colorPickerModeOptionsHtml;
}
* {
box-sizing: border-box;
}
body {
font-size: 1.1rem;
font-family: "Ubuntu", sans-serif;
text-align: center;
margin: 0;
}
/*------Layout------*/
#container {
margin: 0 auto;
width: 80%;
}
#form-div {
width: 100%;
height:10vh;
margin: 0 auto;
}
#colorPick-form {
display: flex;
width: 100%;
height:6vh;
justify-content: space-between;
}
#colorPick-form > * {
margin: 1rem;
height: inherit;
border: 1px lightgray solid;
font-family: "Ubuntu", sans-serif;
}
#colorPick-form > #colorPicker {
width: 14%;
height: inherit;
}
#colorPick-form > #colorPick-mode {
width: 45%;
padding-left: 0.5rem;
}
#colorPick-form > #btn-getNewScheme {
width: 26%;
}
#main {
display: flex;
flex-direction:column;
width:100%;
margin: .8em auto 0;
height: 75vh;
border:lightgray 1px solid;
}
#result-color-div {
width:100%;
height:90%;
display:flex;
}
#result-color-div > *{
width:calc(100%/5);
}
#result-code-div {
width:100%;
height:10%;
display:flex;
}
.copy-label{
width:10%;
display:flex;
padding:0.5em;
font-size:0.8rem;
align-items: center;
cursor: pointer;
background-color: #4CAF50;
color: white;
}
#result-code-div .result-code{
width:calc(90%/5);
text-align: center;
border:none;
cursor: pointer;
}
.result-code:hover, .result-code:focus, .copy-label:hover, .copy-label:focus{
font-weight:700;
}
/*------Button------*/
#btn-getNewScheme {
background-image: linear-gradient(
to right,
#614385 0%,
#516395 51%,
#614385 100%
);
}
#btn-getNewScheme {
padding:0.8rem 1.5rem;
transition: 0.5s;
font-weight: 700;
background-size: 200% auto;
color: white;
box-shadow: 0 0 20px #eee;
border-radius: 5px;
display: block;
cursor: pointer;
}
#btn-getNewScheme:hover,
#btn-getNewScheme:focus {
background-position: right center; /* change the direction of the change here */
color: #fff;
text-decoration: none;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght#300;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="index.css">
<title>Color Scheme Generator</title>
</head>
<body>
<div id="container">
<div>
<header><h1 class="site-title">🦎 Color Scheme Generator 🦎</h1></header>
</div>
<div id="form-div">
<form id="colorPick-form" method="get" >
<input id="colorPicker" type="color" />
<select name="colorPick-mode" id="colorPick-mode">
</select>
<button type='submit' id="btn-getNewScheme">Get Color Scheme</button>
</form>
</div>
<div id="main">
<div id="result-color-div">
</div>
<div id="result-code-div">
</div>
</div>
<script src="index.js" type="module"></script>
</body>
</html>
I think the problem is rendering timing. So you need to add event listener below the code where set innerHTML.
function renderColor() {
// to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet
.map((resultColorItem) => {
return `<div class="result-color" style="background-color: ${resultColorItem};"></div>`;
})
.join("");
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor}' type="text" value='${resultColor}'/>
`;
})
.join("");
resultColorDiv.innerHTML = resultColorDivHtml;
resultColorCodeDiv.innerHTML = resultCodeDivHtml;
// here! add event listener
const labels = document.getElementsByClassName("result-code");
Object.entries(labels).forEach(([key, label]) => {
label.addEventListener("click", (event) =>
alert(`copy color: ${event.target.value}`)
);
});
}
const resultColorCodeDiv=document.getElementById("resultColorCodeDiv")
const resultColorDiv=document.getElementById("resultColorDiv")
resultColorSchemeSet=[
{color:"red", code: "#ff0000"},
{color:"green", code: "#00ff00"},
{color:"blue", code: "#0000ff"}]
function renderColor(){
//to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet.map((resultColorItem) => {
return `<div class="result-color" style="background-color: ${resultColorItem.color};"></div>`
}).join('')
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor.code}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor.code}' type="text" value='${resultColor.code}'/>`
})
.join("")
resultColorDiv.innerHTML = resultColorDivHtml
resultColorCodeDiv.innerHTML = resultCodeDivHtml
addListener(document.querySelectorAll(".result-color"))
addListener(document.querySelectorAll(".result-code"))
}
renderColor()
function addListener(elements){
for(const element of elements){
element.addEventListener("click" , ()=>{
// add copy logic here
console.log("hello")
})
}
}
<body>
<div id="resultColorDiv"></div>
<div id="resultColorCodeDiv"></div>
</body>
const form = document.querySelector('#memeForm');
const imageInput = document.querySelector('#imageURL');
const topText = document.querySelector('#textOnTop');
const bottomText = document.querySelector('#textOnBottom');
const results = document.querySelector('#results');
form.addEventListener('submit', function(e) {
e.preventDefault();
const meme = document.createElement('div');
const image = document.createElement('img');
const textTop = document.createElement('div');
const textBottom = document.createElement('div');
const removeBtn = document.createElement('button');
//allows file to be read by the DOM as an image?
image.src = imageInput.value;
textTop.classList.add('textTop');
textTop.innerHTML = topText.value;
textBottom.classList.add('textBottom');
textBottom.innerHTML = bottomText.value;
//allows the button created in line 16 and appended to the 'meme' div in line 40 to remove all contained within the parent 'meme' div
removeBtn.innerText = "Delete Meme";
removeBtn.addEventListener('click', function(e) {
e.target.parentElement.remove();
});
//Does classList.add allow the append methods that follow to be added to 'meme'?
meme.classList.add('meme');
meme.append(image);
meme.append(textTop);
meme.append(textBottom);
meme.append(removeBtn);
//appends ALL meme inputs to the specified location(section tag)?
results.append(meme);
//clears form's inputs once form is submitted
form.reset();
});
//cool and colorful mousemove feature!
document.addEventListener('mousemove', function(e) {
// console.log('e.pageX, e.pageY');
const r = Math.round(e.pageX * 255 / window.innerWidth);
const b = Math.round(e.pageY * 255 / window.innerHeight);
const color = `rgb(${r}, 0, ${b})`;
document.body.style.backgroundColor = color;
});
h1 {
font-family: 'Montserrat', sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
h4 {
font-family: 'Montserrat', sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
label {
font-weight: bolder;
margin-bottom: 20px;
font-family: 'Montserrat', sans-serif;
}
.meme {
position: relative;
}
.textTop {
position: absolute;
top: 30px;
right: 200px;
font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
z-index: 2;
font-size: 40px;
}
.textBottom {
position: absolute;
font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
font-size: 40px;
z-index: 2;
bottom: 100px;
}
.meme image {
max-width: 100%;
z-index: 1;
}
input {
width: 50%;
box-sizing: border-box;
margin-bottom: 20px;
}
.submitBtn {
width: 12%;
float: right;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meme Generator</title>
<link rel="stylesheet" href="meme.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght#200&display=swap" rel="stylesheet">
</head>
<body>
<div>
<h1>Meme Generator</h1>
<h4>Fill out the form to start creating memes!</h4>
</div>
<form action="" id="memeForm">
<p>
<label for=""> Image URL
<input type="url" placeholder="What's the URL for your meme?" id="imageURL">
</label>
</p>
<p>
<label for=""> Text on Top
<input type="text" placeholder="(Optional) What text do you want at the top of your meme?" id="textOnTop">
</label>
</p>
<p>
<label for=""> Text on Bottom
<input type="text" placeholder="(Optional) What text do you want at the bottom of your meme?" id="textOnBottom">
</label>
</p>
<p>
<input type="submit" value="Create Meme!" class="submitBtn"></input>
</p>
</form>
<!-- saw many people use canvas but when I tried to use that tag my image wouldn't load -->
<div id="results"></div>
<script src="meme.js"></script>
</body>
</html>
First post here and a relatively new coder so bear with me.
I've been working on this meme generator and so far it can take an image URL and text and add those to the specified div that results in something that is on the verge of looking like a meme.
I have 2 main problems:
Once I fill in the inputs and press the "Create Meme!" button, the image and text are appended to their respective and elements contained within the "meme" div but I'm not able to create another meme until I delete the meme using the "Delete Meme" button I've created in my js file. Essentially, the "Create Meme!" button is not clickable once a meme has been generated. One of the goals of this project is for a user to add multiple memes to the page by submitting the form multiple times.
I can't figure out how to position the text that is shown on the top and bottom of the image correctly. I'm sure if I were to play with the positioning in CSS more it would look more like a standard meme but I'd rather have the text be automatically centered in the top and bottom of the image. For example, if I adjust the size of the page the image and text don't adjust along with it.
Please let me know if I can provide more clarity on my issue, I've been stuck here since last night and my googling efforts are becoming more and more futile.
The clicking of the button problem is the fact your div overlays the button so when you click, you click on the div, not the button.
For the layout, there is many ways to tackle it. One way is just to use some relative and absolute positioning.
.wrapper {
position: relative;
width: 80%;
}
.wrapper p {
position: absolute;
left: 0;
text-align: center;
width: 100%;
font-size: 1.4em;
}
.wrapper img {
width: 100%;
}
.wrapper p.top {
top: 0;
}
.wrapper p.bottom {
bottom: 0;
}
<div class="wrapper">
<p class="top">Hello World</p>
<img src="http://placekitten.com/400/300" />
<p class="bottom">Bacon Bacon Bacon Bacon Bacon Bacon Bacon Bacon</p>
</div>
This question already has answers here:
css rotate a pseudo :after or :before content:"" [duplicate]
(2 answers)
Closed 4 years ago.
Please check this code
https://codepen.io/manuchadha/pen/PBKYBJ
I have created a form. I want to be able to upload an image using the file upload input. When an image is selected, I want to show a thumbnail of the image just below the file selector box and also show a close (x) sign on the top-right corner of the image which could be used to delete the image.
I am trying to follow this example (https://codepen.io/brissmyr/pen/egidw) to create an X using css (not fonts) but I am unable to create it. What am I doing wrong? All I see are two vertical bars at the top corner of the image box but they are not transforming by 45degrees. I suspect that it could be a css transform issue but I could be wrong
The code is
/*handler for file upload*/
function handleFileSelect() {
console.log("got file upload event:");
/*
FileList object is the object returned as a result of a user selecting files using the <input> element,
from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement.
*/
var files = document.getElementById('question-file-upload').files; //event.target.files;
console.log("files selected:" + files + ", total selected: " + files.length);
for (var i = 0; i < files.length; i++) {
console.log("files name:" + files[i].name)
console.log("files object:" + files[i])
}
//working with only 1 file at the moment
var file = files[0];
if (files && file) {
/*
The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer,
using File or Blob objects to specify the file or data to read.
*/
var reader = new FileReader();
/*bind onload event of FileReader to _handleReaderLoaded
onload is a handler for the load event. This event is triggered by FileReader each time the reading operation is successfully completed.
*/
reader.onload = this._handleReaderLoaded.bind(this);
reader.readAsBinaryString(file);
}
}
function _handleReaderLoaded(readerEvt) {
var binaryString = readerEvt.target.result;
var base64textString = btoa(binaryString);
console.log(btoa(binaryString));
var src = "data:image/png;base64,";
src += base64textString;
var newImage = document.createElement('img');
newImage.src = src;
newImage.width = newImage.height = "80";
var closeButtonLink = document.createElement('a');
/*closeButtonLink.textContent = "x";*/
/*dont want font*/
closeButtonLink.setAttribute('href', "#");
closeButtonLink.classList.add("close");
document.querySelector('#imageContainer').appendChild(newImage);
document.querySelector('#imageContainer').appendChild(closeButtonLink);
}
body {
margin: 0px;
}
.body__div--background {
background: linear-gradient(45deg, #33b1f8 37%, #6e90f6 100%);
/*syntax linear-gradient(direction, color1 limit, color2 limit)*/
color: #555555;
font-family: Helvetica;
line-height: 1.5;
font-size: 11px;
letter-spacing: 0.25px;
}
#submit-practice-question-button {
display: block;
}
#imageContainer {
display: inline-block;
border: 1px solid black;
}
.close {
position: relative;
margin: 0px;
padding: 0px
/*right: 80px;
top:80px;
width: 32px;
height: 32px;
*/
opacity: 0.3;
}
.close:hover {
opacity: 1;
}
.close:before,
.close:after {
/*position: relative;*/
/*left: 15px;*/
border: 1px solid black;
top: 0px;
right: 80px;
content: ' ';
/*height: 33px;*/
width: 2px;
background-color: #333;
}
.close:before {
transform: rotate(45deg);
}
.close:after {
transform: rotate(-45deg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<base href="">
<title>Example</title>
<!--meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'"-->
<link rel="stylesheet" media="screen" href="fiddle.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.1/css/bootstrap-select.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="fiddle.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.1/js/bootstrap-select.min.js"></script>
</head>
<body>
<!--a href="#" class="close"></a-->
<div id="form-div" class="body__div--background">
<form id="new-question-form" class="practice-question-form" [formGroup]="practiceQuestionForm" (ngSubmit)="addPracticeQuestion()" novalidate>
<div class="form-group">
<label for="file-upload" class="control-label required">Upload files</label>
<div class="custom-file" id="file-upload" lang="es">
<input type="file" class="custom-file-input" id="question-file-upload" multiple onchange="handleFileSelect(this.files)">
<label style="width:50%" class="custom-file-label" for="question-file-upload"></label>
</div>
</div>
<div id="imageContainer"></div>
<button type="submit" id="submit-practice-question-button" class="content-div__button--blue"> Submit! </button>
</form>
</div>
</body>
Pseudo elements are inline by default, so you must apply display: block or display: inline-block to transform them, check below snippet
/*handler for file upload*/
function handleFileSelect() {
console.log("got file upload event:");
/*
FileList object is the object returned as a result of a user selecting files using the <input> element,
from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement.
*/
var files = document.getElementById('question-file-upload').files; //event.target.files;
console.log("files selected:" + files + ", total selected: " + files.length);
for (var i = 0; i < files.length; i++) {
console.log("files name:" + files[i].name)
console.log("files object:" + files[i])
}
//working with only 1 file at the moment
var file = files[0];
if (files && file) {
/*
The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer,
using File or Blob objects to specify the file or data to read.
*/
var reader = new FileReader();
/*bind onload event of FileReader to _handleReaderLoaded
onload is a handler for the load event. This event is triggered by FileReader each time the reading operation is successfully completed.
*/
reader.onload = this._handleReaderLoaded.bind(this);
reader.readAsBinaryString(file);
}
}
function _handleReaderLoaded(readerEvt) {
var binaryString = readerEvt.target.result;
var base64textString = btoa(binaryString);
console.log(btoa(binaryString));
var src = "data:image/png;base64,";
src += base64textString;
var newImage = document.createElement('img');
newImage.src = src;
newImage.width = newImage.height = "80";
var closeButtonLink = document.createElement('a');
/*closeButtonLink.textContent = "x";*/
/*dont want font*/
closeButtonLink.setAttribute('href', "#");
closeButtonLink.classList.add("close");
document.querySelector('#imageContainer').appendChild(newImage);
document.querySelector('#imageContainer').appendChild(closeButtonLink);
}
body {
margin: 0px;
}
.body__div--background {
background: linear-gradient(45deg, #33b1f8 37%, #6e90f6 100%);
/*syntax linear-gradient(direction, color1 limit, color2 limit)*/
color: #555555;
font-family: Helvetica;
line-height: 1.5;
font-size: 11px;
letter-spacing: 0.25px;
}
#submit-practice-question-button {
display: block;
}
#imageContainer {
display: inline-block;
border: 1px solid black;
}
.close {
position: relative;
margin: 0px;
padding: 0px
/*right: 80px;
top:80px;
width: 32px;
height: 32px;
*/
opacity: 0.3;
}
.close:hover {
opacity: 1;
}
.close:before,
.close:after {
/*position: relative;*/
/*left: 15px;*/
border: 1px solid black;
top: 0px;
right: 80px;
content: 'X';
/*height: 33px;*/
width: 2px;
display: inline-block;
background-color: #333;
}
.close:before {
transform: rotate(45deg);
}
.close:after {
transform: rotate(-45deg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<base href="">
<title>Example</title>
<!--meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'"-->
<link rel="stylesheet" media="screen" href="fiddle.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.1/css/bootstrap-select.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="fiddle.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.1/js/bootstrap-select.min.js"></script>
</head>
<body>
<!--a href="#" class="close"></a-->
<div id="form-div" class="body__div--background">
<form id="new-question-form" class="practice-question-form" [formGroup]="practiceQuestionForm" (ngSubmit)="addPracticeQuestion()" novalidate>
<div class="form-group">
<label for="file-upload" class="control-label required">Upload files</label>
<div class="custom-file" id="file-upload" lang="es">
<input type="file" class="custom-file-input" id="question-file-upload" multiple onchange="handleFileSelect(this.files)">
<label style="width:50%" class="custom-file-label" for="question-file-upload"></label>
</div>
</div>
<div id="imageContainer"></div>
<button type="submit" id="submit-practice-question-button" class="content-div__button--blue"> Submit! </button>
</form>
</div>
</body>