Inline JavaScript throwing "not defined" (it IS!) - WordPress related maybe? - javascript

<style>
#flamingo-picture-2 {
border-width: 15px;
border-style: solid;
border-color: red;
}
</style>
<script>
function changeBorderColor(){
var img = document.getElementById('flamingo-picture-2');
if ( img.style.border-color == 'red' ) {
img.style.border-color = 'blue';
} else {
img.style.border-color = 'red';
}
}
</script>
<img id="flamingo-picture-2" src="/wp-content/uploads/flamingo.jpg" onclick="changeBorderColor()">
This is inside a WordPress post content. (I know -- bad practice. But it is just a little demo/example.)
Console shows an error that changeBorderColor is not defined. I keep staring at it. I feel like I defined it. Did I miss a brace or a semi-colon or something? Is it possible WordPress is doing something? (I don't think it is, as I've looked at the output page source, but you never know...)

Instead of img.style.border-color you need img.style.borderColor It works here:
function changeBorderColor(){
var img = document.getElementById('flamingo-picture-2');
if ( img.style.borderColor == 'red' ) {
img.style.borderColor = 'blue';
} else {
img.style.borderColor = 'red';
}
}
#flamingo-picture-2 {
border-width: 15px;
border-style: solid;
border-color: red;
}
<img id="flamingo-picture-2" src="/wp-content/uploads/flamingo.jpg" onclick="changeBorderColor()">

Related

Change button color based on screen size

