Apply class to button which execCommand on contentEditable div - javascript

Is there a built in way of keeping a button active when it execute a execCommand on a content editable div ?
example :
<input type="button" onclick="doRichEditCommand('bold');" value="B"/>
function doRichEditCommand(command){
document.execCommand(command, null, false);
}
I'd like my button to remain active when the carret is within something where document.execCommand(command, null, false); has been applied. I suppose it's doable by checking the parent elements but if there is a built in way it would be better.
In other words I'd like my bold button to be orange when the carret is somewhere which should be bold.

It's doable, but it's really annoying.
Every time the contenteditable changes you call document.queryCommandState() to find the state of the text where the caret is, and then update the button class to match. So something like:
let div = document.getElementById("myContentEditable");
div.oninput = () => {
if (document.queryCommandState('bold')) {
console.log("bold!");
} else {
console.log("not bold.");
}
return false;
};
From there you can apply or remove a style from your bold button to indicate whether the cursor's in a bold section or not. Repeat for the other styles.
The annoying part is that you need to update the button state on several different events. This seems fairly exhaustive to me:
div.oninput = div.onselect = div.onchange = div.onkeyup = eventhandler;
...but I could be wrong.

<head>
<script type="text/javascript">
var editorDoc;
function InitEditable () {
var editor = document.getElementById ("editor");
editorDoc = editor.contentWindow.document;
var editorBody = editorDoc.body;
// turn off spellcheck
if ('spellcheck' in editorBody) { // Firefox
editorBody.spellcheck = false;
}
if ('contentEditable' in editorBody) {
// allow contentEditable
editorBody.contentEditable = true;
}
else { // Firefox earlier than version 3
if ('designMode' in editorDoc) {
// turn on designMode
editorDoc.designMode = "on";
}
}
}
function ToggleBold () {
editorDoc.execCommand ('bold', false, null);
}
</script>
</head>
<body onload="InitEditable ();">
First, write and select some text in the editor.
<br />
<iframe id="editor" src="editable.htm"></iframe>
<br /><br />
You can toggle the bold/normal state of the selected text with this button:
<br />
<button onclick="ToggleBold ();">Bold</button>
</body>
editable.html:
<!DOCTYPE html>
<html>
<head>
<title>Editable content example</title>
<meta charset="utf-8" />
</head>
<body>
Some text in the editor.
</body>
</html>
some possible solution here: execCommand method examples

This is what I achieved:
JS
function format(command) {
document.execCommand(command, false);
const button = document.getElementById(command);
button.classList.toggle("button--active");
}
HTML
<button id="bold" onclick="format(this.id)">Bold</button>
SCSS
button {
//Whatever you want
&--active {
//Whatever you want
}
}
However, it works for general writing. If you select text and apply an effect, the button will be kept active.

Related

JS appendChild() to a <div> in <form>

I am able to avoid the below issue by making my div a direct child of body and appending a select to the div, but am not able to achieve the same results when the div is a child of a form within body (either when appending to the div or to the form).
I am just making a drop-down table (select element) that is added to the web page when the user clicks a button. The drop-down select shows when the div is the direct child of body, but not when it is a child of a form that is a child of body. When the button is clicked using the below method, the dropdown appears for like 0.25s and then the page returns to the original layout. The same occurs when trying to append directly to the form.
<!DOCTYPE html> <!--text_index.html-->
<html>
<head>
<meta charset="UTF-8">
<title>Add Drop Down Menu to HTML w/ JS on Button Click</title>
<link rel="stylesheet" type="text/css" href="test_styles.css">
</head>
<body>
<form id="form-button">
<div id="user-area">
<button id="dropdown-button">Add a dropdown menu!</button><br /><br />
</div>
</form>
<script src="test_script.js"></script>
</body>
</html>
Now the JS is shown below. The console returns no error but the select element does not remain in the browser window.
let materialArray = ['Select Your Material:',
                    'Kryptonite',
                    'Odium',
                    'Quartz'];
