Manipulate Pseudo Elements with Custom Fields - javascript

What I need to do is similar to this post, but I need the user to be able to change the Pseudo Element using a custom field. Still learning JavaScript and this has been a struggle!
User needs ability to change ~ border-right: 500px solid #4679BD;
The custom field is ~ $angle = get_field('contact_angle_color');
Here is my code without my failed JavaScript attempts:
.relative-wrap {
position: relative;
min-height: 150px;
}
.triangle-down-right {
width: 50%;
height: 0;
padding-top: 54%;
overflow: hidden;
position: absolute;
top: 0;
right: 0;
}
.triangle-down-right:after {
content: "";
display: block;
width: 0;
height: 0;
margin-top:-500px;
border-top: 500px solid transparent;
border-right: 500px solid #4679BD;
}
<div class="triangle-down-right"></div>

I could not understand the part about custom field, but if you are planning on having unlimited control over pseudo-elements, well, good luck with that. Currently, manipulating pseudo-elements with Javascript is possible through injecting inline css into DOM as described in this post, but it is not recommended unless, of course, you absolutely have to.
So, the other way to change pseudo-elements is to add/remove/modify class names on the element. Please see the example code below and the JSFiddle: https://jsfiddle.net/9w4d6mts/
HTML:
<input type="button" id="direction" value="Change Direction">
<br>
<input type="button" id="color" value="Change Color">
<div id="demo" class="triangle-down-right alt"></div>
CSS:
.relative-wrap {
position: relative;
min-height: 150px;
}
.triangle-down-right,
.triangle-down-left {
width: 50%;
height: 0;
padding-top: 54%;
overflow: hidden;
position: absolute;
top: 0;
right: 0;
}
.triangle-down-right:after,
.triangle-down-left:after {
content: "";
display: block;
width: 0;
height: 0;
margin-top:-500px;
border-top: 500px solid transparent;
}
.triangle-down-right:after {
border-right: 500px solid #4679BD;
}
.triangle-down-left:after {
border-left: 500px solid #4679BD;
}
.triangle-down-right.alt:after,
.triangle-down-left.alt:after {
border-color: transparent #D4679B transparent;
}
JS:
document.getElementById('direction').addEventListener('click', function(){
var d = document.getElementById('demo');
d.className = (d.className.replace(' alt','') === "triangle-down-right") ? d.className.replace('right','left') : d.className.replace('left','right');
});
document.getElementById('color').addEventListener("click", function(){
var d = document.getElementById('demo');
console.log(d.className);
d.className = (d.className.slice(-3) === "alt") ? d.className.replace(' alt','') : d.className + ' alt';
});
Basically, we are preparing the classes in CSS beforehand and switch them with Javascript based on user interaction. That's it.

Related

"Progress" bar with both value and acceptable ranges