What I am trying to achieve is when my device size is less than 736 px, the button should animate. I got the button working correctly, however, I’m struggling to work with the specific screen size.
$(window).resize(function() {
if ($(window).width() <= 736) {
// do something
let myBtn = document.querySelector(".btn");
let btnStatus = false;
myBtn.style.background = "#FF7F00";
function bgChange() {
if (btnStatus == false) {
myBtn.style.background = "#FF0000";
btnStatus = true;
}
else if (btnStatus == true) {
myBtn.style.background = "#FF7F00";
btnStatus = false;
}
}
myBtn.onclick = bgChange;
}
});
.btn {
width: 200px;
height: 100px;
text-align: center;
padding: 40px;
text-decoration: none;
font-size: 20px;
letter-spacing: .6px;
border-radius: 5px;
border: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">CLICK ME</button>
Here's an implementation of what you're trying to do that uses:
class to alter button styling instead of style,
vanilla JavaScript instead of jQuery.
Using class is a good idea, as it keeps the styling in the CSS and out of the JavaScript code.
Using vanilla JavaScript whenever you can is preferable.
Here are the two new classes:
.btn-small-screen {
background: #FF7F00;
}
.btn-clicked {
background: #FF0000;
}
.btn-small-screen class is applied when the window is small, .btn-clicked is toggled whenever the button is clicked.
Here's the JavaScript code:
let myBtn = document.querySelector('.btn');
let isSmallWindow = () => window.innerWidth <= 736;
function toggleButtonOnClick () {
myBtn.classList.toggle('btn-clicked');
}
function setButtonMode () {
if (isSmallWindow()) {
myBtn.classList.add('btn-small-screen');
myBtn.addEventListener('click', toggleButtonOnClick);
} else {
myBtn.classList.remove('btn-small-screen');
myBtn.classList.remove('btn-clicked');
myBtn.removeEventListener('click', toggleButtonOnClick);
}
}
// setup mode on resize
window.addEventListener('resize', setButtonMode);
// setup mode at load
window.addEventListener('load', setButtonMode);
References:
Document.querySelector()
Window.innerWidth
Element.classList
DOMTokenList.toggle()
DOMTokenList.add()
DOMTokenList.remove()
EventTarget.addEventListener()
A working example:
let myBtn = document.querySelector('.btn');
let isSmallWindow = () => window.innerWidth <= 736;
function toggleButtonOnClick () {
myBtn.classList.toggle('btn-clicked');
}
function setButtonMode () {
if (isSmallWindow()) {
myBtn.classList.add('btn-small-screen');
myBtn.addEventListener('click', toggleButtonOnClick);
} else {
myBtn.classList.remove('btn-small-screen');
myBtn.classList.remove('btn-clicked');
myBtn.removeEventListener('click', toggleButtonOnClick);
}
}
// setup small mode on resize
window.addEventListener('resize', setButtonMode);
// setup small mode at load
window.addEventListener('load', setButtonMode);
.btn {
width: 200px;
height: 100px;
text-align: center;
padding: 40px;
text-decoration: none;
font-size: 20px;
letter-spacing: .6px;
border-radius: 5px;
border: none;
}
.btn-small-screen {
background: #FF7F00;
}
.btn-clicked {
background: #FF0000;
}
<button class="btn">CLICK ME</button>
Note: There is one optimization that I left out, so the code would be easier to follow.
Notice that setButtonMode() changes the DOM every time, even though it might already be set to the desired mode. This is inefficient.
To improve efficiency and only change the DOM when necessary, you could introduce a state variable (call it smallMode), and set it true whenever appropriate. Like so:
let smallMode = false;
function setButtonMode () {
if (isSmallWindow()) {
if (!smallMode) {
myBtn.classList.add('btn-small-screen');
myBtn.addEventListener('click', toggleButtonOnClick);
smallMode = true;
}
} else if (smallMode) {
myBtn.classList.remove('btn-small-screen');
myBtn.classList.remove('btn-clicked');
myBtn.removeEventListener('click', toggleButtonOnClick);
smallMode = false;
}
}

Invalid characters in HTML preventing my menu from toggling?

I'm creating a button that makes a table and a drop down menu. But the drop down menu doesn't work when it's clicked, like it should.
I keep receiving this error: 'Uncaught InvalidCharacterError: Failed to execute 'toggle' on 'DOMTokenList': The token provided ('[object HTMLCollection]') contains HTML space characters, which are not valid in tokens.' This error occurs near the last line here where I use toggle.
I've checked the HTML generated with JS and it seems fine. I just can't figure out what exactly this error is referring to. I've gone through the code at least a half dozen times and don't see any spaces within the html. This makes me question whether this is where the problem actually is. If anyone has a solution or insight into how to correct this, that would be much appreciated.
Here is the code:
//**HTML**
<div class = 'insertsGrid buttonStyle'>Grid</div>
//**CSS**
.buttonStyle{
width: 12vh;
height: 12vh;
border: 1px solid;
position: fixed;
display:flex;
justify-content:center;
align-items: center;
font-weight: 900;
font-size: 4vh;
color: #b8860b;
cursor:pointer;
background-color:white;
user-select: none;
}
th, td, tr {
border: 1px solid black;
}
//**Javascript**
const insertsGrid = document.getElementsByClassName('insertsGrid');
insertsGrid[0].addEventListener('mousedown', createGrid);
let z =0;
function createGrid (){
z++;
document.execCommand('insertHTML', true,/*this is the bar */'<div class=bar'+z.toString()+'></div>'+/*this is the menu options that show when bar is clicked */ '<div class =dropDownContent'+z.toString()+'><div class =dropDownContentX'+z.toString()+'><p>Add Row</p><p class=addColumn'+z.toString()+'>Add Column</p></div></div>'+/*this is the table */ '<table><tr><td>Head1</td><td>Head2</td></tr><tr><td></td><td></td></tr></table><br>');
let bar = document.getElementsByClassName('bar'+z.toString());
let dropDownContent = document.getElementsByClassName('dropDownContent'+z.toString());
let dropDownContentX = document.getElementsByClassName('dropDownContentX'+z.toString());
let addColumn = document.getElementsByClassName('addColumn'+z.toString());
//dom css for the html created in the dom
bar[0].style.width = '10%';
bar[0].style.height = '1%';
bar[0].style.border = '1px solid black';
bar[0].style.cursor = 'pointer';
bar[0].style.marginBottom = '50px';
dropDownContent[0].style.display = 'none';
dropDownContentX[0].style.display = 'inline';
dropDownContentX[0].style.backgroundColor = 'white';
dropDownContentX[0].style.width = '100%';
dropDownContentX[0].style.fontSize = '80%';
//action executed when the nav button is pressed
bar[0].addEventListener('mousedown' , tog);
function tog (){
dropDownContent[0].classList.toggle('dropDownContentX');
}
You are passing dropDownContentX into the toggle() method. This is a collection of DOM nodes, not a string. The toggle() method expects a CSS class name without spaces. You are passing the wrong data type to this method.
Source: https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle

Javascript Less Sorter

Problem:
I want to make a Less-sorting script for myself. When i enter Less Code in the textarea and click the button, p#result should output the sorted Less Code.
The Less Code should be sorted like this:
{
Mixins(They all start with ".mx")
Properties(Sorted in alphabetic Order)
}
Here is what i have got so far:
index.html:
<head>
<script src="jquery.min.js"></script>
</head>
<textarea id="input" style="width: 600px; height: 300px; resize: none;">
</textarea>
<p id="result" style="max-width: 600px; word-wrap: break-word;"></p>
<button>Sort</button>
<script src="jquery.sorter.js"></script>
jquery.sorter.js:
var result = "",
mixins = "",
properties = "";
$("button").on("click", function () {
var textarea = $('#input').val().split('\n');
function checkLine(position) {
var index;
for (index = position; index < textarea.length; ++index) {
var line = textarea[index].trim();
if (line.includes("{") === true)
{
result = result + mixins + "<br>" + properties + line + "<br>";
mixins = "";
properties = "";
checkLine(index + 1);
} else if (line.includes("}") === true)
{
result = result + mixins + properties + line + "<br>";
mixins = "";
properties = "";
break;
} else if (line.includes(".mx") === true)
{
mixins = mixins + line + "<br>";
} else if (line.includes(":") === true)
{
properties = properties + line + "<br>";
} else
{
result = result + "<br>";
}
console.log(index + ": " + mixins + " " + properties);
}
}
checkLine(0);
$("p#result").append(result);
$("button").hide();
});
If i enter this:
.frame {
color: blue;
background-color: white;
.mx-hello(white);
.framesecond {
font-size: 12px;
background: green;
.mx-test(white);
}
}
I should get al least this output: (I didnt think of a sorting mechanism yet... :D)
.frame {
.mx-hello(white);
color: blue;
background-color: white;
.framesecond {
.mx-test(white);
font-size: 12px;
background: green;
}
}
But i get this Output:
.frame {
.mx-hello(white);
color: blue;
background-color: white;
.framesecond {
.mx-test(white);
font-size: 12px;
background: green;
}
.mx-test(white);
font-size: 12px;
background: green;
}
.mx-hello(white);
color: blue;
background-color: white;
.framesecond {
.mx-test(white);
font-size: 12px;
background: green;
}
.mx-test(white);
font-size: 12px;
background: green;
}
Background - Story:
I work for a Web-Development Company. My Less Code always looks a bit messy, but we have guidelines how to format our Code. If im done with a Project i always sit there hour for hour just rearranging Less Code. Then i thought to myself: "There must be an easier solution for my problem!". So i googled and googled and nothing really worked. Then i decided to try it myself and thats why i am here!
I hope you understand my Problem, if something is unclear please let me know so i can edit my Question! (Im not so good at javascript, so any help is appreciated! :D)
I took a look at it to see if I could solve this one. Check this out:
Codepen: https://codepen.io/huppys/pen/VrbxLd?editors=1010
I replaced the string.includes("something") with some regular expressions to be able to filter even for some different kind of less expressions.
Plus: Properties get sorted. After finding a property the string describing the property gets pushed into an array. Before adding the found properties to the output string they get sorted.
Side note: What IDE or editor are you using for writing your LESS code? Probably it could take care of the syntax sorting itself?

Two recursive functions try to execute at the same time when only one should run

Essentially, I am trying to create a webpage that has 2 buttons; one will cause the screen to flash randomly, and the other will cause it to slowly change colours. I want to be able to switch between these two (if you press the first button it starts flashing and then if you press the second button it slowly changes without any kind of cancel button).
The buttons each call a function which sets the 'running' variable of the other function to false and it's own 'running' variable to true. It then calls a recursive function (recursive in that it just calls itself over and over). These recursive functions only execute their code when their 'running' variable is true.
If you run the snippet you can see that the program is very inconsistent (you may need to play with it for a bit to see the issue since it sometimes seems to work). Sometimes it refuses to change function and other times the two functions seem to both be active and they both try to execute (it almost looks as if they are fighting for control). I don't understand how this is happening since, I believe, only one of the 'running' variables can be true at any time.
var runningDisco = false;
var runningColours = false;
function startColours() {
if (runningDisco == true); //Is disco running?
{
runningDisco = false; //If yes, stop it
}
runningColours = true; //Indicate we are running
window.setTimeout(Colours, 100, 0); //Run
}
function startDisco() {
if (runningColours == true); {
runningColours = false;
}
runningDisco = true;
window.setTimeout(Disco, 100);
}
function Disco() {
if (runningDisco == true); {
hex = "#";
for (discoCount = 0; discoCount < 6; discoCount++) {
hex = hex.concat((Math.floor(Math.random() * 17)).toString(16));
}
document.body.style.background = hex;
window.setTimeout(Disco, 10);
}
}
function Colours(colourCount) {
if (runningColours == true); {
if (colourCount > 359) {
colourCount -= 359;
}
document.body.style.background = "hsl(" + colourCount + ", 50%, 50%)";
window.setTimeout(Colours, 10, colourCount + 1);
}
}
input {
font-family: 'Roboto', sans-serif;
text-align: center;
background-color: #dd1021;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<input id="clickMe" type="button" value="Start Disco" onclick="startDisco();" />
<input id="clickMe" type="button" value="Start Colours" onclick="startColours();" />
The semicolons after your if-statements are causing a problem
For example, replace:
if (runningColours == true); {
if (runningDisco == true); {
with
if (runningColours == true) {
if (runningDisco == true) {
Here it is fixed in jsfiddle.
You have semicolons in the wrong place
If you need to run a single animation you need to use a single global variable to hold the timeout handler and clear it when starting a new one.
Like this:
var running;
function startColours() {
clearTimeout(running);
running = setTimeout(Colours, 100, 0); //Run
}
function startDisco() {
clearTimeout(running);
running = setTimeout(Disco, 100);
}
function Disco() {
var hex = "#";
for (discoCount = 0; discoCount < 6; discoCount++) {
hex = hex.concat((Math.floor(Math.random() * 17)).toString(16));
}
document.body.style.background = hex;
running = setTimeout(Disco, 10);
}
function Colours(colourCount) {
if (colourCount > 359) {
colourCount -= 359;
}
document.body.style.background = "hsl(" + colourCount + ", 50%, 50%)";
running = setTimeout(Colours, 10, colourCount + 1);
}
input {
font-family: 'Roboto', sans-serif;
text-align: center;
background-color: #dd1021;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<input id="clickMe" type="button" value="Start Disco" onclick="startDisco();" />
<input id="clickMe" type="button" value="Start Colours" onclick="startColours();" />
The real problem is the semicolons after the if statements inside the Disco and Colours functions:
if (runningDisco == true); {
document.body.style.background = …
}
will execute as
if (runningDisco == true)
;
{
document.body.style.background = …
}
which runs the content regardless of the boolean variable. Why does it work at all sometimes? I guess when the two setTimeout callbacks run close enough to each other that only the latter is rendered at all it feels consistent. Of course that is very unstable - they are indeed fighting each other for screen time.
You made a common mistake to those new to JavaScript - including a semi-colon after you if header. This creates an if statement with no body that is followed by a block containing the single statement runningColours = false, which will not execute correctly. The below should fix this:
if (runningColours == true)
{
runningColours = false;
}
The following JSFiddle link should have a working version of your script:
https://jsfiddle.net/4qhmtnhe/
I hope it starts working, and you continue to learn JavaScript.

Message DIV Issues

I have the following javascript it pops up a message on the screen, but always over the top of the previous messageDiv if it hasn't been removed yet.
I am trying to figure out how to get the messageDiv to either push the previous div down until it disappears and then takes the previous MessageDiv's place, or show up just below the current one on the page moving down just below the previous one as new ones appear.
function pushDev(){
$.post( "#cgi.SCRIPT_NAME#", {fileId: "#fileIdIn#", action: "migrateFileDev"}, function(data){
$("body").prepend("<div class='pageMessage' id='messageDiv'>" + data + "</div>");
setTimeout(function(){$('#messageDiv').remove()}, 6000);
});
}
function savePage(){
var code = editor.getValue();
$.post( "#cgi.SCRIPT_NAME#", {fileIdIn: "#fileIdIn#", filePath: "#path#", action: "savePage", editText: code }, function(data){
$("body").prepend("<div class='pageMessage' id='messageDiv'>Saved</div>");
setTimeout(function(){$('#messageDiv').remove()}, 6000);
});
}
.pageMessage{
/*position:fixed;*/
/*top: 15%;*/
/*right: 8%;*/
background-color: #f5f5f5;
opacity: 0.9;
color: #FFF;
font-size: 18px;
text-align:center;
padding: 8px;
width: auto;
height:auto;
border:solid;
border-color: #00A3DD;
border-width: 3px;
z-index: 1000;
border-radius: 8px;
}
I think you are running into a problem because you have multiple elements with the same ID and when your setTimeout callback executes, it removes the newest message rather than the oldest one. Only one element with a given ID is allowed in HTML. You need to figure out a different way of finding the div that should be deleted for the particular timeout, for example (I got rid of the irrelevant AJAX code):
function pushDev(){
var messageDiv = $("<div class='pageMessage'>Data</div>")
$("body").prepend(messageDiv);
setTimeout(function(){messageDiv.remove()}, 6000);
}
function savePage(){
var messageDiv = $("<div class='pageMessage'>Saved</div>")
$("body").prepend(messageDiv);
setTimeout(function(){messageDiv.remove()}, 6000);
}
JSFiddle here.

Categories