let formButton = document.getElementById('form-button');
let divUserArea = document.getElementById('user-area');
let dropdownBtn = document.getElementById('dropdown-button');
/***********************************************************************/
/****BEGIN LOOP W/ BUTTON CLICK AND NAMED FUNCTION****/
//NOTE: YOU CANNOT appendChild() ON A <DIV> INSIDE A <FORM>.
////IF YOU CAN THEN THERE IS SOME LOGIC THAT I AM MISSING.
////YOU CANNOT appendChild() DIRECTLY ON A FORM EITHER.
let newSelect = document.createElement("select");
let newOption = [];
function onClickDropdownBtn () {
    for (let i = 0; i < materialArray.length; i++) {
        newOption[i] = document.createElement("option"); //create the new option for the new HTML select element
        newOption[i].text = materialArray[i]; //add the appropriate text to the new option
        newSelect.add(newOption[i], i); //add the completed option to the HTML select element
    }
divUserArea.appendChild(newSelect); //also tried formButton.appendChild(newSelect); and got same
result
return true;
}
dropdownBtn.addEventListener('click', onClickDropdownBtn);
if (onClickDropdownBtn === false) {
newSelect.style.display = 'hidden';
dropdownBtn.style.display = 'block';
} else {
newSelect.style.display = 'block';
dropdownBtn.style.display = 'hidden';
}
/****END LOOP W/ BUTTON CLICK AND NAMED FUNCTION ****/
Is there a way to append to the div inside the form, or to the form directly?
Thanks!
For gits and shiggles, here is the CSS. Maybe the issue is here?
select {
width: 200px;
height: 25px;
text-align: center;
}
button {
width: 200px;
height: 25px;
text-align: center;
}
When you put a <button> inside a form, the default type is submit, which makes the page "refresh" (that's why you only see your dropdown for a second).
You can either change your button type, like this:
<button type='button' id="dropdown-button">Add a dropdown menu!</button>
Or you can add the event.PreventDefault() in your click function to avoid the form submission, like this:
function onClickDropdownBtn (event) {
for (let i = 0; i < materialArray.length; i++) {
newOption[i] = document.createElement("option"); //create the new option for the new HTML select element
newOption[i].text = materialArray[i]; //add the appropriate text to the new option
newSelect.add(newOption[i], i); //add the completed option to the HTML select element
}
divUserArea.appendChild(newSelect); //also tried formButton.appendChild(newSelect); and got same
event.preventDefault();
return true;
}
That will keep your dropdown component in the page and you can go from there.
Forms have the default behaviour of reloading the page (they evolved in an era before SPAs). Your code works just fine, except that it also reloads the page and you lose the state (in your case, the select element).
Just change onClickDropdownBtn() to
function onClickDropdownBtn (event) {
event.preventDefault()
...
and it should be ready to go!

Is there a way to have active/inactive state on a single link?

I will need to put 2 different actions on a single link which would have an active/inactive state, right now I only know how to do one at the time, something like this (active):
State One
And I would like to have another one on same click (inactive), is there a way to have this dynamically changed? The label shouldn't change, except for color for example - style.
On the other side, it would be a great thing if I could show the list of active items as well, something like:
Active states: State one, State two, State ...
I recommend something other than an A tag for what you're doing. I also recommend the modern equivalent of an onclick, an event listener. I also recommend assigning and toggling the class.
State One
I have removed your onclick and put it into an event listener. I've added a class, so you can toggle it.
function classToggle() {
this.classList.toggle('class123');
this.classList.toggle('class456');
}
This toggles your class, thus allowing you to change the behavior of the link based on the class. Active/Inactive or Class123/Class456 whatever you want to use will work.
document.querySelector('#myDiv').addEventListener('click', classToggle);
This is your listener. It applies the classToggle function on click. You can do this with a div/button/whatever. Personally I'd change the A tag to a Div.
<div id="myElem" class="class123">click here</div>
And here is an example of this stuff working and changing based on the toggle and classes.
function classToggle() {
this.classList.toggle('class123');
this.classList.toggle('class456');
}
document.querySelector('#myElem').addEventListener('click', classToggle);
document.querySelector('#myElem').addEventListener('click', mogrify);
function mogrify(){
if (document.querySelector('#myElem').classList.contains('class123')) {
document.querySelector('#myElem').style.backgroundcolor = "#54C0FF"
document.querySelector('#myElem').innerText = "State Two";
} else {
document.querySelector('#myElem').style.backgroundcolor = "#FF8080"
document.querySelector('#myElem').innerText = "State One";
}
}
.class123 {
color: #f00;
}
.class456 {
color: #00f;
}
State One
I think I got it to work, here's my code, please let me know if good enough.
A href:
State One
js:
<script>
function toggleState(a) {
if ( a.className === 'visible' ) {
HideOneState('state_One', gameInstance);
a.className = '';
} else {
ShowOneState('state_One', gameInstance);
a.className = 'visible';
}
}
</script>
#shandoe2020 has a good answer but here is the "old way" which is pretty easy to understand too. It can be adapted to links (or anything else) quite easily.
<!DOCTYPE html>
<html>
<head>
<style>
.my-button { width:150px; height:150px; }
.my-red { background-color:#ff0000; }
.my-blue { background-color:#0000ff; }
</style>
<script>
/* toggle the state of my-red and my-blue class */
function toggle()
{
/* yeah yeah, hardcoding the item to change is bad */
var elem = document.getElementById("btn")
elem.classList.toggle("my-red")
elem.classList.toggle("my-blue")
}
</script>
</head>
<body>
<div>
<p><button id="btn" class="my-button my-red" onclick="toggle()">Button</button></p>
</div>
</body>
</html>

Poweroff toggle button/div

I’m trying to make a power off button (actually it is a div), that when I click, it will change its appearance.
It looks like an interruptor, so I want to change the background-color of the page, the color of the icon ‘power off’ and the border-style of the button.
I took this function from another site and it is doing well in adding once a CSS property, but I want it to go on and of always.
document.getElementById('io').addEventListener('click', function () {
if (this.classList.contains('poweroff')) {
// this.classList.remove('poweroff');
this.classList.add('on');
} else {
this.classList.remove('on');
}
});
I believe the logic will be something like
x = x - 1
where x need to go turning from 0 to 1 and from 1 to 0, every time I click the button.
<body>
<div class="interruptor">
<div id="io" class="poweroff">
<i class="fa fa-power-off"></i>
</div>
</div>
<script src="https://use.fontawesome.com/ddde7c70b6.js"></script>
<script src="/js/logic.js" charset="utf-8"> </script>
</body>
Since you are checking on the basis of powerOff class you need to toggle it also like this
document.getElementById('io').addEventListener('click', function () {
if (this.classList.contains('poweroff')) {
this.classList.remove('poweroff');
this.classList.add('on');
} else {
this.classList.add('poweroff');
this.classList.remove('on');
}
});
Instead of checking if condition and adding and removing classes, use toggle like this
Read Here about toggle
document.getElementById('io').addEventListener('click', function () {
this.classList.toggle('on');
});
You should use toggle instead of add and remove, as :
document.getElementById('io').addEventListener('click', function () {
if (this.classList.contains('poweroff')) {
this.classList.toggle('poweroff');
this.classList.toggle('on');
} else {
this.classList.toggle('on');
}
});
This way it will automatically add and remove class on button click.

Could an html editor insert jQuery elements?

I've been playing with making an html editor with javascript functions:
So I have a very basic editor with a "bold" button which with I can make whatever text is selected bold, this is fine (I also have a number of other buttons too, but for simplicity and shortness of code I've missed them all out)
<head>
<script>
var editorDoc;
function InitEditable () {
var editor = document.getElementById ("editor");
editorDoc = editor.contentWindow.document;
var editorBody = editorDoc.body;
if ('contentEditable' in editorBody) {
editorBody.contentEditable = true;
}
else {
if ('designMode' in editorDoc) {
editorDoc.designMode = "on";
}
}
}
function ToggleBold () {
editorDoc.execCommand ('bold', false, null);
}
</script>
</head>
<body onload="InitEditable ();">
<button type="button" onclick="ToggleBold ();">Bold</button>
<iframe contenteditable="true" id="editor"></iframe>
</body>
However, something I was really interested in being able to implement would be adding a button which could insert, say, an accordion when pressed
This would then have to add other bits of script (I imagine) to be able to run each accordion (if you had more than one)
Although I haven't had much of a go at doing this myself yet, I was hoping to get a little insight into whether or not it's possible before starting

Keeping buttons in place when using .hide()

Not sure if this is because I'm new to meteor or if I am making an error in my syntax with my HTML or jQuery. Ideally I would like the whole grid to stay in place when a button is clicked. For example if you clicked the button in the middle of the grid there would be a empty spot where that button was before. My question is, why is it that when I click a button the button disappears but moves the whole grid and what do I do to fix this?
HTML:
<head>
<title>bubblepopper</title>
</head>
<body>
<center>{{> grid}}</center>
</body>
<template name ="grid">
<div id="container">
{{#each buttons}}
<button class="button" type="button"></button>
{{/each}}
</div>
</template>
JS:
Buttons = new Meteor.Collection("buttons");
if (Meteor.isClient) {
player = prompt("What is your name?")
Template.grid.buttons = function () {
}
Template.grid.buttons = function () {
var list = [];
for(var i=1; i<=64; i++){
list.push({value: i});
}
return list;
};
Template.grid.events({
'click .button': function(ev) {
$(ev.target).hide()
}
});
}
if (Meteor.isServer) {
}
.hide() works by adding the style display: none to the element. This removes the space used by the element in the rendered page.
If you want to make something invisible but keep its space on the page, use the visibility style:
$(ev.target).css('visibility', 'hidden');
To restore it, set the visibility to visible.

Categories

Resources