I've got an inventory for items in my javascript game.
I'm trying to make it so that when you mouseover an inventory item it shows a text overlay description of the item.
My idea was to append a div with the mouseover "reveal()" function once the item is added to the inventory but for some reason its not working. It works with the item text being ::before or ::after the div but i cant seem to get a text overlay of the item image even when playing around with the Z-Index.etc
I've tried a simple :hover in CSS but couldnt get it to work that way either.
I can "spawn" the item with the text on top from the start i just cant seem to get it so that the text only appears on a mouse over.
Hopefully i have explained it in a way that makes sense:
const textElement = document.getElementById('text');
const imgElement = document.getElementById('room-image');
const optionButtonsElement = document.getElementById('option-buttons');
const button3 = document.getElementById('TEST');
const inventory = document.getElementById('inventory');
const itemContainer = document.getElementById('imageContainer');
const itemText = document.getElementById('itemtext');
let textArrayIteration = 1
function reveal() {
itemText.classList.toggle('on');
}
//ADDING OBJECT VALUE TO INVENTORY///
function pullValue() {
var node = document.createElement("P");
var textNodeItems = Object.values(items);
var textNode = (document.createTextNode(textNodeItems));
node.appendChild(textNode);
document.getElementById("inventory").appendChild(node);
//ASSIGNING THE IMAGE AND DIVS FOR THE ITEM//
if (inventory.innerHTML.indexOf("test") !== -1) {
var a = document.createElement("div")
a.setAttribute("id", "Div1");
var iconUrl = document.createElement("img");
iconUrl.src = "test.jpg";
a.appendChild(itemText);
a.appendChild(iconUrl);
inventory.appendChild(a);
node.style.display = "none";
}
.itemtext-on {
position: absolute;
display: none;
z-index: 200;
}
.itemtext {
position: absolute;
display: block;
font-size: 80px;
top: 50px;
color: red;
z-index: 200;
}
<div id="itemtext" class="itemtext" onmouseover="reveal()">test</div>
You have not defined the class on.
I see that you have defined .itemtext-on.
If this is a typo, then change it to .itemtext.on and it should work.
Related
I am having issues with onclick events triggered on parent elements but not on children.
I have an image grid created through JavaScript:
HTML div:
JavaScript to append images to this image-grid div:
var columnDiv = document.createElement('div');
columnDiv.setAttribute('class', 'column');
// create content div inside column
var contentDiv = document.createElement('div');
contentDiv.setAttribute('class', 'content');
contentDiv.setAttribute('data-animation_url', element['animation_url'])
contentDiv.setAttribute('data-image_url', element['image_url'])
// create image and append to contentDiv
var image = document.createElement('img');
image.setAttribute('src', image_gateway_url);
image.setAttribute('style', 'width:100%');
contentDiv.appendChild(image);
// add image name
var caption = document.createElement('span');
caption.setAttribute('class', 'image-name')
caption.innerHTML=element['name'];
contentDiv.appendChild(caption);
// append content div to column and append it to the grid
columnDiv.appendChild(contentDiv);
document.getElementById('image-grid').appendChild(columnDiv);
CSS:
#image-grid{
margin: auto;
position:absolute;
z-index: -1;
}
.column {
float: left;
width: 25%;
height: 35vh;
position: relative;
z-index: 0;
}
.content {
background-color: white;
padding: 10px;
position: relative;
z-index: 1;
}
JavaScript code for click event:
$('div').click(function() {
var myClass = this.className;
alert(myClass);
});
When clicking on images, the event triggers the alert 'gallery-grid' wherever I click.
From other posts I would expect the event to trigger on children first then work its way up towards the parent but for some reason it is not the case here...
Does anyone happen to know how I could access the 'content' class div with my onclick event to redirect users to the page relevant to the image they clicked ?
Thank you
The issue was caused by the use of this instead of event.target.
This code now allows to iterate over all parent divs until I find the one I am interested in:
$('div').click(function(event) {
let currentElement = event.target;
while(currentElement.className != 'content') {
currentElement=currentElement.parentNode;
};
alert(currentElement.className);
})
So this is a bit of a mix-up.
I want to highlight certain words and add a help-text to them when you hover them. My current code searches for keywords, let's say the word "Mammal". When it finds the word "Mammal" it adds a span element around the word with a class that styles it so that you get an underline on the word. It also adds a child span element on the word that is hidden and contains the help-text I want to show.
The child's position is set to position:absolute and placed directly underneath the underlined word.
I have no control over the parent elements of the word or where on the page the word is, so the words parent/grandparent/etc might have overflow:hidden (and/or position:relative) which will partially hide the word. I want it to always show up (without taking any space on the page) when you hover the marked word, but I just can't think of a good way to solve this.
I've thought about putting the hover display text, not as a child of the hover element, but to have it further up above the overflow:hidden container, but I can't think of a good way how I would get that to work and how the child element would then target a grandparent sibling element to be displayed, etc.
Here's an element that shows how it looks and behaves:
.tooltip {
border-bottom: 1px solid orange;
}
.tooltip .tooltipText {
visibility: hidden;
width: 100px;
background-color: green;
position: absolute;
margin: 20px 0px 0px -80px;
}
.tooltip:hover .tooltipText {
visibility: visible;
}
<html>
<body>
<div style="overflow: hidden; width:100px;">
<div style="position:relative;">
<div>text <span class="tooltip">containing<span class="tooltipText">Hover text here</span></span> the word i'm looking for</div>
</div>
</div>
</body>
First i get all the nodes, then i go through them updating the words and adding the required elements:
nodes.forEach(function(node){
let nextNode = node.nextSibling,
parent = node.parentNode,
content = node.textContent,
newNodes = [];
node.parentNode.removeChild(node);
content.split(wordToHighlight).forEach(function(part, i, arr){
newNodes.push(document.createTextNode(part));
if(i < arr.length - 1){
let highlight = document.createElement("span");
highlight.innerHTML = wordToHighlight;
highlight.classList.add('tooltip');
let label = document.createElement('span');
label.classList.add('tooltipText');
label.innerHTML = "Hover text here";
highlight.appendChild(label);
newNodes.push(highlight);
}
});
newNodes.forEach(function(n){
if(nextNode)
parent.insertBefore(n, nextNode);
else
parent.appendChild(n);
});
});
This logic works for the most part, but when a parent/grandparent/etc contains either position:relative or overflow:hidden then the text gets cut and I've tried fiddling with CSS for hours now to see if I could find a way to make it work without much success. I would also like a better way to center it directly underneath the word it highlights, but move it so that it won't go out of the viewport to the right/left/top/bottom depending on where the word appears if that's possible.
I can add more details/code or such if needed, thanks for any help!
just insert the tooltip outside the element which has overflow: hidden;.
That is the only solution here, though you will need to position accordingly in that case.
The comment from #pilchard about using the library Popper worked perfectly for this use case and it was easy and fast to set up.
function show(selector, popperInstance) {
const tooltip = document.querySelector(selector);
tooltip.setAttribute('data-show', '');
popperInstance.setOptions({
modifiers: [{ name: 'eventListeners', enabled: true }],
});
popperInstance.update();
}
function hide(selector, popperInstance) {
const tooltip = document.querySelector(selector);
tooltip.removeAttribute('data-show');
popperInstance.setOptions({
modifiers: [{ name: 'eventListeners', enabled: false }],
});
}
function underlineWords()
{
const showEvents = ['mouseenter', 'focus'];
const hideEvents = ['mouseleave', 'blur'];
let nodeNumber = 1;
nodes.forEach(function(node){
let nextNode = node.nextSibling,
parent = node.parentNode,
content = node.textContent,
newNodes = [],
selectorIds = [],
poppers = [],
textIds = [];
node.parentNode.removeChild(node);
content.split(itemName).forEach(function(part, i, arr){
newNodes.push(document.createTextNode(part));
if(i < arr.length - 1){
let highlight = document.createElement('span');
highlight.innerHTML = itemName;
highlight.classList.add('tooltipHover');
highlight.id = itemName + nodeNumber + '-' + i + 'Hover';
highlight.setAttribute('aria-describedby', 'tooltip');
selectorIds.push('#' + highlight.id);
let tooltipText = document.createElement('span');
tooltipText.innerHTML = "Hover text here";
tooltipText.classList.add('tooltip');
tooltipText.id = nodeNumber + '-' + i + 'Show';
textIds.push('#' + tooltipText.id);
highlight.appendChild(tooltipText);
newNodes.push(highlight);
const popper = Popper.createPopper(highlight, tooltipText, {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
});
poppers.push(popper);
}
});
newNodes.forEach(function(n){
if(nextNode)
parent.insertBefore(n, nextNode);
else
parent.appendChild(n);
});
for(let i = 0; i < selectorIds.length; i++){
const popper = poppers[i];
const selectorId = selectorIds[i];
const textId = textIds[i];
const selector = document.querySelector(selectorId);
showEvents.forEach(event => {
selector.addEventListener(event, function(){ show(textId, popper) });
});
hideEvents.forEach(event => {
selector.addEventListener(event, function(){ hide(textId, popper) });
});
}
nodeNumber += 1;
});
}
I'm trying to add a link to a pseudo element, but not the parent element. I'm brand new to javascript, and after doing a lot of research I've been able to add a link to both the parent and pseudo elements, but I don't want the parent to be linked. It unfortunately will have to be a pseudo element because I don't have the option of adding another div to the html.
I have a fiddle which is kind of a mash of a few different fiddles I've found. Please let me know if I'm on the right track, or if this is even possible. And let me know if there is any additional information I can provide.
One more thing to note, is that the parent div will have child divs as a menu, which is why I'd prefer the parent not be clickable. But after testing (at least in the fiddle as it is now) the child links are still be clickable and correct, and these will still need to be clickable as well.
Thanks!
http://jsfiddle.net/mqb9juhn/1/
<div id="example">
<div class="example-child">
Test Test 2
</div>
</div>
#example {
position: relative;
}
#example::before {
content: "click here"!important;
font-size: 16px;
display: block;
padding: 20px;
background-color: #ffff00;
top: 0;
}
var UID = {
_current: 0,
getNew: function(){
this._current++;
return this._current;
}
};
HTMLElement.prototype.pseudoStyle = function(element,prop,value){
var _this = this;
var _sheetId = "pseudoStyles";
var _head = document.head || document.getElementsByTagName('head')[0];
var _sheet = document.getElementById(_sheetId) || document.createElement('style');
_sheet.id = _sheetId;
var className = "pseudoStyle" + UID.getNew();
_this.className += " "+className;
_sheet.innerHTML += "\n."+className+":"+element+"{"+prop+":"+value+"}";
_head.appendChild(_sheet);
return this;
};
$(document).ready(function(){ $("#example").on('click', function(){
window.location = "http://www.google.com/";});
});
var div = document.getElementById("example");
div.pseudoStyle("before","color","#ff0000");
With the onclick event I am trying to add mutliple LIs to UL, It wont add more than one Li with this method no matter how many appendChilds I do.
var form = document.getElementById("form");
var newUl = document.createElement('ul');
var newLi = document.createElement('li');
newButton.addEventListener("click", function(){
form.appendChild(newUl);
newUl.id = "formList";
var formList = document.getElementById("formList");
formList.appendChild(newLi);
formList.appendChild(newLi);
formList.appendChild(newLi);
}
//// html
<div id="form">
</div>
newLi is a reference to the node you wish to append to the formList. It can exist just once.
So, first time it executes formList.appendChild(newLi), it will append it to formList. Second time it executes, it would be removed from the first position and now added to second position. Same for third position.
You cannot append the same node multiple times using appenChild.
The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position (there is no requirement to remove the node from its parent node before appending it to some other node). This means that a node can't be in two points of the document simultaneously. So if the node already has a parent, the node is first removed, then appended at the new position.
Description at MDN
You have to make a separate element each time.
Try this:
var form = document.getElementById("form");
function newLi() {
return document.createElement("li");
}
newButton.addEventListener("click", function(){
//Create a separate <ul> each time, give it a class, and add it.
var newUl = document.createElement("ul");
newUl.class = "formList";
form.appendChild(newUl);
//create new <li>'s and append them
formList.appendChild(newLi());
formList.appendChild(newLi());
formList.appendChild(newLi());
//smile. :D
}
Unlike Muhammad, I assume that you want to create a separate unordered list (<ul>) each time.
Hence, whenever the button is clicked, we add a new <ul> and then append our <li>s into the new <ul>.
var form = document.getElementById("form");
var newUl = document.createElement('ul');
newUl.id = "formList";
form.appendChild(newUl);
newButton.addEventListener("click", function(){
var newLi = document.createElement('li');
newUl.appendChild(newLi);
})
You need to create the ul once, and assign to it the id = "formList", then append it to the form
On every click, create new li element
You don't need to select the ul again, because you already has a reference to it.
Here you can find a working fiddle https://jsfiddle.net/LeoAref/m5d0bzeL/
There's too much to correct in your post all at once. But if you're trying to template your LI, you can clone it using cloneNode
var template_ul = document.createElement('ul');
var template_li = document.createElement('li');
let newButton = document.getElementById('new');
var count = 0;
newButton.addEventListener("click", function() {
let list = template_ul.cloneNode();
document.getElementById('form').appendChild(list);
let first_li = template_li.cloneNode();
var text = document.createTextNode(++count);
first_li.appendChild(text);
list.appendChild(first_li);
list.appendChild(template_li.cloneNode());
list.appendChild(template_li.cloneNode());
});
body {
text-align:center;
}
button { margin: 4px auto 1em; }
ul {
margin: 0 auto 1em;
padding: 0;
width: 50%
}
ul:nth-child(2n) li{
background:#c90;
}
li {
list-style-type: none;
background: #09c;
height: 20px;
padding: 2px;
}
ul,
li {
border: 1px solid #444;
}
<button id="new">New</button>
<div id="form">
</div>
function addNode(){
var x = document.createElement("ul");
x.setAttribute("id","myList");
document.body.appendChild(x);
var myListItem = document.createElement("li");
var textNode = document.createTextNode("List Item one");
var t2 = document.createTextNode("second item");
myListItem.appendChild(textNode);
document.getElementById("myList").appendChild(newLi("FirstItem"));
document.getElementById("myList").appendChild(newLi("Second Item"));
document.getElementById("myList").appendChild(newLi("Third Item"));
document.getElementById("myList").appendChild(newLi("Fourth Item"));
}
//function which generates a new li tag and accepts a string for TextNode
function newLi(x)
{
var m = document.createElement("li");
var t = document.createTextNode(x);
m.appendChild(t);
return m;
}
So I have a div (with the id of "thecolor2") that I want to append to an unordered list, but before I append it, I want to set its background color to a variable which has the value of a hex code. However, for some reason, it doesn't take in the color.
Here is the CSS:
#thecolor2{
height: 50px;
width: 50px;
border-radius: 100px;
border: 1px solid yellow;
position: relative;
bottom: 635px;
}
Her is the HTML:
<ul id = "allposts"></ul>
And here is the JS:
var thestream = document.getElementById('allposts');
var oneofpost = document.createElement('li');
var thecolor2 = document.createElement('div');
thecolor2.id = "thecolor2";
$("#thecolor2").css("background-color", color);
thestream.appendChild(oneofpost);
thestream.appendChild(thecolor2);
You cant use a jQuery ID selector to match a node which hasn't been added to the document tree. You can simply use plain DOM to set its inline CSS style like this:
thecolor2.style.backgroundColor = color
As described by Carlo in another answer, you cannot use the jQuery selector to select elements that haven't been added. You can however, turn a created DOM element into a jQuery object by doing:
var thecolor2 = $(document.createElement('div'));
However, if you're going to be using jQuery then I suggest writing everything in jQuery, otherwise stick with using pure JavaScript for everything.
jQuery
var thestream = $('#allposts');
var oneofpost = $('<li></li>');
var thecolor2 = $('<div></div>');
thecolor2.prop('id', "thecolor2")
.css({
backgroundColor: color
}).appendTo(oneofpost);
thestream.append(oneofpost);
See jsFiddle
JavaScript
var thestream = document.getElementById('allposts');
var oneofpost = document.createElement('li');
var thecolor2 = document.createElement('div');
thecolor2.id = "thecolor2";
thecolor2.style.backgroundColor = color;
oneofpost.appendChild(thecolor2);
thestream.appendChild(oneofpost);
See jsFiddle
Also I'm assuming you're trying to append a list item to the ul, so I corrected the code you had there with appendChild.