Why is text entered into a contenteditable element reversed? - javascript

Describe the issue/behavior that seems buggy
❌ when typing it adds the text/code in reverse when typing.
Sample Code or Instructions to Reproduce
when using contendeditable attribute in the <code> HTML tag element.
<pre>
<code contenteditable="true"></code>
</pre>
with an input event listener
and using this js library https://highlightjs.org/ for syntax highlighting
const code = document.querySelector("code");
code.addEventListener("input", () => {
hljs.highlightElement(code); // this came from this js library https://highlightjs.org/
// other code logic (mostly saving to localStorage)
}
like you saw in every typed letter I will add the highlight functionality,
but seems that completely breaks the typing direction
and yes, input events also work for not <input> tags if they have that attribute (contenteditable)
docs: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event
source code:
https://jsfiddle.net/20zpL5bk/
also another bug is that we can't go down the line break. (only if there is hljs.highlightElement(code);)
✅ here without hljs.highlightElement(code); is super fluid and can't do everything (but not syntax highlight):
(how can I have fluid, normal writing with also syntax highlighting in real-time (input event)?
is my code wrong for some reason?)
Expected behavior
✅ how should be: <div></div> or hello world
❌ how it is now: >vid/<>vid< or dlrow olleh
Additional context
I tried to write the code in reverse myself manually >vid/<dlrow olleh>vid<, and yes the highlighting works.
but the direction is always the wrong way. (also deleting isn't possible)
another interesting thing is if you copy and paste (CTRL+V) the correct code <div>hello world</div> it works fine. (but still remain in the same line, no multiple lines)
also the cursor of the input doesn't move with the text but remains at the start
source code:
https://jsfiddle.net/20zpL5bk/
let inputs = document.querySelectorAll("textarea");
let langs = ["html", "css", "javascript"];
let outputs = document.querySelectorAll("code");
outputs.forEach((code, index) => {
// ✅ make it like input
code.contentEditable = "true";
// ✅ if there is some code from localStorage we add it to the website.
code.innerHTML = localStorage.getItem(`${langs[index]}`) || "";
// ✅ styling of your library (work great when app start)
hljs.highlightElement(code);
code.addEventListener("input", () => {
localStorage.setItem(`${langs[index]}`, code.innerHTML);
// ❌ why the typing is reversed here?
// if the next line isn't there then it work fine, otherwise it will change the values to reversed
hljs.highlightElement(code);
// console.log
// example to type <div></div>
// what I get >vid/<>vid<
});
});
body {
--gap: 2vmin;
margin: 0;
height: 100vh;
}
#container {
display: flex;
height: 100%;
gap: var(--gap);
padding: var(--gap);
box-sizing: border-box;
}
#container>* {
flex: 1;
display: grid;
grid-template-rows: auto 1fr;
gap: var(--gap);
}
code {
overflow: auto;
white-space: pre;
border: 0.2rem solid;
border-radius: 0.5rem;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="container">
<div>
<span>HTML</span>
<code class="language-html" style="border-color: orange;"></code>
</div>
<div>
<span>CSS</span>
<code class="language-css" style="border-color: blue;"></code>
</div>
<div>
<span>JS</span>
<code class="language-js" style="border-color: yellow;"></code>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/default.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<script src="./script.js"></script>
</body>
</html>

Related

How to change canvas style on tsParticles.js

I'm trying to change position and dimensions of the canvas but it's set as inline code with !important added, editing style attribute is instantly changed to original styling.
There is fullscreen option but it doesn't change anything for me: docs.
I've spend a lot of time trying to change it with no luck.
Simple example showing issue:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>tsParticles</title>
<style>
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background-color: #212121;
}
#tsparticles {
width: 200px;
height: 200px;
position: absolute;
}
</style>
</head>
<body>
<div id="tsparticles"></div>
<script
src="https://cdn.jsdelivr.net/npm/tsparticles-preset-bubbles#2/tsparticles.preset.bubbles.bundle.min.js"></script>
<script>
(async () => {
await loadBubblesPreset(tsParticles); // this is required only if you are not using the bundle script
await tsParticles.load("tsparticles", {
autoPlay: false, //works
// FullScreen: false, //nothing changes
FullScreen: { enable: false, zIndex: 99 }, ////nothing changes
preset: "bubbles",
});
})();
</script>
</body>
</html>
`
I've tried changing inline styling and find a way to set it in config. Version v1 was sized according to its parent. With version v2 I'm stuck and out of ideas.
The property for disabling the full screen options is fullScreen, not FullScreen. The options are case sensitive.

JavaScript: Getting HTML to appear inside of a var statement / function

I know this gets asked a lot and I've already tried some examples from SO, but no luck.
I have a function that allows me to change text in a div and it works, but only as plain text. I want it to work as HTML, but I've tried placing in innerHTML, perhaps in the wrong spot, and separated HTML in my script with + symbols. Nothing seems to work. Either I get the HTML in my text raw or the function simply does not work.
Here's my script as of this time:
$(function() {
var copyStack = [
'<strong>This is bold text within strong tags,</strong>' + ' this is the remainder of my copy.',
'<strong>This is more bold text within strong tags,</strong>' + ' this is the remainder of my second copy.'
];
$("#swatch-0").click(function () {
$(".product-shop-description").text(copyStack[0]);
console.log(copyStack[0]);
});
$("#swatch-1").click(function () {
$(".product-shop-description").text(copyStack[1]);
console.log(copyStack[1]);
});
});
I think This is what you want to do:
var copyStack = [
'<strong>This is bold text within strong tags,</strong>' + ' this is the remainder of my copy.',
'<strong>This is more bold text within strong tags,</strong>' + ' this is the remainder of my second copy.'
];
swatchOne = document.getElementById("swatch-0");
const changeInnerHTML = (elm, inner) => (elm.innerHTML = inner);
swatchOne.addEventListener("click", () => {
changeInnerHTML(swatchOne,copyStack[0]);
});
swatchTwo = document.getElementById("swatch-1");
swatchTwo.addEventListener("click", () => {
changeInnerHTML(
swatchTwo,copyStack[1]);
});
.btn{
background: #cecece;
padding: 1em;
width: max-content;
margin-bottom:1em;
}
#swatch-0{
background: #000;
color:#fff
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class='btn' id='swatch-0' >Hello</div>
<div class='btn' id='swatch-1' >Hello22</div>
<script src="./script.js"></script>
</body>
</html>
The getElementById property is used to access an HTML element
more info [HERE][]
The innerHTML property is used to access and modify the HTML inside of an HTML element
more info HERE
Solved it! Thanks to some help and some guesswork, here's the answer:
$("#swatch-0-peanut-butter-chocolate-chip").click(function () {
$(".product-shop-description").html(copyVariety[0]);
console.log(copyVariety[0]);
});

Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element' I am getting this error

I am new to Javascript and I can't figure out why am I getting this error.
Here is my code:
const bckg = document.querySelector(".bckg");
const compStyle = getComputedStyle(bckg);
body {
box-sizing: content-box;
position: relative;
}
.visible {
position: relative;
top: 50px;
margin: auto;
background-color: bisque;
height: 300px;
width: 600px;
overflow: hidden;
}
.bckg {
position: absolute;
left: 0px;
width: 1200px;
height: 300px;
background-image: url("bckg.jpg")
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<script src="script.js"></script>
<div class="visible">
<div class="bckg" id="bckg">
<div class="player"></div>
<div class="obstacle"></div>
</div>
</div>
</body>
</html>
This error I get in Mozilla: "Uncaught TypeError: Window.getComputedStyle: Argument 1 is not an object."
What could it be?
Your script tag needs to be moved to the very end of the body. The script loaded to early.
This error I get in Mozilla: "Uncaught TypeError: Window.getComputedStyle: Argument 1 is not an object." What could it be?
If you read the error message it says it could not find the argument.
The reason for this is that browsers loads JavaScript tags synchronously. It has been a standard since JavaScript was first introduced.
Solution snippet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="visible">
<div class="bckg" id="bckg">
<div class="player"></div>
<div class="obstacle">
</div>
</div>
</div>
<!-- I moved the script to the end of the body -->
<script src="script.js"></script>
</body>
</html>
Adding a console.log you could have seen that the argument for Window.getComputedStyle is indeed not an object
const bckg = document.querySelector(".bckg");
console.log(bckg); // will return undefined
You can also try out the "defer" attribute, however it has been best practice to move the script tags to the end of the body for compatibility with different older browsers. See https://www.w3schools.com/tags/att_script_defer.asp
Another alternative is to use the "DOMContentLoaded" event
https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event
document.addEventListener("DOMContentLoaded", function() {
// code...
});
Delta Boukensha is right - your document hasn't finished loading.
So either put your script at the bottom of your markup as Delta suggests or use a utility function to run code once the document has rendered such as :
function whenDOMready( func ) {
switch( String( document.readyState ) ) {
case "complete":
case "loaded":
case "interactive":
func();
break;
default:
window.addEventListener("DOMContentLoaded", (e) => func());
}
}
Then call it from wherever you want like this :
let bckg;
let compStyle;
function domReady() {
bckg = document.querySelector(".bckg");
compStyle = getComputedStyle(bckg);
/* ...other code here */
}
whenDOMready( domReady );
There are two benefits this utility gives you :
No matter when you call it it will work - either calling your function (func) immediately or when the DOMContentLoaded event fires. If you just add the event listener directly you have to worry about if it has already fired or not.
You are guaranteed that your DOM is ready for inspection and access.

How to adjust textbox width based on input that has fixed number of characters but font size may vary?

So I'm receiving a text from a server response:
"AC-8D-9A-7E"
and the text has a fixed number of characters of 11 as above and I want to display it on a textbox in HTML.
However, what I want is that, initially the textbox has a width of 0px and when I received the text from the server, I will then append it to the textbox where the width of the textbox is roughly equal to the width of the text:
How do i set the width of the textbox so that it is roughly the width of the text?
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
height: 100%;
font-size: 1vw;
}
body {
height: 100%;
}
#container {
display: flex;
width: 100%;
}
#code {
border-color: black;
width: 0px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href = "style.css">
<title>Document</title>
</head>
<body>
<div id = "container">
<input type = "text" id = "code" disabled>
</div>
<script>
document.getElementById("code").value = "AC-8D-9A-7E";
</script>
</body>
</html>
If I comment out the #code segment css, the textbox will be looking like so:
Therefore, how do i retrieve the rough width of the textbox so that it is roughly the same as the width of the text?
Edit: I do not need to consider situations like paste or delete events mentioned in other post as the textbox for me just serve as a display purpose
You can use ch unit. 1ch is approximately equal to the width of 1 character. Since you know the length of the input value is going to be 11 characters, you can set the width of it to be 11ch.
So when you get the response from the server, you can set the width to be 11ch. Although you could make it 12ch and make it look a tad bit better (or you could add padding to the input)
#code {
width: 11ch;
}
The accepted answer to this question gives a great explanation of the difference between ch and em. Something you may want to consider.
Use the size attribute that specifies the width of input in characters. I used 11 since your display results has 11 chars. Also, I recommend that you use some padding for input field.
<input type="text" size="11" id="code" disabled />

How to select all custom element that inherit from a specific javascript class

right now I'm trying to have fun with the webComponent.
I have created a component that is supposed to represent a mother class to all my other translatable components. it works as I want at the moment, but I would like a way to select all the elements of the current document that inherits from this mother class.
something like:
document.getElementsByTagName('lsp-motherComposant');
doesn't works.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>WebComponentTest</title>
<!-- motherComponent -->
<link rel="import" href="components/lsp-translatable/lsp-
translatable.html" />
<!-- child Component -->
<link rel="import" href="components/lsp-button/lsp-button.html" />
</head>
<body>
<select id="lang">
<option value="fr" selected>fr</option>
<option value="en">en</option>
<option value="zh">zh</option>
</select>
<lsp-button i18n="events" width="33%" gradient color1="0,0,0,0"
color2="128,0,128,1" direction="left"></lsp-button>
<script type="text/javascript">
window.onload = function(){
document.getElementsByTagName('lsp-translatable');
// => empty node list
};
</script>
</body>
</html>
lsp-translatable.js:
class LspTranslatable extends HTMLElement {//some stuff}
customElements.define('lsp-translatable', LspTranslatable);
lsp-button.js:
class LspButton extends LspTranslatable {//some stuff}
customElements.define('lsp-button', LspButton);
This won't help you in production code but it's a development version of what you are looking for.
Chrome DevTools has a developer command queryObjects that will return all instances of a class. In Chrome DevTools you could run the following:
queryObjects(LspTranslatable);
getElementsByTagName works fine for me
you can use document.querySelectorAll if you want to look for specific attributes for example document.querySelectorAll('img[title]') (all images with a title attribute)
console.log( Array.from(document.getElementsByTagName('randomComponent')) );
randomComponent {
position: static;
display: block;
border: 1px solid #6F6;
height: 1rem;
width: 1rem;
}
<randomComponent id="1"></randomComponent>
<randomComponent id="2"></randomComponent>
Have you tried document.querySelectorAll?
const components = document.querySelectorAll('lsp-button');
console.log(components);
console.log(Array.from(components));
lsp-button {
position: static;
display: block;
border: 1px solid #6F6;
height: 1rem;
width: 1rem;
}
<lsp-button id="button-0"></lsp-button>
<lsp-button id="button-1"></lsp-button>
<lsp-button id="button-2"></lsp-button>
<lsp-button id="button-3"></lsp-button>
<lsp-button id="button-4"></lsp-button>
<lsp-button id="button-5"></lsp-button>
<lsp-button id="button-6"></lsp-button>
<lsp-button id="button-7"></lsp-button>
<lsp-button id="button-8"></lsp-button>
<lsp-button id="button-9"></lsp-button>
To be sure that all the custom elements you select by attributes with querySelector() are really inheriting from a specific Javascript class, you should test each element whith instanceof.
window.onload = function() {
const els = document.querySelectorAll( '[i18n]' )
const translatableNodes = Array.from(els).filter( el => el instanceof LspTranslatable )
}

Categories