Here is exhaustive topic on SO about how to create progress bar. I would like to improve this "widget" to display acceptable range markers. It may be vertical lines or something else.
For example, value range may be [-50;50], but acceptable range is [-25;25]. So can someone point me out how to modify, for example, the first answer from topic mentioned above to get what I described here.
Here is first suggested answer from the topic:
#progressbar {
background-color: black;
border-radius: 13px;
/* (height of inner div) / 2 + padding */
padding: 3px;
}
#progressbar>div {
background-color: orange;
width: 40%;
/* Adjust with JavaScript */
height: 20px;
border-radius: 10px;
}
<div id="progressbar">
<div></div>
</div>
Here is how I see my widget. Red parts of bar - acceptable range.
Clarification
So firstly, as mentioned in my comment, this doesn't really sound like a progress bar. As implied by the name, progress bars are meant to show progress, and so things like negative values don't make sense.
It sounds like you want something like the HTML Range Input, though you mentioned you only want to display data (which you could still technically do by setting the disabled attribute on a range input).
Possible Solution
Ultimately it looks like you just want CSS to display a range (not a progress bar). This can be achieved with pure CSS, but I should mention there are a few quirks based on the requirements you have outlined.
You could set all the values by hand, based on whatever range and value you wish to display, but I assume this isn't desirable. So the next thing to do would be to utilize CSS variables and the CSS calc() function to set everything for you (based on some initial data).
The one weird thing is displaying the text for things like the range and values. Because we are using CSS variables to hold our values and perform calculations, it would be nice to use those same values to display the text. But CSS variables cannot be converted between types and so a value of say 2 is a number (not text or a string), and this means the value of 2 cannot be displayed as text using the CSS content property. Because of this I have 2 sets of variables. The first set is the number, used for calculations to set the widths. The second set is the -text version, used to display the text under your range bar.
.rangeBar {
background: #EEE;
height: 2em;
padding: .2em;
border: 1px solid #CCC;
border-radius: 1em;
box-sizing: border-box;
position: relative;
--min-value: 0;
--min-value-text: '0';
--max-value: 4.5;
--max-value-text: '4.5';
--min-range: 1;
--min-range-text: '1';
--max-range: 3;
--max-range-text: '3';
--value: 2;
--value-text: '2';
}
.rangeBar::before {
content: var(--min-value-text);
position: absolute;
top: 100%;
left: 0;
color: #888;
}
.rangeBar::after {
content: var(--max-value-text);
position: absolute;
top: 100%;
right: 0;
color: #888;
}
.rangeBar .value {
background: #0A95FF;
width: calc(var(--value)/var(--max-value)*100%);
height: 100%;
border-radius: 1em;
position: relative;
z-index: 1;
}
.rangeBar .value::after {
content: var(--value-text);
position: absolute;
top: 100%;
right: 0;
color: #888;
}
.rangeBar .minRange {
background: #E74C3C;
width: calc(var(--min-range)/var(--max-value)*100%);
height: 100%;
border-radius: 1em;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.rangeBar .minRange::after {
content: var(--min-range-text);
position: absolute;
top: 100%;
right: 0;
color: #888;
}
.rangeBar .maxRange {
background: #E74C3C;
width: calc((var(--max-value) - var(--max-range))/var(--max-value)*100%);
height: 100%;
border-radius: 1em;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.rangeBar .maxRange::after {
content: var(--max-range-text);
position: absolute;
top: 100%;
left: 0;
color: #888;
}
<div class="rangeBar">
<div class="minRange"></div>
<div class="value"></div>
<div class="maxRange"></div>
</div>
Additional Notes
There are possibly a few ways to simplify the CSS for this and automatically take care of some of the issues with this, but would require JavaScript (which is outside of the scope of this question). There has been no indication as to how any of the data or values for this range bar will be set, and so JavaScript was avoided for this question.
EDIT
Because OP updated the original question to include JavaScript, I am adding an additional solution. This mostly works the same but instead uses a JavaScript function called _CreateRange that takes 5 parameters (min value, max value, min range, max range, and value) and creates a new element on the page that uses those parameters/values. This makes things a little simpler as you only need to enter those values once (rather than once for the number value and once for the text value) and you can also use this to dynamically create or load ranges on the page (depending on where the data for these ranges is coming from).
// These are just example values you can modify
let value = 2,
minValue = 0,
maxValue = 4.5,
minRange = 1,
maxRange = 3;
const _CreateRange = (mnV, mxV, mnR, mxR, v) => {
let r = document.createElement("div");
r.className = "rangeBar";
r.innerHTML = `<div class="minRange"></div><div class="value"></div><div class="maxRange"></div>`;
r.style.setProperty("--min-value", mnV);
r.style.setProperty("--min-value-text", JSON.stringify(mnV+""));
r.style.setProperty("--max-value", mxV);
r.style.setProperty("--max-value-text", JSON.stringify(mxV+""));
r.style.setProperty("--min-range", mnR);
r.style.setProperty("--min-range-text", JSON.stringify(mnR+""));
r.style.setProperty("--max-range", mxR);
r.style.setProperty("--max-range-text", JSON.stringify(mxR+""));
r.style.setProperty("--value", v);
r.style.setProperty("--value-text", JSON.stringify(v+""));
document.querySelector("#bar").append(r);
}
// This is where the function to create the range is called
// We are using our default example values from earlier, but you can pass in any values
_CreateRange(minValue, maxValue, minRange, maxRange, value);
.rangeBar {
background: #EEE;
height: 2em;
padding: .2em;
border: 1px solid #CCC;
box-sizing: border-box;
position: relative;
margin: 0 0 2em;
}
.rangeBar::before {
content: var(--min-value-text);
position: absolute;
top: 100%;
left: 0;
color: #888;
}
.rangeBar::after {
content: var(--max-value-text);
position: absolute;
top: 100%;
right: 0;
color: #888;
}
.rangeBar .value {
background: #0A95FF;
width: calc(var(--value)/var(--max-value)*100%);
height: 100%;
position: relative;
z-index: 1;
}
.rangeBar .value::after {
content: var(--value-text);
position: absolute;
top: 100%;
right: 0;
color: #888;
margin: .2em 0 0;
}
.rangeBar .minRange {
background: #E74C3C;
width: calc(var(--min-range)/var(--max-value)*100%);
height: 100%;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.rangeBar .minRange::after {
content: var(--min-range-text);
position: absolute;
top: 100%;
right: 0;
color: #888;
}
.rangeBar .maxRange {
background: #E74C3C;
width: calc((var(--max-value) - var(--max-range))/var(--max-value)*100%);
height: 100%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.rangeBar .maxRange::after {
content: var(--max-range-text);
position: absolute;
top: 100%;
left: 0;
color: #888;
}
<div id="bar"></div>

JavaScript and CSS not working as intended

In the following code, when I put the div with class thumb-bar, the JavaScript I have written works but if place use it after full-img div tag, it doesn't work also the CSS attribute cursor: pointer for the thumb-bar div is not applied.
Edit - I mean the click listeners I apply using JavaScript are not working
CSS:
body {
width: 640px;
margin: 0 auto;
}
.full-img {
position: relative;
display: block;
width: 640px;
height: 480px;
}
button {
border: 0;
background: rgba(150, 150, 150, 0.6);
text-shadow: 1px 1px 1px white;
border: 1px solid #999;
position: absolute;
cursor: pointer;
top: 2px;
left: 2px;
}
.thumb-bar img {
display: block;
width: 20%;
float: left;
cursor: pointer;
}
HTML:
<div class="thumb-bar"></div>
<div class="full-img">
<img class="displayed-img" src="images/pic1.jpg">
<button class="dark">Darken</button>
</div>
JavaScript:
var displayedImage = document.querySelector('.displayed-img');
var thumbBar = document.querySelector('.thumb-bar');
btn = document.querySelector('button');
var overlay = document.querySelector('.overlay');
for (var i = 1; i <= 5; i++) {
var newImage = document.createElement('img');
newImage.setAttribute('src', 'images/pic' + i + '.jpg');
thumbBar.appendChild(newImage);
newImage.addEventListener('click', function(e) {
displayedImage.setAttribute('src', e.target.getAttribute('src'))
});
}
Because you're floating .thumb-bar img, those images are taken out of the page flow which results in the .thumb-bar element to have a height of 0, which in turn causes subsequent content to not be pushed down. That means that the .full-img element is rendered on top of the images and obscures them from the mouse pointer.
You need to clear the floats in order to get the .full-img element to render below them. This can be done by either making sure the .thumb-bar clear it's own content:
.thumb-bar {
overflow: hidden;
}
... or make the .full-img element itself clear them:
.full-img {
clear: both;
}

How to give triggers to input field

I have a inputfield and I need to give two trigger. One is dropdown arrow and Another is cancel ("X") image. Here I am creating my inputfield.
My JS
var input = document.createElement("input");
input.className = 'styled-select';
input.style = 'width:30%' ;
input.id = "SearchInput";
input.type = "text";
input.title = "Madd";
input.onclick = TableExpand; // This happening when I clicking on Inputfield
My CSS for Inputfield
* {
box-sizing: border-box;
}
.styled-select {
width: 100px;
height: 20px;
border: 1px solid #95B8E7;
background-color: #fff;
vertical-align: middle;
display: inline-block;
overflow: hidden;
white-space: nowrap;
margin: 0;
padding: 0;
overflow: hidden;
overflow: -moz-hidden-unscrollable;
background: url(combo_arrow.png) no-repeat right white;
position:relative;
border-radius: 5px 5px 5px 5px;
}
.styled-select select {
background: transparent;
-webkit-appearance: none;
width: 100px;
font-size: 11px;
border: 0;
height: 17px;
position: absolute;
left: 0;
top: 0;
}
I need two trigger as I mentioned Arrow and Cross. I am able to give arrow by using background image but don't know how to give Cross image.
Also How I will use this as a trigger. I mean When I click on Cross and Dropdown one it leads me to the one function where I can write my code.
You can put the triggers as absolutely positioned elements on the input field. This way, you can add separate click events on these triggers to be able to perform whatever you want when they are clicked.
Here is an example of what you are trying to achieve:
HTML:
<div id="container">
<input type="text" id="textfield" />
<div id="triggers">
<img class="trigger" src="https://cdn3.iconfinder.com/data/icons/musthave/128/Stock%20Index%20Up.png" id="arrow" />
<img class="trigger" src="https://cdn3.iconfinder.com/data/icons/musthave/128/Remove.png" id="cross" />
</div>
</div>
CSS:
#container {
position: relative;
width: 600px;
}
#textfield {
height:30px;
width: 100%;
}
.trigger{
width: 20px;
}
#triggers {
position: absolute;
right: 0px;
top: 5px;
}
JS:
$(document).ready(function() {
$("#arrow").click(function() {
$("#textfield").val("Arrow was clicked.");
})
$("#cross").click(function() {
$("#textfield").val("Cross was clicked.");
})
})
Here is a working version:
https://jsfiddle.net/1j760ztn/
Your cross and dropdown should be separate buttons. And the javascript you need to listen for them goes like this.
<input type="text" id="theText"><button id="cross"><button id="dropdown">
<script> var cross = document.getElementById('cross'); cross.addEventListener("click", function(){ document.getElementById('theText').innerHTML = 'clicked X' }); </script>

Mouseover popup speech bubble

I'm new to javascript/css and would like to make a version of a mouseover popup similar to the one that displays over the underlined words here: http://st.japantimes.co.jp/essay/?p=ey20141219
I can see the code that is used, but I'm not sure where/how to add in my own speech bubble image when I edit the code for my own project.
Here is an example of the code used on the referenced page:
HTML:
<a style="cursor:pointer;" onclick="showChuPopup(event,'<b>’Twas</b><br />It was の省略');return false;" onmouseover="showChuPopup(event,'<b>’Twas</b><br />It was の省略');" onmouseout="endChuPopup();">’Twas</a>
Javascript:
function showChuPopup(e,text){
if(document.all)e = event;
var obj = document.getElementById('chu_popup');
var obj2 = document.getElementById('chu_popup_text');
obj2.innerHTML = text;
obj.style.display = 'block';
var st = Math.max(document.body.scrollTop,document.documentElement.scrollTop);/*
if(navigator.userAgent.toLowerCase().indexOf('safari')>=0)st=0;*/
var leftPos = e.clientX - 100;
if(leftPos<0)leftPos = 0;
obj.style.left = leftPos + 'px';
obj.style.top = e.clientY - obj.offsetHeight -1 + st + 'px';} function endChuPopup() {
document.getElementById('chu_popup').style.display = 'none';} function touchHandler(e){
document.getElementById('chu_popup').style.display = 'none';}
Thanks for any help or ideas.
There are a few ways to go about this, but I'll recommend two options and provide links to both!
First, check out the answer on this question to see if this is what you want:
jQuery Popup Bubble/Tooltip
Second, have you thought about just using a tooltip with CSS? They're not hard to implement at all, and you can absolutely bind data to them.
(Shamelessly stolen from: https://www.w3schools.com/css/css_tooltip.asp, I would recommend poking around here and also looking into Bootstrap if you're a beginner!)
<style>
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
top: 150%;
left: 50%;
margin-left: -60px;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent black transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
}
</style>
<div class="tooltip">Hover over me
<span class="tooltiptext">Tooltip text</span>
</div>

Body won't scroll when dynamic content added

Live link here: http://tbremer.com/
Try Architecture or Concert to see problem
My issue is that when my images are added the viewport doesn't scroll or extend to allow for the new content.
I need to understand what the root issue is here and hopefully find a work around.
Thanks!
OK, sorry here is the pertinent code.
CSS:
/* Content Wrapper */
#contentWrapper {
padding: 0px;
margin: 0px;
width: 100%;
height: 99%;
z-index: 0;
border: 0px solid #600;
}
/* Image Viewer */
#imageViewer{
position: fixed;
left: 0px;
top: 0px;
padding: 0px;
padding-left: 350px;
margin: 0px;
border: 0px solid #F0F;
visibility: hidden;
}
.portImage {
padding: 0;
margin: 4px;
border: 1px solid #000;
display: inline;
}
HTML:
<div id="contentWrapper">
<div id="imageViewer"></div>
</div>
JAVASCRIPT:
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
$("#imageViewer").empty();
$("#imageViewer").css("visibility", "hidden");
//___ Get server response.
var responseArray = xmlhttp.responseText.split(',');
responseArray.pop();
//console.log(responseArray.length);
//console.log(responseArray);
for(var i=0;i<responseArray.length;i++){
$("#imageViewer").append("\
<div id='portImage"+i+"' class='portImage'>\
<img src='"+responseArray[i]+"' height='500'>\
</div>\
");
}
$(".portImage").each(function() {
var image = $("<img />").attr('src', this);
});
//$("#imageViewer").append("Test");
$("#imageViewer").css("visibility", "visible");
}
}
Position:Absolute on the imageViewer not fixed. That is all you have to change.
You need to remove the height from #contentWrapper and position: fixed from #imageViewer.
(And please post your code here.)

Categories

Resources