partial input.value styling? - javascript

I have to following Code: JSFiddle – I have an HTML-input and a button. – When clicking on the button a function is being run, that changes the input.value to this text: "Black Yellow".
I would like the word Yellow to be yellow. color: yellow
I found some stuff on stack overflow, but nothing that really worked for me and from what I've read, I think this might be a bit tricky, but I really need this to work, so I would very much welcome any sort of input! – Simon
HTML
<button onclick="myFunction()"> Run </button>
<input name="input1" id="myInput">
JS
function myFunction() {
document.querySelector("#myInput").value = "Black Yellow";
}

It is not an easy task as someone else mentioned. I have done something similar in react but that is completely different from doing it in plain javascript.
Here is how you can create your own input field:
Javascript:
const input = {
element: document.getElementById("input"),
focusing: false,
value: ""
}
function checkTarget(e) {
if (e.target !== input.element){
input.focusing = false
return
}
input.focusing = true
console.log(input.focusing)
}
function handleKey(e) {
if (e.isComposing || e.keyCode === 229 || !input.focusing) {
return;
}
input.value += e.key
input.element.innerText = input.value
}
function handleClick() {
let texts = input.value.split(" ")
let span1 = document.createElement("span")
let span2 = document.createElement("span")
span1.innerText = texts[0] + " "
span2.innerText = texts[1]
span2.style.color = "yellow"
input.element.innerText = ""
input.element.appendChild(span1)
input.element.appendChild(span2)
}
document.addEventListener("click", checkTarget)
document.addEventListener("keydown", handleKey);
HTML:
<button id="button"onclick="handleClick()"> Run </button>
<div id="input">
</div>
CSS:
#input {
width: 150px;
height: 20px;
border: #777 1px solid;
border-radius: 2px;
display: inline-block;
}
Run this in your fillde and let me know if it works.
Of course, this will work if there are only 2 words present in the "input" field. For more words you will need to tweak this code.
What i had to do in react was - create a text area which shows each word in different color (rainbow input). So i created an array of all rainbow colors, created a rand function which chooses one of them and then I did a similar thing as i did here. I used map on the array i got from split(" ") and then returned a span with inline styling for the text color. And finally rendered the entire junk in the div. That was the easy part. The editing was the hard part (handling delete, backspace, tab etc). Which is when I gave up and stole a component off of github.

This is not an easy task. You can't control the word color in HTML at the moment. You need to create your own input somehow using 2 input elements. For every color an input. But as I said, it can get complicated.
function renderFakeInput(input, colors) {
input.style.display = "none";
const fakeInput = document.createElement("div");
fakeInput.classList.add("fake-input");
fakeInput.addEventListener("click", () => renderRealInput(input, colors, fakeInput));
for (const color of colors) {
const word = document.createElement("div");
word.textContent = color;
word.style.color = color;
fakeInput.appendChild(word);
}
input.parentElement.appendChild(fakeInput);
}
function renderRealInput(input, colors, fakeInput) {
const onBlur = () => {
input.removeEventListener("blur", onBlur);
renderFakeInput(input, input.value.split(" "));
};
input.style.display = "";
input.value = colors.join(" ");
input.focus();
input.addEventListener("blur", onBlur);
fakeInput.remove();
}
const colorString = "Black Yellow";
const colors = colorString.split(" ");
const inputs = Array.from(document.getElementsByClassName("multi-color"));
for (const input of inputs) {
renderFakeInput(input, colors);
}
.fake-input {
display: flex;
flex-direction: row;
}
<div>
<input class="multi-color" />
</div>
<div>
<input class="multi-color" />
</div>

Related

I am unable to apply color styles for html elements generated via createElement in javascript

