New to jQuery and need help appending things during events - javascript

Currently, I'm try to create a button that, when clicked, updates a 'feed' div. I want it to create three elements: a tweet(<div>), a message(<p>), and a username(<p>). Then, I want it to append both the message and the username to the tweet div, then append the tweet div to the feed div. (knock off twitter for a learning project)
This is the event handler i have right now:
/* edit note: what is $button???? */
$button.on('click', function() {
$feed.empty();
for (var i = tweet.length - 1; i > 0; i--) {
var user = tweet[i];
console.log(user);
var $tweet = $('<div class="tweet"></div>');
var $message = $('<p class="message"></p>');
var $username = $('<p class="username"></p');
console.log(user.message);
$message.text(user.message);
$message.appendTo($tweet);
$tweet.text('#' + $message);
$tweet.appendTo($feed);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>Need more HMML here!</div>
When I click the button, I get '# [object Object]'.
I would like to know how to get the text from the data structure to render correctly on the 'feed'.
Data structure is formatted this way:
{
user: 'douglascalhoun',
message: ' installed my future ',
createdAt: Wed Feb 15 2023 15:01:02 GMT-0600 (Central Standard Time),
profilePhotoURL: './assets/img/user-3.png'
}

I think I see where you are going with this.
Here I setup a fake tweet thread and the used it in the event handler. I added some CSS just to give visual clarity.
// setup a JavaScript object with date fixed to an actual date
// well this is not great: Wed Feb 15 2023 15: 01: 02 GMT - 0600(Central Standard Time),
// setup fake tweets object: I just set up for the example since the question was about the jQuery part.
const baseDate = new Date("2023-02-15T15:01:02.000+06:00");
const bsec = baseDate.getSeconds();
const sample = [{
user: 'douglascalhoun',
message: ' installed my future ',
createdAt: new Date(baseDate.setSeconds(bsec + 20)),
profilePhotoURL: './assets/img/user-3.png'
}, {
user: 'willieb',
message: 'Ate my bananna',
createdAt: new Date(baseDate.setSeconds(bsec + 45)),
profilePhotoURL: './assets/img/user-3.png'
}, {
user: 'charliewoods',
message: 'Need more input',
createdAt: new Date(baseDate.setSeconds(bsec + 16)),
profilePhotoURL: './assets/img/user-3.png'
}].sort((a, b) => b.createdAt - a.createdAt);
//console.log(sample);
const $button = $('.add-more');
const $feed = $('.feed-me');
$button.on('click', function() {
// assumes we want a new clean feed each time
$feed.empty();
const tweet = sample;
//console.log(tweet,tweet.length);
const startat = tweet.length;
//console.log(startat,tweet[0]);
for (let i = startat; !!i; i--) {
const userTweet = tweet[i - 1];
//console.log(i-1,userTweet);
// create three objects
const $tweet = $('<div class="tweet"></div>');
const $message = $('<p class="message"></p>');
const $username = $('<p class="username"></p');
// add text to the message and username objects
$message.text(userTweet.message);
$username.text(userTweet.user);
// append the message to the tweet object
$message.appendTo($tweet);
//put this text at the start of the username object
$username.prepend('#');
// add the user to the start of the tweet and append it to the fee;
$tweet.prepend($username);
$tweet.appendTo($feed);
}
});
.container {
display: grid;
place-items: center;
}
.tweet{
display: flex;
}
.tweet {
border: solid 1px lime;
}
.username {
font-size: 1.5rem;
font-family: sans-serif;
border: solid blue 1px;
}
.message {
border: cyan 1px solid;
padding: 0.5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<button type="button" class="add-more">Add More</button>
<div class="feed-me">empty</div>
</div>
Second example to hit DOM one time for each new "batch" of tweets and removed comments. I updated the datetime to simulate new tweets and added a time formatted to the end to illustrate removal of those over a "capacity" value - so in this example we only show up to 7 at a time.
function getTweets() {
// to simulate whatever is used to go get tweets
// setup fake tweets object: from NOW
const baseDate = new Date();
const bsec = baseDate.getSeconds();
const sample = [{
user: 'douglascalhoun',
message: 'installed my future',
createdAt: new Date(baseDate.setSeconds(bsec + 20)),
profilePhotoURL: './assets/img/user-3.png'
}, {
user: 'willieb',
message: 'Ate my bananna',
createdAt: new Date(baseDate.setSeconds(bsec + 45)),
profilePhotoURL: './assets/img/user-3.png'
}, {
user: 'charliewoods',
message: 'Need more input',
createdAt: new Date(baseDate.setSeconds(bsec + 16)),
profilePhotoURL: './assets/img/user-3.png'
}].sort((a, b) => b.createdAt - a.createdAt);
// console.log('returning tweets', sample.length);
return sample;
}
const feedParameters = {
getem: getTweets,
feed: $('.feed-me')
};
// use the feedParameters for the function and feed objects
$('.add-more').on('click', feedParameters, handleAddMore);
function handleAddMore(event) {
//use the parameter objects
const tweets = event.data.getem();
const $feed = event.data.feed;
// use this data to put a "cap" on number shown
const capacity = $feed.data('capacity');
const $newTweets = $('<div class="newtweets" />');
tweets.forEach(userTweet => {
// just create from template literals and append it to the new tweets
//Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
$('<div class="tweet" />')
.append(`<span class="message">${userTweet.message}</span>`)
.prepend(`<span class="username">#${userTweet.user}</span>`)
.append(`<span class='tweet-time'>${userTweet.createdAt.toISOString().substring(11, 19)}</span>`)
.appendTo($newTweets);
});
$newTweets.find('.tweet').appendTo($feed);
// remove any extra first N over capacity
let removeCount = $feed.find('.tweet').length - capacity;
if (removeCount > 0) {
let extra = $feed.find('.tweet:nth-child(-n+' + removeCount + ')').remove();;
}
}
.container {
display: grid;
place-items: center;
}
.tweet {
display: flex;
border: solid 1px lime;
justify-content: space-between;
}
.username {
display: grid;
place-items: center;
font-size: 1.25rem;
font-family: sans-serif;
border: solid blue 1px;
}
.message {
border: cyan 1px solid;
padding: 0.5rem;
align-self: flex-end;
}
.tweet-time {
display: grid;
place-items: center;
font-size: 0.75rem;
font-family: sans-serif;
}
.test {
background-color: #ddddff44;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<button type="button" class="add-more">Add More</button>
<div class="feed-me" data-capacity="7"><span class="tweet">empty</span></div>
</div>

Related

Wix Custom element is working only when it keeps its standard tag "wix-default-custom-element"

So as you can read from the title, I have tried to use a Custom Element in WIX. When I used the template by wix, it worked perfectly well. When I just try to change the tag name however, the element doesn't show anything afterwards. Changing text such as H2_TEXT works
Here is the code by wix if somebody needs it (this does work for me):
// To debug this code, open wixDefaultCustomElement.js in Developer Tools.
const IMAGE_URL = 'https://wix.to/vUBXBKU';
const H2_TEXT = 'This is a Custom Element';
const H3_1_TEXT = 'View its code by clicking the Settings button and pasting the Server URL into a new browser tab.';
const H3_2_TEXT = 'Explore this code and use it as a reference to create your own element.';
const DEBUG_TEXT = 'Loading the code for Custom Element \'wix-default-custom-element\'. To debug this code, open wixDefaultCustomElement.js in Developer Tools.';
const createImage = () => {
const imageElement = document.createElement('img');
imageElement.src = IMAGE_URL;
imageElement.id = 'wdce-image';
return imageElement;
};
const createH2 = () => {
const h2Element = document.createElement('h2');
h2Element.textContent = H2_TEXT;
h2Element.id = 'wdce-h2';
return h2Element;
};
const createH3 = (id, text) => {
const h3Element = document.createElement('h3');
h3Element.id = id;
h3Element.textContent = text;
return h3Element;
};
const createTextContainer = () => {
const textContainer = document.createElement('div');
textContainer.id = 'wdce-text-container';
textContainer.appendChild(createH2());
textContainer.appendChild(createH3('wdce-h3-1', H3_1_TEXT));
textContainer.appendChild(createH3('wdce-h3-2', H3_2_TEXT));
return textContainer;
};
const createImageContainer = () => {
const imageContainer = document.createElement('div');
imageContainer.id = 'wdce-image-container';
imageContainer.appendChild(createImage());
return imageContainer;
};
const createStyle = () => {
const styleElement = document.createElement('style');
styleElement.innerHTML = `
wix-default-custom-element {
background-color: #f0f4f7;
display: flex;
width: 100%;
justify-content: center;
}
#wdce-image-container {
width: 35%;
max-width: 165px;
display: flex;
margin: 0 20px 0 30px;
overflow: hidden;
}
#wdce-image {
width: 100%;
min-width: 100px;
}
#wdce-text-container {
display: flex;
flex-direction: column;
width: 65%;
justify-content: center;
max-width: 314px;
min-width: 200px;
}
#wdce-h2 {
font-family: 'HelveticaNeueW01-45Ligh, HelveticaNeueW02-45Ligh, HelveticaNeueW10-45Ligh, Helvetica Neue, Helvetica, Arial, メイリオ, meiryo, ヒラギノ角ゴ pro w3, hiragino kaku gothic pro, sans-serif',
font-size: 16px;
font-weight: 500;
letter-spacing: 0.89px;
color: #32536a;
margin: 0 0 16px 0;
}
#wdce-h3-1, #wdce-h3-2 {
font-family: 'HelveticaNeueW01-45Ligh, HelveticaNeueW02-45Ligh, HelveticaNeueW10-45Ligh, Helvetica Neue, Helvetica, Arial, メイリオ, meiryo, ヒラギノ角ゴ pro w3, hiragino kaku gothic pro, sans-serif',
font-size: 14px;
font-weight: 300;
line-height: 1.43;
color: #162d3d;
margin: 0 0 8px 0;
}
`;
return styleElement;
};
class WixDefaultCustomElement extends HTMLElement {
constructor() {
super();
console.log(DEBUG_TEXT);
}
connectedCallback() {
this.appendChild(createStyle());
this.appendChild(createImageContainer());
this.appendChild(createTextContainer());
}
}
customElements.define('wix-default-custom-element', WixDefaultCustomElement);
Now you might say, "well, that's easy: just change the tag name in customElements.define()", but that doesn't work. I have also tried changing the name in createStyle from wix-default-custom-element to custom-Output.
Like this (that doesn't work):
const createStyle = () => {
const styleElement = document.createElement('style');
styleElement.innerHTML = `
#custom-Output { //doesn't work with #customElement1 (the id) either
background-color: #f0f4f7;
display: flex;
width: 100%;
justify-content: center;
}
and
customElements.define('custom-Output', WixDefaultCustomElement);
Thank you for your time!
The tag name defined in the code needs to match the one defined in the Wix Editor UI. Select your Custom Element in the editor, click Choose source, and then change the tag name there as well.

How to make the function not delete the div it creates and save it

I would appreciate a little help with my project
I made an event on the button "Outer Data" the event is called "mouseover" what I actually did as soon as the event takes place is create a div with additional data you can see it in the code I attached, my problem is that every time I create the div it won't delete it it will just hide it And if I activate it, it won't reset as soon as I do the event again because I made a delete button and I want as soon as I click it to delete the data and as soon as I click the "external data" button the data will be deleted I know that as soon as I refresh the site it will come back why is that what I want, Would appreciate help
body {
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
background-color: #ffffff;
}
#container {
border: 2px solid #000000;
width: 25%;
border-radius: 10px;
}
#header {
background-color: #000000;
color: #ffffff;
text-align: center;
padding: 5px;
border-radius: 10px 10px 0px 0px;
}
.btn {
background-color: orange;
border: 1px solid #000000;
cursor: pointer;
border-radius: 5px;
float: right;
margin: 2px
}
.btn:hover {
background-color: rgba(255, 166, 0, 0.554);
color: #ffffff;
}
.btn-add {
background-color: orange;
border: 1px solid #000000;
cursor: pointer;
border-radius: 5px;
}
.btn-add:hover {
background-color: rgba(255, 166, 0, 0.554);
color: #ffffff;
}
.btn-outer {
background-color: rgb(255, 0, 0);
border: 1px solid #000000;
color: white;
cursor: pointer;
border-radius: 4px;
}
.btn-outer:hover {
background-color: rgb(111, 111, 111);
color: #ffffff;
}
#srcIn {
border: 1px solid #000000;
border-radius: 5px;
width: 35%;
}
.userDiv {
border: 1px solid black;
border-radius: 10px;
padding: 1rem;
margin-bottom: 1rem;
}
.divOuter {
border: 1px solid black;
border-radius: 10px;
padding: 1rem;
background-color: gray;
}
<body onload="loadUsers()">
<div id="container">
<div id="header">
Search: <input type="text" onkeyup="searchUsers()" id="srcIn">
<button class="btn-add">Add</button>
</div>
</div>
<script>
const container = document.getElementById("container");
const headerText = document.getElementById('header-view');
async function loadUsers() {
const respUsers = await fetch(`https://jsonplaceholder.typicode.com/users`);
if (respUsers.ok) {
const getDataUsers = await respUsers.json();
getDataUsers.forEach(user => {
// create element div
const div = document.createElement('div');
div.classList.add('divEl')
div.style.display = 'block';
div.className = 'userDiv'
// create Id element
const h3 = document.createElement('h3');
h3.innerText = 'Id: ' + user.id;
// create inputs element
const inputName = document.createElement('input');
const inputEmail = document.createElement('input');
inputName.value = user.name;
inputEmail.value = user.email;
inputName.id = `name-${user.id}`
inputEmail.id = `email-${user.id}`
// create spans element
const span1 = document.createElement('span');
const span2 = document.createElement('span');
span1.innerText = 'Name: ';
span2.innerText = 'Email: ';
// create breaking line element
const br1 = document.createElement('br');
// create button element
const btnUpd = document.createElement('button');
const btnDel = document.createElement('button');
const btnOut = document.createElement('button');
btnUpd.innerText = 'Update';
btnDel.innerText = 'Delete';
btnOut.innerText = 'Outer Data';
btnUpd.classList.add('btn');
btnDel.classList.add('btn');
// append all elements to div
div.appendChild(h3);
div.appendChild(span1);
div.appendChild(inputName);
div.appendChild(br1)
div.appendChild(span2);
div.appendChild(inputEmail);
div.appendChild(btnOut);
div.appendChild(btnUpd);
div.appendChild(btnDel);
container.appendChild(div);
// create event over outer Data btn open outer data like: street, city, zipCode
btnOut.addEventListener('mouseover', () => {
// create Div element
const divOuter = document.createElement('div');
divOuter.id = 'divOuter';
divOuter.classList.add('divOuter');
divOuter.className = "divOuter";
// create spans element
const spanSt = document.createElement('span');
const spanCt = document.createElement('span');
const spanZc = document.createElement('span');
spanSt.innerText = "Street: "
spanCt.innerText = "City: "
spanZc.innerText = "Zip Code: "
// create Inputs elements
const strInp = document.createElement('input');
const citInp = document.createElement('input');
const zpcInp = document.createElement('input');
strInp.value = user.address.street
citInp.value = user.address.city
zpcInp.value = user.address.zipcode
strInp.className = 'inpOuter'
citInp.className = 'inpOuter'
zpcInp.className = 'inpOuter'
// create element br
const brS1 = document.createElement('br');
const brS2 = document.createElement('br');
// append elements to div
divOuter.appendChild(spanSt)
divOuter.appendChild(strInp)
divOuter.appendChild(brS1)
divOuter.appendChild(spanCt)
divOuter.appendChild(citInp)
divOuter.appendChild(brS2)
divOuter.appendChild(spanZc)
divOuter.appendChild(zpcInp)
div.appendChild(divOuter)
})
// create event if i out from btn outer data div remove
btnOut.addEventListener('mouseout', () => {
const divOuterI = document.getElementById('divOuter');
divOuterI.remove();
})
// create event that update data
btnUpd.addEventListener('click', () => {
const obj = {
method: 'PUT',
id: user.id,
name: inputName.value,
email: inputEmail.value,
headers: {
'Content-type': 'application/json; charset=UTF-8',
}
}
console.log(obj)
})
// create event that delete data
btnDel.addEventListener('click', () => {
const obj = {
method: 'DELETE',
id: user.id,
name: "",
email: "",
street: "",
city: "",
zipcode: "",
headers: {
'Content-type': 'application/json; charset=UTF-8',
}
}
inputName.value = "";
inputEmail.value = "";
const inputOuter = document.querySelectorAll('.inpOuter');
inputOuter.forEach(inp => {
inp.value = "";
})
console.log(obj)
})
})
}
}
// func Search users
function searchUsers() {
const srcIn = document.getElementById("srcIn").value;
const users = document.querySelectorAll(".userDiv");
users.forEach(user => {
const userName = user.querySelector('input[id^=name-]')
const userEmail = user.querySelector('input[id^=email-]')
const divbr = user.querySelector('input[id^=br-]')
if (userName.value.includes(srcIn) || userEmail.value.includes(srcIn) || srcIn === "") {
user.style.display = "block"
}
else {
user.style.display = "none"
}
});
}
</script>
</body>

How to display the arrays in a Textarea element

I want to show the very hard array and hard array in the textarea. Right now, it shows under the textarea as I don't know how to show it in the textarea. The user gives the input and the server response with the hard and very hard sentences from the user input. The hard sentences have a yellow background and the very hard have red background. For now, only the hard and very hard sentences with yellow and red background respectively is shown below the textarea and not the whole thing but I think it isn't intuitive as the user would have to go and search for the sentences in the textarea again as where the sentence exactly lies. So I want the whole thing to be shown in the textarea itself with the hard and very hard sentences highlighted in yellow and red background.
Right now my code looks something like this:
state={
hardArray: [],
vhardArray: []
}
performHard = async () => {
const { enteredText } = this.state;
const body = { text: enteredText };
const stringifiedBody = JSON.stringify(body);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: stringifiedBody
};
const url = "api/same";
try {
const response = await fetch(url, options);
const result = await response.json();
this.setState(prevState => ({
hardArray: [...prevState.hardArray, ...result.hard]
}));
} catch (error) {
console.error("error");
}
};
performVHard = async () => {
const { enteredText } = this.state;
const body = { text: enteredText };
const stringifiedBody = JSON.stringify(body);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: stringifiedBody
};
const url ="api/same";
try {
const response = await fetch(url, options);
const result = await response.json();
this.setState(prevState => ({
vhardArray: [...prevState.vhardArray, ...result.very_hard]
}));
} catch (error) {
console.error("error");
}
};
performAnalysis = () => {
this.performHard();
this.performVHard();
};
<textarea
name="enteredText"
className="textareaclass"
placeholder="Enter your text here"
onChange={this.handleChange}
value={enteredText}
></textarea>
<Button
className="rectangle-3"
onClick={this.performAnalysis}>Analyse
</Button>
<div>
{this.state.hardArray.map((word, i) => (
<span className="hardColor">{word}</span>
))}
{this.state.vhardArray.map((word, i) => (
<span className="vhardColor">{word}</span>
))}
</div>
edit: this is how I receive the respond from the server
{
"hard": [
"It's the possibility of having a dream come true that makes life interesting",
"I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation.",
]
"very_hard": [
“He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even
without looking.”
]
}
I want to show all the text in the same textarea where the user wrote his content instead of showing anywhere else in the browser as it will make everything look ugly.
You can only give a textarea one background color, but you can make it transparent and put things behind it to add some color, yea this is a total hack and you will need to fiddle with the sizes and the blank lines to move the text down a bit - I will leave that exercise to you.
This also does not show how to get your values into the textarea but that is simple JavaScript/react code perhaps.
I altered this with some functions to illustrate where you MIGHT simply add/remove blank lines in the textarea to match the height of the background color - would probably have to adjust that background to match when this overflows the size, OR you might adjust the background to make it smaller for the colors.
I will leave it to you to determine which is the better option, I used "|" and "||" as the line/section separators as once it is in the textarea and edited you will need something like that.
All I have time for right now to enhance this but should give a starting point for this somewhat edge case without a clear standard solution.
.message {
width: 300px;
height: 150px;
display: block;
position: absolute;
}
textarea.format-custom,
.custom-underlay,
.underlay {
margin: 0;
box-sizing: border-box;
vertical-align: top;
display: block;
position: absolute;
border: lime solid 1px;
}
textarea.format-custom {
width: 100%;
height: 100%;
background: transparent;
resize: none;
display: block;
}
.underlay {
width: 100%;
height: 100%;
background: transparent;
display: block;
z-index: -1;
}
.custom-underlay {
width: 100%;
height: 50%;
margin: 0;
box-sizing: border-box;
vertical-align: top;
}
.custom-underlay.top {
background-color: #FFDDDD;
top: 0;
left: 0;
}
.custom-underlay.bottom {
background-color: #DDDDFF;
top: 50%;
left: 0;
}
<div class="message">
<label for="msg">Your message:</label>
<textarea id="msg" name="user_message" class="format-custom">howdy, I am here
bottom of here</textarea>
<div class="underlay">
<div class="custom-underlay top"></div>
<div class="custom-underlay bottom"></div>
</div>
</div>
Alternate idea from question, put text on the div's behind:
'use strict';
// borrowed code from https://stackoverflow.com/a/17590149/125981
// makeClass - By Hubert Kauker (MIT Licensed)
// original by John Resig (MIT Licensed).
var makeClass = (function(Void) {
return function() {
var constructor = function() {
var init = constructor.prototype.init,
hasInitMethod = (typeof init == "function"),
instance;
if (this instanceof constructor) {
if (hasInitMethod) init.apply(this, arguments);
} else {
Void.prototype = constructor.prototype;
instance = new Void();
if (hasInitMethod) init.apply(instance, arguments);
return instance;
}
};
return constructor;
};
})(function() {});
//make a class MyApp using above
var MyApp = makeClass();
// create MyApp functional part using the init:
MyApp.prototype.init = function(myItem, showmeClass = "showme", separator = "|", groupSeparator = "||") {
let eventChangeName = "change";
let textElement = document.getElementById(myItem);
let showme = textElement.closest(".container").getElementsByClassName(showmeClass)[0];
let lineSep = "|\n";
let myData = {
hard: [],
very_hard: []
};
this.sentData = {
hard: [],
very_hard: []
};
//so we can tell the lines
function getStyle(elId, styleProp) {
var x = document.getElementById(elId);
let y = {};
if (x.currentStyle) {
y = x.currentStyle[styleProp];
} else if (window.getComputedStyle) {
y = document.defaultView.getComputedStyle(x, null).getPropertyValue(styleProp);
}
return y;
}
function getTextareaThings(myTextarea) {
let taComputedStyles = window.getComputedStyle(myTextarea);
return {
height: myTextarea.style.height,
rows: myTextarea.rows,
clientHeight: myTextarea.clientHeight,
lineHeight: taComputedStyles.getPropertyValue('line-height'),
font: taComputedStyles.getPropertyValue('font-size')
};
}
function getLinesInString(myString) {
/* new line things: /r old Mac, /cr/lf some, /n some
all the "new line": regex: /\r\n|\n|\r/gm
above reduced regex: g and m are for global and multiline flags */
let nl = /[\r\n]+/gm;
let lines = [];
lines = myString.split(nl);
return lines;
}
function splitGroupString(myString, separator) {
let strings = [];
strings = myString.split(separator);
return strings;
}
function getGroupsInString(myString) {
return splitGroupString(myString, groupSeparator);
}
function getGroupItemsInString(myString) {
return splitGroupString(myString, separator);
}
function getCurrentValue() {
return textElement.value;
}
function addNewLines(text, count) {
let newLine = "\n";
return text + newLine.repeat(count);
}
// make stuff obvious
function onFocusTextareaValue(event) {
showForDebug(event);
}
function onChangeTextareaValue(event) {
if (event.type == eventChangeName) {
event.stopPropagation();
event.stopImmediatePropagation();
}
showForDebug(event);
}
function showForDebug(event) {
let what = "Event: " + event.type;
let b = "<br />";
let tat = getTextareaThings(event.target);
let v = getCurrentValue().replace(what, "");
showme.innerHTML = what + b + ": lines:" + getLinesInString(v).length + b + v;
}
function getStringLineCount(arr) {
arr.length;
}
function getGroupItems() {
let groups = getGroupsInString(getCurrentValue());
let groupItems = {
count: groups.length, // how many groups, two in the definition (top/bottom)
groups: []
};
groups.forEach(function(group, index, groupsArr) {
let items = getGroupItemsInString(group);
// determine how to define "group name", I use a string and the index here
let gname = "group" + index;
let g = {
itemCount: items.length // number in this group
};
g[gname] = {
items: []
};
items.forEach(function(item, itemindex, itemsArr) {
let itemName = "item" + itemindex;
let itemobj = {};
itemobj[itemName] = {
items: item
};
g[gname].items.push(itemobj);
});
groupItems.groups.push(g);
});
return groupItems;
}
// setup events
textElement.addEventListener(eventChangeName, onChangeTextareaValue, false);
textElement.addEventListener("focus", onFocusTextareaValue, false);
this.getGeometry = function() {
let geometry = {};
let element = textElement;
let rect = element.getBoundingClientRect();
geometry.top = rect.top;
geometry.right = rect.right;
geometry.bottom = rect.bottom;
geometry.left = rect.left;
geometry.offsetHeight = element.offsetHeight;
geometry.rows = element.rows;
geometry.clientHeight = element.clientHeight;
geometry.fontSize = this.getStyleProperty("font-size");
geometry.lineCount = this.getLines().length;
geometry.lineHeight = this.getLineHeight();
geometry.height = geometry.bottom - geometry.top;
geometry.width = geometry.right - geometry.left;
console.log("Geometry:",geometry);
};
this.getMetrics = function() {
let fSize = this.getStyleProperty("font-size");
let lineCount = this.getLines().length;
let lineHeight = this.getLineHeight();
let yh = lineHeight / lineCount;
let yfhPixel = parseInt(fSize, 10);
let yLineY = yh * yfhPixel;
console.log("LH:", lineHeight, "font:", fSize, "Lines:", lineCount, "lineHeight:", lineHeight, "yh:", yh, "yfPixel:", yfhPixel, "yLineY:", yLineY);
};
this.getStyleProperty = function(propertyName) {
return getStyle(textElement.id, propertyName)
};
// public functions and objects
this.getLines = function() {
return getLinesInString(getCurrentValue());
};
this.getGroups = function() {
return getGroupsInString(getCurrentValue());
};
this.setText = function(content) {
if (!content) {
content = this.sentData;
}
let hard = content.hard.join(lineSep);
let veryHard = content.very_hard.join(lineSep);
this.textElement.value = hard.concat("|" + lineSep, veryHard);
};
this.getLineHeight = function(element) {
if (!element) {
element = textElement;
}
let temp = document.createElement(element.nodeName);
temp.setAttribute("style", "margin:0px;padding:0px;font-family:" + element.style.fontFamily + ";font-size:" + element.style.fontSize);
temp.innerHTML = "test";
temp = element.parentNode.appendChild(temp);
let lineHeight = temp.clientHeight;
temp.parentNode.removeChild(temp);
return lineHeight;
};
this.getGroupItems = function() {
return getGroupItems();
};
this.textElement = textElement;
this.showme = showme;
};
let sentData = {
hard: [
"It's the possibility of having a dream come true that makes life interesting",
"I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation."
],
very_hard: ["He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even without looking."]
};
// create instances and use our app, pass the id
var containerApp = MyApp("textThing"); //default last three parameters
containerApp.sentData = sentData;
containerApp.setText();
let groups = containerApp.getGroups();
let groupItems = containerApp.getGroupItems();
containerApp.getMetrics();
containerApp.getGeometry();
// create instances and use our app, pass the id
var containerApp2 = MyApp("msgTwo", "showme", "|", "||");
//console.log("Second One Lines:", containerApp2.getLines().length);
//containerApp2.getMetrics();
//containerApp2.getGeometry();
.page-container {
display: flex;
/* center and stack the containers*/
justify-content: center;
flex-direction: column;
align-items: center;
font-size: 62.5%;
}
.container {
border: solid 1px black;
}
.container-block {
border: 2px dashed #AAAAAA;
}
.container-items {
width: 500px;
position: relative;
}
.container-items .format-custom,
.container-items label {
width: 100%;
}
.container-items .format-custom {
height: 10em
}
.message-hr {
border: 1px solid blue;
background-color: blue;
height: 0.05em;
width: 450px;
align-items: center;
margin: 0.5em;
}
.showme {
border: dotted 2px dodgerblue;
background-color: #EEEEEE;
padding: 1em;
}
textarea.format-custom,
.custom-underlay,
.underlay {
margin: 0;
box-sizing: border-box;
vertical-align: top;
display: block;
border: lime solid 1px;
}
textarea.format-custom {
width: 100%;
height: 3em;
background: transparent;
resize: none;
border: red solid 1px;
padding: 0.5em;
}
.underlay {
border: 1px solid #fff;
width: 100%;
height: 100%;
background: transparent;
top: 1em;
left: 0;
display: block;
z-index: -1;
position: absolute;
}
.custom-underlay {
width: 100%;
height: 50%;
margin: 0;
box-sizing: border-box;
vertical-align: top;
position: absolute;
}
.custom-underlay.top {
background-color: #FFFF00;
top: 0;
left: 0;
}
.custom-underlay.bottom {
background-color: #FFAAAA;
top: 50%;
left: 0;
}
<div class="page-container">
<div class="container">
<div class="container-block">
<div class="container-items">
<label for="textThing">Your message:</label>
<textarea id="textThing" name="textThing" class="format-custom">howdy, I am here|another one | cheese burgers
fries and a drink
||
bottom of here| bottom second</textarea>
<div class="underlay">
<div class="custom-underlay top"></div>
<div class="custom-underlay bottom"></div>
</div>
</div>
</div>
<div class="showme">xxxone</div>
</div>
<div class="container">
<div class="container-block">
<div class="message-hr container-items">
</div>
</div>
</div>
<div class="container">
<div class="container-block">
<div class="container-items">
<label for="msgTwo">Second message:</label>
<textarea id="msgTwo" name="msgTwo" class="format-custom">Not the same|Nxxt one
||
bottom of next</textarea>
<div class="underlay">
<div class="custom-underlay top"></div>
<div class="custom-underlay bottom"></div>
</div>
</div>
</div>
<div class="showme">xxxtwo</div>
</div>
</div>
its not with color but in this code you can set a lable like this (hard: veryhard :)
state = {
value: "",
hard: [],
veryHard: []
};
handleChange = ({ target }) => {
const { value, name } = target;
console.log(value, name);
this.setState({ value });
};
performAnalysis = () => {
let hard = [
//this state ,get from performHard function (you should set state it )
"It's the possibility of having a dream come true that makes life interesting",
"I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation."
];
let veryHard = [
//this state ,get from performVHard function (you should set state it )
"“He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even without looking.“"
];
this.setState({ hard, veryHard });
// you shoud setState like this in these 2 function
// this.performHard();
// this.performVHard();
};
render() {
return (
<div className="App">
<header className="App-header">
<textarea
value={
this.state.value.length
? this.state.value
: " Hard : " +
" " +
this.state.hard +
" " +
"very Hard : " +
this.state.veryHard
}
onChange={this.handleChange}
/>
<button onClick={this.performAnalysis}>analise</button>
</header>
</div>
);
}
its not exactly that you want,but you can get help from this code

How to get start and end time on drop in vis.js timeline?

I implemented the vis.js timeline in my vue.js project, but I have a problem with the drop. First of all I think the drop does not works in that library, second how can i get the start and the end time and date when I drag one item and then drop it?
Because the drop event is not working I'm trying to do it with
#items-update="itemsUpdate()"
and I'm getting the data back with.
let properties = this.$refs.timeline.getEventProperties(event)
But I'm getting the time where the mouse pointer stops.
So is there any way to get the start time and end time after drop I mean after I stop dragging the item?
Because I need to save start time and the end time into my database for that dragged item.
Thanks.
I don't know how to implement directly with vue.js but you can already get this data from "vis.js" by adding a "dragend" event to the dragged item in the timeline and then processing it in vue.js.
Here is working example adapted from "vis.js examples" website
// create groups
var numberOfGroups = 3;
var groups = new vis.DataSet()
for (var i = 0; i < numberOfGroups; i++) {
groups.add({
id: i,
content: 'Truck ' + i
})
}
// create items
var numberOfItems = 10;
var items = new vis.DataSet();
var itemsPerGroup = Math.round(numberOfItems / numberOfGroups);
for (var truck = 0; truck < numberOfGroups; truck++) {
var date = new Date();
for (var order = 0; order < itemsPerGroup; order++) {
date.setHours(date.getHours() + 4 * (Math.random() < 0.2));
var start = new Date(date);
date.setHours(date.getHours() + 2 + Math.floor(Math.random() * 4));
var end = new Date(date);
items.add({
id: order + itemsPerGroup * truck,
group: truck,
start: start,
end: end,
content: 'Order ' + order
});
}
}
// specify options
var options = {
stack: true,
start: new Date(),
end: new Date(1000 * 60 * 60 * 24 + (new Date()).valueOf()),
editable: true,
orientation: 'top',
onDropObjectOnItem: function(objectData, item, callback) {
if (!item) { return; }
alert('dropped object with content: "' + objectData.content + '" to item: "' + item.content + '"');
}
};
// create a Timeline
var container = document.getElementById('mytimeline');
timeline1 = new vis.Timeline(container, items, groups, options);
function handleDragStart(event) {
var dragSrcEl = event.target;
event.dataTransfer.effectAllowed = 'move';
var itemType = event.target.innerHTML.split('-')[1].trim();
var item = {
id: new Date(),
type: itemType,
content: event.target.innerHTML.split('-')[0].trim()
};
// set event.target ID with item ID
event.target.id = new Date(item.id).toISOString();
var isFixedTimes = (event.target.innerHTML.split('-')[2] && event.target.innerHTML.split('-')[2].trim() == 'fixed times')
if (isFixedTimes) {
item.start = new Date();
item.end = new Date(1000 * 60 * 10 + (new Date()).valueOf());
}
event.dataTransfer.setData("text", JSON.stringify(item));
// Trigger on from the new item dragged when this item drag is finish
event.target.addEventListener('dragend', handleDragEnd.bind(this), false);
}
function handleDragEnd(event) {
// Last item that just been dragged, its ID is the same of event.target
var newItem_dropped = timeline1.itemsData.get(event.target.id);
var html = "<b>id: </b>" + newItem_dropped.id + "<br>";
html += "<b>content: </b>" + newItem_dropped.content + "<br>";
html += "<b>start: </b>" + newItem_dropped.start + "<br>";
html += "<b>end: </b>" + newItem_dropped.end + "<br>";
document.getElementById('output').innerHTML = html;
}
function handleObjectItemDragStart(event) {
var dragSrcEl = event.target;
event.dataTransfer.effectAllowed = 'move';
var objectItem = {
content: 'objectItemData',
target: 'item'
};
event.dataTransfer.setData("text", JSON.stringify(objectItem));
}
var items = document.querySelectorAll('.items .item');
var objectItems = document.querySelectorAll('.object-item');
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
item.addEventListener('dragstart', handleDragStart.bind(this), false);
}
for (var i = objectItems.length - 1; i >= 0; i--) {
var objectItem = objectItems[i];
objectItem.addEventListener('dragstart', handleObjectItemDragStart.bind(this), false);
}
li.item {
list-style: none;
width: 150px;
color: #1A1A1A;
background-color: #D5DDF6;
border: 1px solid #97B0F8;
border-radius: 2px;
margin-bottom: 5px;
padding: 5px 12px;
}
li.item:before {
content: "≣";
font-family: Arial, sans-serif;
display: inline-block;
font-size: inherit;
cursor: move;
}
li.object-item {
list-style: none;
width: 150px;
color: #1A1A1A;
background-color: #D5DDF6;
border: 1px solid #97B0F8;
border-radius: 2px;
margin-bottom: 5px;
padding: 5px 12px;
}
li.object-item:before {
content: "≣";
font-family: Arial, sans-serif;
display: inline-block;
font-size: inherit;
cursor: move;
}
.items-panel {
display: flex;
justify-content: space-around;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<title>Timeline | Drag & Drop</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" />
</head>
<body>
<h1>Timeline Drag & Drop Example</h1>
<p>For this to work, you will have to define your own <code>'dragstart'</code> eventListener on each item in your list of items (make sure that any new item added to the list is attached to this eventListener 'dragstart' handler). This 'dragstart' handler
must set <code>dataTransfer</code> - notice you can set the item's information as you want this way.</p>
<div id="mytimeline"></div>
<div class='items-panel'>
<div class='side' style="max-width:350px;overflow:auto">
<h3>Last item just been dragged on timeline:</h3>
<pre id="output"></pre>
</div>
<div class='side'>
<h3>Items:</h3>
<ul class="items">
<li draggable="true" class="item">
item 1 - box
</li>
<li draggable="true" class="item">
item 2 - point
</li>
<li draggable="true" class="item">
item 3 - range
</li>
<li draggable="true" class="item">
item 3 - range - fixed times -
<br> (start: now, end: now + 10 min)
</li>
</ul>
</div>
<div class='side'>
<h3>Object with "target:'item'":</h3>
<li draggable="true" class="object-item">
object with target:'item'
</li>
</div>
</div>
</body>
</html>

I want to display the ID of clicked Item in a class and delete it if clicked again

I am trying to make an interface where you can select tickets and buy them, I want that when I click on a seat it displays like "You are currently buying the next tickets + (The tickets chosen by the user)".
This is my code so far:
var seatsUnclicked = document.getElementsByClassName("seat-unique");
var seatsClicked = document.getElementsByClassName("seatClicked");
var images = document.getElementsByTagName("IMG");
var seatsOutput = document.getElementsById("seatsOutput");
var ticketsData = 0
for (let i = 0; i < seatsUnclicked.length; i++) {
seatsUnclicked[i].onmouseover = function() {
this.src = "chairclicked.svg";
this.onmouseout = function() {
this.src = "chair.svg"
}
if ($(this).hasClass('seatClicked')) {
this.src = "chairclicked.svg";
this.onmouseout = function() {
this.src = "chairclicked.svg"
}
}
}
seatsUnclicked[i].onclick = function() {
this.classList.add("new")
if ($(this).hasClass('seatClicked')) {
this.classList.remove("seatClicked")
this.classList.remove("new")
this.src = "chair.svg";
this.onmouseout = function() {
this.src = "chair.svg"
}
ticketsData = ticketsData - /* "the id of this element in a string" */
}
if ($(this).hasClass('new')) {
this.src = "chairclicked.svg";
this.classList.add("seatClicked")
this.classList.remove("new")
this.onmouseout = function() {
this.src = "chairclicked.svg"
}
ticketsData = ticketsData + /* "the ID of this element in a string" */
}
seatsOutput.innerHTML = "THE TICKETS YOU HAVE CHOSEN ARE" + string(ticketsData)
}
}
<div class="seats-row-A">
<img id="A1" class="seat-unique " src="http://via.placeholder.com/100x100?text=A1">
<img id="A2" class="seat-unique " src="http://via.placeholder.com/100x100?text=A2">
<img id="A3" class="seat-unique " src="http://via.placeholder.com/100x100?text=A3">
<img id="A4" class="seat-unique " src="http://via.placeholder.com/100x100?text=A4">
<img id="A5" class="seat-unique" src="http://via.placeholder.com/100x100?text=A5">
<img id="A6" class="seat-unique " src="http://via.placeholder.com/100x100?text=A6">
<img id="A7" class="seat-unique " src="http://via.placeholder.com/100x100?text=A7">
</div>
<h2 id="seatsOutput">Chosen Tickets:</h2>
jQuery
The only jQuery statement in OP code is: $(this).hasClass('seatClicked').
The plain JavaScript equivalent is: this.classList.contains('seatClicked').
Question
I couldn't follow the OP code because there was only a class, an id, and img tags that match the JavaScript, but it's not that clear because of the *.svg files (not provided.) Also, there's a curly bracket } missing (I think it belongs to the for loop, but I'm not wasting time on debugging typos.)
The Demo was built in mind with what the question and comments had mentioned:
"...I want that when I click on a seat it displays like "You are currently buying..."
Highlight icon when hovered over.
Reveal icon's id when hovered on.
All hover behavior is done with CSS: :hover, ::before, ::after, content: attr(id), content: '\a0\1f4ba'. Using JavaScript for behavior CSS can do will result in more CPU cycles. CSS will use GPU of your graphics card instead of the CPU.
Testing
The seats are dynamically generated with id="A* by entering a number in the input and clicking the View button. For each additional click of the button a new batch of seats are appended and have ids that correspond to it's group:
input: 55 and first click A0-A55,
input: 12 and second click B0-B12,
input: 222 and third click C0-C222
...
Last group is J
References
The Demo is basically a <form>. HTMLFormControlsCollection API is used to set/get form controls and values.
Reference the tag
const ui = document.forms.tickets;
This is a collection of all form controls in form#tickets
const t = ui.elements;
Now all form controls are now accessible by prefixing a form control's #id or [name] with the HTMLFormControlsCollection Object.
<textarea name='textA'></textarea>
Without HFCC API
var ta = document.querySelector('[name=textA]');
With HFCC API
var ta = t.textA;
The links are collected by Links Collection.
document.links
DocumentFragment is used to insert a huge amount of dynamic HTML in one shot efficiently and quickly.
document.createDocumentFragment();
Various array methods were used:
Array.from()
map()
fill()
indexOf()
Demo
const ui = document.forms.tickets;
const t = ui.elements;
const seats = document.getElementById('seats');
t.btn.addEventListener('click', seatsAvailable);
seats.addEventListener('click', function(e) {
let picked = [];
pickSeat(e, picked);
}, false);
function pickSeat(e, picked) {
const display = t.display;
if (e.target.tagName === "A") {
e.target.classList.toggle('picked');
picked = Array.from(document.querySelectorAll('.picked'));
}
picked = picked.map(function(seat, index, picked) {
return seat.id;
});
display.value = "";
display.value = picked;
}
function seatsAvailable(e) {
const qty = this.previousElementSibling;
const last = document.links[document.links.length - 1].id;
console.log(last);
const limit = parseInt(qty.value, 10) + 1;
const spots = new Array(limit);
spots.fill(0, 0, limit);
return generateSeats(spots, last);
}
function generateSeats(spots, last) {
if (last.charAt(0) === "J") {
t.display.textContent += "Last row available";
return false;
}
const rowID = ['x', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
let row = rowID.indexOf(last.charAt(0)) + 1;
const frag = document.createDocumentFragment();
const avSeats = spots.map(function(A, idx) {
const seat = document.createElement('a');
seat.id = rowID[row] + idx;
seat.href = "#/";
frag.appendChild(seat);
return seat;
});
seats.appendChild(frag);
if (document.links[0].id === 'x') {
const x = document.getElementById('x');
x.parentElement.removeChild(x);
}
if (document.links.length > 114) {
const ext = (Math.round(document.links.length / 114)*600)+600;
seats.style.maxHeight = ext+'px';
}
return avSeats;
}
html,
body {
width: 100%;
height: 10%;
font: 400 16px/1.3 Consolas;
}
#seats {
display: flex;
flex-flow: column wrap;
max-height: 600px;
width: auto;
border: 3px ridge grey;
}
.box {
display: table
}
input,
button,
label {
font: inherit
}
#qty {
text-align: right
}
#display {
display: table-cell;
}
.tag {
overflow-x: scroll;
overflow-y: hidden;
display: block;
width: 400px;
line-height: 1.3
}
a,
a:link,
a:visited {
display: inline-block;
margin: 0;
text-align: center;
text-decoration: none;
transition: all 500ms ease;
}
a:hover,
a:active {
background: rgba(0, 0, 0, 0);
color: #2468ac;
box-shadow: 0 0 0 3px #2468ac;
}
a::before {
content: attr(id);
color: transparent;
}
a:hover::before {
color: #2468ac;
}
a.picked::before {
color: #000;
}
a::after {
content: '\a0\1f4ba';
font-size: 1.5rem;
}
#x {
pointer-events: none
}
.as-console-wrapper {
width: 30%;
margin-left: 70%
}
<form id='tickets'>
<fieldset class='box'>
<legend>Available Seats</legend>
<fieldset class='box'>
<input id='qty' type='number' min='0' max='50' value='1'> <button id='btn' type='button'>View</button>
<label class='tag'>Current ticket purchases to seats:
<output id='display'></output>
</label>
</fieldset>
<section id='seats'>
<a id='x' href='#/'></a>
</section>
</fieldset>
</form>

Categories

Resources