Issue is: after hitting the button on the HTML page, the html <h5> tag text changes on the page but the <h5> tag text color wont change to blue (expected behavior as CSS style doesn't reload after clicking the button).
What could be a possible workaround for solving this issue?
const btn = document.querySelector(".test");
btn.addEventListener("click", () => {
a1 = document.createElement('h5');
a1.className = "first";
a1.textContent = 'Blue updated.';
document.getElementById('position').innerHTML = a1.innerText;
//newtext = document.createTextNode('abc');
});
.test {
color: blue;
}
.first {
color: blue;
}
<h5 id="position">Text Color to be replaced to blue after hitting Blue button(but not happening)</h5>
<button class="test">Change to blue</button>
Above, after the button is clicked and the action listener is triggered, the HTML <h5> tag elements code are created with a1 = document.createElement('h5'); a1.className = "first"
The new text is displayed but the color didn't change (to blue).
You're inserting only the textContent instead of appending the entire new H5 element
const btn = document.querySelector(".test");
const pos = document.querySelector('#position');
btn.addEventListener("click", () => {
const h5 = document.createElement('h5');
h5.className = "first";
h5.textContent = 'Blue updated.';
pos.innerHTML = ""; // Empty
pos.append(h5); // Append!
});
.test, .first { color: blue; }
<h5 id="position">Text Color to be replaced to blue after hitting Blue button(but not happening)</h5>
<button class="test">Change to blue</button>
PS: You can also create some nifty reusable functions to handle the DOM querying and creation of elements, using a friendly syntax:
// DOM utility functions:
const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Example:
const elPos = el('#position');
el(".test").addEventListener("click", () => {
const elH5 = elNew('H5', {
textContent: "Blue updated",
className: "first",
});
elPos.innerHTML = ""; // Empty
elPos.append(elH5); // Append!
});
.test, .first { color: blue; }
<h5 id="position">Text Color to be replaced to blue after hitting Blue button(but not happening)</h5>
<button class="test">Change to blue</button>

Split value from textarea by line break and add text indent to each of them (Javascript)

I am spliting the value from textarea by line break and add text indent to each of them.
Here is my code:
function splits() {
let textarea = document.getElementsByTagName("textarea")[0]
let arrays = textarea.value.split(/\r?\n/)
for (let i = 0; i < arrays.length; i++) {
textarea.style.textIndent = "10px"
textarea.value = "<p>" + arrays[i] + "</p>"
//not working return "<p>(The content I entered)</p>
}
}
<textarea></textarea>
<button onclick=splits()>Splits</button>
I want to make each of the elements from the arrays be in a new <p>.
However, my code above is obviously not working.
Do anyone know anyone to do this?
Thanks for any helps and responds.
This is not possible to do with a textarea. What you are looking for is an content editable div
function splits(){
const div = document.getElementById("test");
let values = div.innerText.split(/\r?\n/)
div.innerHTML = values.map(sentence => `<p>${sentence}</p>`).join("");
div.style.textIndent = "10px";
}
div#test {
width: 300px;
height: 200px;
border: 1px solid #ccc;
}
<div contenteditable="true" id="test"></div>
<button onclick=splits()>Splits</button>
You're replacing the textarea value each time through the loop, rather than appending to it.
You also don't need to set the style each time through the loop, you can do that just once.
function splits() {
let textarea = document.getElementsByTagName("textarea")[0]
let arrays = textarea.value.split(/\r?\n/)
textarea.style.textIndent = "10px"
textarea.value = arrays.map(s => `<p>${s}</p>`).join("");
}
<textarea></textarea>
<button onclick=splits()>Splits</button>

How to reset value after button click?

I'm creating a simple app in which user provides a number and square is generated with the given number. The problem is that when the user provides the input the first time, it works as intended, but when the user edits the value and clicks the button, the value adds with the existing value and it displays the square of the sums. I want to reset the input after the button click, but haven't got any clue how to do. Any solutions
The html code looks like this
<div class="intro">
<h1>Select no of squares to be made</h1>
<small>This experience is better with the values between 400 and 600</small>
<input type="number" id="squaresInput">
<button class="show">Go</button>
</div>
And js file is
const userInput = document.getElementById('squaresInput')
const btnInput = document.querySelector('.show')
btnInput.addEventListener('click', () => getUserInput())
let squaresNum
function getUserInput(){
let squaresNum = userInput.value
for(let i = 0; i < squaresNum; i++){
const square = document.createElement('div')
square.classList.add('square')
square.addEventListener('mouseover', () => setColor(square))
square.addEventListener('mouseout', () => removeColor(square))
container.appendChild(square)
}
}
This should work for you :
userInput.value = ''
I'd start moving
const userInput = document.getElementById('squaresInput')
into "getUserInput()" function.
Then removing the "let squaresNum" outside the function, it is useless.
Gianluca
You can just add userInput.value = ""; at the end of function, which will clear out any existing value in the input.
const userInput = document.getElementById('squaresInput')
const btnInput = document.querySelector('.show')
btnInput.addEventListener('click', () => getUserInput())
let squaresNum;
function getUserInput(){
let squaresNum = userInput.value
for(let i = 0; i < squaresNum; i++){
const square = document.createElement('div')
square.classList.add('square')
square.addEventListener('mouseover', () => setColor(square))
square.addEventListener('mouseout', () => removeColor(square))
container.appendChild(square)
}
userInput.value = "";
}
<div class="intro">
<h1>Select no of squares to be made</h1>
<small>This experience is better with the values between 400 and 600</small>
<input type="number" id="squaresInput">
<button class="show">Go</button>
<div class="container"></div>
</div>
You need something like this before adding more squares.
container.innerHTML = ""
at the beginning of
function getUserInput () {....
In this way you will eliminate the squares previously created before creating the new ones.
Take advantage of using <form>.
Change <div class='intro'> to <form id='intro'>
Whatever .container is change it to <fieldset id='container'> or name='container'. If you don't want the border, in CSS .container {border:0;}
Now you just register the 'submit' event to the <form>
When any <button>, <input type='submit'>, or <button type='submit'> is clicked or a form control has focus and user keys Enter/Return the 'submit' event is triggered.
event.preventDefault() is to stop the <form> from trying to send data to a server.
this.reset(); will clear the <input>
Unless setColor() and removeColor() do more than just change div.square color, it's better just to use CSS. .square {border-color: red; background: red}
Using a <form> allows you to use the HTMLFormControlsCollection and HTML Forms API. It's terse and specific which allows more control and less coding.
// Reference a `<form>`
const f = document.forms['id'] /*OR*/ document.forms.id // name can be used as well
// Reference all form controls within <form>
const io = f.elements;
// Reference a form control within <form>
const btn = io['id'] /*OR*/ io.id // name can be used as well
Use createDocumentFragment(); because 400 to 600 nodes to render is really too much.
Also added a <button> to clear out the squares whenever the user wishes to.
Added 'mouseover/out' event handler. It's registered to the parent element only and not to each .square. This and the 'submit' event are possible because of Event Bubbling and how Event Delegation leverages it.
In the event handler hoverGrid() values, expressions, statements, and functions (ex. addColor() and removeColor()) can be placed within the appropriate case of the switch().
...
case 'mouseover':
addColor();
break;
case 'mouseout':
removeColor();
break;
...
const I = document.forms.intro;
const io = I.elements;
const clr = io.clr;
const box = io.box;
I.onsubmit = createGrid;
clr.onclick = clearGrid;
box.onmouseover = hoverGrid;
box.onmouseout = hoverGrid;
function createGrid(event) {
event.preventDefault();
let cnt = parseInt(io.qty.value);
let frag = document.createDocumentFragment();
for (let i = 0; i < cnt; i++) {
let square = document.createElement('div');
square.className = 'square';
square.dataset.index = i + 1;
frag.appendChild(square);
}
box.appendChild(frag);
this.reset();
console.clear();
console.log(box.childElementCount);
};
function clearGrid(event) {
this.previousElementSibling.innerHTML = '';
};
function hoverGrid(event) {
let E = event.type;
const sqr = event.target;
if (sqr.matches('.square')) {
switch (E) {
case 'mouseover':
console.log(sqr.dataset.index);
break;
case 'mouseout':
console.clear();
break;
default:
break;
}
}
};
:root {
font-size: 16px;
}
body {
font-family: Consolas;
line-height: 1;
overflow: auto;
}
input,
button {
display: inline-block;
font: inherit
}
small {
display: block;
margin-bottom: 4px;
}
button {
width: 4ch;
padding: 2px 5px;
cursor: pointer;
}
#box {
display: flex;
flex-flow: row wrap;
max-width: 96vw;
height: max-content;
}
.square {
width: 1ch;
height: 1ch;
border: 1px solid black
}
.square:hover {
border-color: red;
background: red;
}
#clr {
width: 9ch;
float: right;
}
/* SO Console Display - Rightside Column */
.as-console-wrapper {
width: 20% !important;
font-variant: normal;
font-weight: bold;
color: red;
}
.as-console-row.as-console-row::after {
content: '';
padding: 0;
margin: 0;
border: 0;
width: 0;
}
<form id="intro">
<fieldset>
<legend>Select no. of squares to be made</legend>
<small>This experience is better with the values between 400 and 600</small>
<input type="number" id="qty" min='0' max='1000'>
<button>GO</button>
</fieldset>
<fieldset id='box'></fieldset>
<button id='clr' type='button'>CLEAR</button>
</form>

JavaScript and css: highlight multiple words all with same background

I'm trying to make a basic web application where people can highlight multiple words (i.e., click on the first word, then click on a word further on, and everything will be highlighted, even on another line).
So far I was able to wrap all of the words in tags and set a click event listener to each one which changes it's className to "highlight" which is just background-color:yellow.
The problem is that only the background of that individual word is highlighted, but i want everything in between the two (or more, even on different lines) words to be highlighted.
To complicate things a little more, i also have punctuation and maybe other stuff inbetween the words, which are not surrounded by span tags, but I want everything between the words to have a different background color/ be selected.
I was thinking of just putting the necessary words that are selected in they're own, separate span tag, but then, I'm not sure how to make it dynamically change exactly, and i also want the user to save the selections and then re-select them with a button or something, so that means that one word could be in 2 different phrases, and I'm not sure how one word could be in two different span tags....
So basically: how can I select multiple words in JavaScript including highlighting everything inbetween the two words?
EDIT
There was a request for some of the code I've tried, so I've attempted to simplify the relevant sections:
var h= eid("HebrewS");
var currentPhrase=[];
var equal=false;
var shtikles = [
];
h.innerHTML = h.innerHTML.replace(/([\u0590-\u05FF\"\']+)/g,'<span class="shtikle""">$1</span>');
var words = q("#HebrewS span");
words.forEach(function(item, idx){
shtikles[idx] = {obj:item, id:idx, heb:item.innerHTML, translation:"means "+ idx};
item.addEventListener("click", function(e) {
if(currentPhrase.length == 0) {
currentPhrase.push(idx);
currentPhrase[1]=idx;
equal=true;
}
else {
currentPhrase[1]=idx;
if(currentPhrase[1] < currentPhrase[0]) {
currentPhrase.reverse();
}
if(currentPhrase[0]==currentPhrase[1])
if(!equal) {
equal=true;
} else {
currentPhrase = new Array();
equal=false;
}
else
equal=false;
}
selectPhrase(currentPhrase);
});
function selectPhrase(p) {
for(var i =0;i<shtikles.length;i++) {
if(shtikles[i].obj)
if(p.length > 0) {
if(i < p[0] || i > p[1]) {
if(shtikles[i].obj.className != "shtikle") {
shtikles[i].obj.className ="shtikle";
}
}
} else {
shtikles[i].obj.className = "shtikle";
}
}
for(var i = p[0]; i <= p[1]; i++) {
shtikles[i].obj.className="phrasePart";
}
}
function q(a) {
return document.querySelectorAll(a);
}
function eid(id) {
return document.getElementById(id);
}
Now for the html:
<div style="" id ="HebrewS">today I will show,. you how] to read.. {Maamarim! וחזקת והיית לאיש1, הנה ידוע2 שהמאמר שאמר אדמו"ר (מהורש"ב) נ"ע ביום השביעי3 דחגיגת הבר מצוה של בנו יחידו כ"ק מו"ח אדמו"ר, י"ט תמוז4 תרנ"ג [שמאמר זה הוא סיום וחותם ההמשך תפילין דמארי עלמא5 שהתחיל לומר בי"ב תמוז, יום הבר מצוה] היתה התחלתו בפסוק זה. – השייכות דפסוק זה (וחזקת והיית לאיש) לבר מצוה בפשטות היא, ע"פ הידוע6 דזה שבן שלש עשרה (דוקא) מחוייב במצוות הוא כי אז דוקא נק' בשם איש. וצריך להבין, דמכיון שבן י"ג שנה נעשה איש (ע"פ טבע), מהי ההדגשה לומר (בחגיגת בר מצוה) וחזקת והיית לאיש. וגם צריך להבין, הרי המעלה דבן י"ג שנה היא שאז נעשה בר דעת7, דדעת הוא במוחין, ובפרט לפי המבואר בהמאמר ד"ה איתא במדרש תילים תרנ"ג [שהוא אחד המאמרים שחזר אותם כ"ק מו"ח אדמו"ר בחגיגת הבר שלו]8 שהמעלה דבן י"ג שנה היא שאז יש לו עצם המוחין9, ומהו הדיוק בבן י"ג שנה בהתואר איש שמורה10 על המדות
Now css:
<style type="text/css">
.shtikle:hover{
background-color:yellow;
}
.phrasePart{
background-color: purple;
border: 0px solid black;
}
</style>
I haven't tested the simplified version of the code, but if you try it out should work.
The basic point is :it selects each word individually, but doesn't highlight the stuff between the words (and I don't want to put all of the words in the current phrase into they're own span, because I want to save the phrase and have it selectable later, and also with multiple phrases some words might be in both)
Split everything into single nodes and then work with ranges. Simple implementation might look like below. It works on two clicks (right click removes selections) and is ready to implement click and slide (you'll have to implement mouseenter event listener with some boolean flag). So the point is that after every click id of each node is checked and either it becomes starting point of a range or closes the range with a for loop that adds class for every node in between.
You might then store id ranges somewhere there and activate them on eg. button click.
//EDIT
check edit below, this is totally messy, but I believe it should fit your needs.
const txt = 'this is some word in a wordy place where all words are kind of, well... this is some word in a wordy place where all words are kind of something so: this is some word in a wordy place where all words are kind of, and then -> this is some word in a wordy place where all words are kind of nothing';
let startIndex = null;
let lines = document.querySelector('.lines');
lines.innerHTML = txt.split(' ').map((z, i) => {
return (z.replace(new RegExp("\\w+|\\W+", "g"), (t) => { return /\w+/.test(t) ? `<span data-id="${i}" data-word>${t}</span>` : `<span data-id="${i}">${t}</span>` }));
}).join(' ');
nodes = Array.prototype.slice.call(document.querySelectorAll('.lines span'));
nodes.forEach(z => {
if(z.hasAttribute('data-word')) {
z.addEventListener('mousedown', (e) => {
const id = Number(e.target.getAttribute('data-id'));
if (startIndex === null) {
startIndex = id;
e.target.classList.add('active');
} else {
const range = id > startIndex ? [startIndex, id] : [id, startIndex];
for(let i = range[0]; i<= range[1]; i++) {
(Array.prototype.slice.call(document.querySelectorAll('span[data-id="' + i + '"]'))).forEach(e => e.classList.add('active'));
};
startIndex = null;
}
});
}
});
window.oncontextmenu = function ()
{
startIndex = null;
nodes.forEach(z => z.classList.remove('active'))
return false;
}
.lines {
user-select: none;
}
.lines span {
display: inline-block;
padding:3px;
box-decoration-break: clone;
transition:.2s;
}
.lines span.active {
background: salmon;
box-shadow: 3px 0 0 salmon, -3px 0 0 salmon;
}
[data-word] {
cursor:pointer;
}
<div class="lines"></div>

Replacing multiple CSS color values simultaneously

I am making a website where the user can select the colors of the page. The site is using only two colors. A background color and a color for everything else. (Text, Borders and background colors in separate boxes.)
I try to get spectrum.js to change all colors other than the background color and text over the colored boxes.
I am trying to modify the code found here by ariel.
var initialColor = "#E84E1B";
$("body").css("color", initialColor);
$("divwithfill").css("border-color", initialColor);
function updateColor(element, color) {
$(element).css("color", (color ? color.toHexString() : ""));
}
$("#colorChanger").spectrum({
color: initialColor,
move: function (color) {
updateColor(".output.render", color);
},
hide: function (color) {
updateColor(".output.render", color);
}
});
Fiddle:
http://jsfiddle.net/mjHUD/31/
This is a copy of a fiddle found of here. I am trying to change all off the #E84E1B values to the color chosen by the user.
EDIT:
To specify: I want the user to be able to use #colorChanger to change all CSS values that are # E84E1B by default. (Includes background-color and border) All CSS values with # c6c6c6 I want to be unchanged. I hope this makes more sense.
So the problem is that you can't actually select elements by their css values, but you can access the stylesheets attached to the document and do some pretty funky things with them.
A little bit of a different method here. No extra classes have to be added. No external libraries required. Basically...
Loop through every stylesheet attached to the document.
Loop through every rule in those stylesheets.
Loop through every property in those rules.
Test the value of each property against the input string.
If the value matches the input string
Set the value of the property to the new color.
When the looping is done, return the input color to save it so we can start all over again.
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
rgb = 'rgb(';
rgb += parseInt(result[1], 16) + ", ";
rgb += parseInt(result[2], 16) + ", ";
rgb += parseInt(result[3], 16) + ')';
return rgb;
}
var initialColor1 = hexToRgb("#C6C6C6");
var initialColor2 = hexToRgb("#E84E1B");
function chameleon(hex, initial) {
var rgb = hexToRgb(hex);
var stylesheets = document.styleSheets, stylesheet, i;
for (i = 0; (stylesheet = stylesheets[i]); i++) {
var rules = stylesheet.cssRules, rule, j;
if(!rules) continue;
for(j = 0; (rule = rules[j]); j++) {
var styles = rule.style, style, k;
for(k = 0; (style = styles[k]); k++) {
var value = styles.getPropertyValue(style);
if(initial == value) {
styles.setProperty(style, rgb);
}
}
}
}
return rgb;
}
document.getElementById('picker1').oninput = function(e) {
initialColor1 = chameleon(e.target.value, initialColor1);
}
document.getElementById('picker2').oninput = function(e) {
initialColor2 = chameleon(e.target.value, initialColor2);
}
body { background-color: #C6C6C6; color: #E84E1B;}#divwithfill { height: 50px; width: 50px; border: solid 1px #E84E1B; background-color: #E84E1B; color: #C6C6C6; }#divnofill { height: 50px; width: 50px; border: solid 1px #E84E1B;}
<span class="output render" id="text1">sample text</span>
<div id="divwithfill">sample text</div>
<div id="divnofill">sample text</div>
<label for="picker1">Color #1: <input type="color" id="picker1" value="#C6C6C6"></label><br>
<label for="picker2">Color #2: <input type="color" id="picker2" value="#E84E1B"></label>
I've got a solution for you that might be easier just using plain old javascript and css. demo
Some example html:
<div id="container">
<div class="box changeable">
Sample Text
</div>
<br />
<div class="box unchangeable">
Sample Text
</div>
</div>
<div>border<input id="border-colorer" type="color" /></div>
<div>text<input id="text-colorer" type="color" /></div>
<div>background<input id="background-colorer" type="color" /></div>
Set up your css like this to inherit colors from the container:
#container .changeable {
background-color:inherit;
color:inherit;
border-color:inherit;
}
.box {
border-width:1px;
border-style:solid;
}
Then set up listeners for the color-selects which will set the style on just the container.
var parent = document.getElementById('container');
var changeable = container.querySelectorAll('.changeable');
document.getElementById('border-colorer').addEventListener('change', function(e) {
[].forEach.call(changeable, function(el){
el.style['border-color'] = e.target.value;
})
});
document.getElementById('text-colorer').addEventListener('change', function(e) {
[].forEach.call(changeable, function(el){
el.style.color = e.target.value;
})
});
document.getElementById('background-colorer').addEventListener('change', function(e) {
[].forEach.call(changeable, function(el){
el.style['background-color'] = e.target.value;
})
});
Now when you change the color in a select, the style will be set on the only the changeable elements in the container.

Categories