Change button text with javascript, depending on applied class on the body - javascript

I have implemented a dark / light theme on my website using this guide. The two color schemes are specified as classes in CSS and applied/changed on the body using javascript). Js selects the theme automatically depending on the OS' preference or manual input, using a button (which then overrides the OS' settings and stores the preference as a cookie). Because I'm using a button to change between the themes manually, I'd like to change the text on it accordingly - "Dark Mode" to change to the dark theme when class="light-mode" is applied on the body, and "Light Mode" as the buttons' text when class="dark-mode" is applied.
As I'm pretty new to javascript, I'm still figuring out a lot of things. I tried some ways to achieve the above, but that didn't work out. Following is what I came up with:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body class="dark-theme">
<button class="btn-toggle" id="theme-btn">Dark Mode</button>
<script>
if (document.body.getElementsByClassName() == "dark-theme") {
document.getElementById("theme-btn").innerHTML="Light Mode";
} else if (document.body.getElementsByClassName() == "light-theme") {
document.getElementById("theme-btn").innerHTML="Dark Mode";
}
</script>
</body>
</html>
I figured, this could do the trick (compare if class applied to the body is "dark-theme", if yes: change button text using the button's id to "Light Mode", doing the opposite if "light-theme" is applied).
Obviously, the actual class specifying the color theme is not specified in my real html/css in the body. How does Javascript apply the class to the body - can the above script even get the correct applied theme?
Could an issue be, that .getElementsByClassName() might return multiple elements, and not just one like .getElementById()?
Following is the html I have in use now (working as far as applying dark / light mode goes), including the script that applies the CSS classes to the body. I didn't add the CSS, as this shouldn't impact the buttons' function:
<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
</head>
<body class="body">
<button class="btn-toggle">Dark Mode</button>
<!-- Color theme picker implementation javascript -->
<script>
const btn = document.querySelector(".btn-toggle"); /* Select the button */
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); /* Check for dark mode preference at the OS level*/
const currentTheme = localStorage.getItem("theme"); /* Get the user's theme preference from local storage, if it's available */
if (currentTheme == "dark") { /* If the user's preference in localStorage is dark... */
document.body.classList.toggle("dark-theme"); /* ...let's toggle the .dark-theme class on the body */
} else if (currentTheme == "light") { /* Otherwise, if the user's preference in localStorage is light... */
document.body.classList.toggle("light-theme"); /* ...let's toggle the .light-theme class on the body */
}
btn.addEventListener("click", function () { /* Listen for a click on the button */
if (prefersDarkScheme.matches) { /* If the user's OS setting is dark and matches our .dark-mode class... */
document.body.classList.toggle("light-theme"); /* ...then toggle the light mode class */
var theme = document.body.classList.contains("light-theme") /* ...but use .dark-mode if the .light-mode class is already on the body, */
? "light"
: "dark";
} else {
document.body.classList.toggle("dark-theme"); /* Otherwise, let's do the same thing, but for .dark-mode */
var theme = document.body.classList.contains("dark-theme")
? "dark"
: "light";
}
localStorage.setItem("theme", theme); /* Finally, let's save the current preference to localStorage to keep using it */
});
</script>
</body>
I'd really appreciate if somebody has any inputs on what route to go / better idea on how to achieve this. At the beginning, I figured I could just add functions to the above script, listening for changes to the theme (maybe local storage?). As this seems somewhat of a hack, I'd rather go the most efficient route, and figured I'd add a second script just checking what class is applied to the body. Thank you for any tips :)

Related

How to change background color of a page while avoiding iframes/images/videos using js/css?

I am new to CSS/JS and I am creating an accessibility chrome extension and I need to change the background color of the page. The problem I encounter is when changing the color of pages that have videos like twitch and youtube.
function changeBKColorPredefined(background, color) {
var tags = document.querySelectorAll("*");
for (let i = 0; i < tags.length; i++) {
tags[i].style.backgroundColor = background;
tags[i].style.color = color;
}
}
This code clearly changes everything there is on the page, but I don't know how to avoid changing the background color of certain tags without having to specifying them which would of course become a really hard to maintain code.
Example output of the code showed before:
I have also tried to only change the body color by using document.body.style.backgroundColor but it does not change the color of the whole page.
Thank you for any help.
Edit: an example of what I mean can be found in this extension: https://chrome.google.com/webstore/detail/a%20-fontsize-changer/ckihgechpahhpompcinglebkgcdgpkil
Use css custom properties also known as CSS Variables. This way you can set in your CSS property value as background, and then change only said value.
Simple example would be:
:root {
/**
* This will be your default value. In this example - black.
*/
--changing-background: #000;
}
/**
* In places where you want to change backround set it as background color
*/
.classes-with-changing-background {
background-color: var(--changing-background);
}
Then in JS you do:
// This is your JS. In my example we change property value to white
document.documentElement.style.setProperty('--changing-background', '#fff');
I took JS from this answer

video.js: Visibility of Control Bar shall influence div element

I am working with video.js and moved the control bar below my video.
When the video is playing and paused and the user is not moving his mouse over the area of the video the Control Bar with Play, Seekbar, Volume and Fullscreen fades out.
Now I also want to put a title and share options beneath the conventional controls. I tried the following link from stackoverflow VideoJS 4.0 Plugin: How to properly add items to the controlBar? but am too inexperienced to adapt it to my needs.
That is why I just want to start a js function that adjusts the visibility of a div element to the visibility of the control bar of video.js.
My code:
<style>
#sharediv {
background-color: #FFFFFF;
}
</style>
<div id="sharebox"> Test </div>
<script>
function showsharebox()
{ document.getElementById("sharebox").style.visibility=(document.getElementById("example_video_1").vjs-control-bar.style.opacity == 0) ? = hidden;
}
</script>
I know that an Event-Handler is missing. Where and how do I need to insert that guy?
Thanks very much!
I know tried to tie the function to the class of the control bar but this doesn't work either:
function showsharebox()
{ document.getElementById("sharebox").style.opacity=(document.getElementById('example_video_1').getElementsByClassName('vjs-default-skin vjs-control-bar').style.opacity;
}
I would be very grateful for any kind of input.

Prevent horizontal scroll in iOS WebApp

I've encountered similar problems before and could never really understand the workarounds, and so I ended up relying on plugins like iScroll. This is such simple task that I refuse to include a plugin for it - what I want is to prevent horizontal scroll in iOS. This includes the rubber band effect for any content that might be on the page but that isn't visible.
From what I understand I need to disable the rubber band altogether first and then apply the touch scroll to a container element (which I've given the id "touch"). Not sure if this is the right approach?
$(document).bind('touchmove', function(e) {
if (!e.target == '#touch') {
e.preventDefault();
}
});
Style for #touch
-webkit-overflow-scrolling: touch;
overflow: hidden;
height: 100%;
#media only screen and (max-width: 768px) {
width: 768px;
}
This doesn't prevent the horizontal width from staying at 728px however, the user is still able to scroll and see the hidden content. Ideas?
Well, the above metas are useful as such:
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="minimum-scale=1.0, width=device-width, maximum-scale=1, user-scalable=no" name="viewport" />
They prevent that bug in Safari that happens when the user rotates the screen. However, the most proper way to accomplish the desired functionality is:
Use a parent div with overflow hidden and make sure the height of this div is limited according to the viewport and a child div with overflow:auto or the css 3 overflow-y:scroll. So basically if the size of the content inside the child div exceeds the default size of the child, you can vertically/horizontally scroll through it. Because the parent has overflow:hidden, the content outside of the child will not be displayed, so you get a proper scroll effect. ** Also, if you use overflow: hidden and prevent default for all touchEvents, there will be no scrolling or weird browser behavior**
With the help of JavaScript, make sure that every element in the DOM is scaled according to the viewport, so avoid using static sizes for as many elements as possible.
Bind the touchStart, touchMove and touchEnd events. Safari doesn't always fire a touchEnd event unless a touchMove event is listened for as well. Even if it's just a placeholder, put it there to avoid the inconsistent behavior in Safari.
Horizontal sliding is possible in two ways: load new content in the same div after you detect the slide direction or populate that child div with all the elements and you are good to go and actually shifting the margins/position of the child inside it's parent to 'scroll'. Animation can be used for a slicker interface.
Bind your touch event listeners. I don't know what library or event management system you are using, but it doesn't matter. Just call the respective function for the respective task.
Get the slide direction(left/right):
var slideBeginX;
function touchStart(event){event.preventDefault();//always prevent default Safari actions
slideBeginX = event.targetTouches[0].pageX;
};
function touchMove(event) {
event.preventDefault();
// whatever you want to add here
};
function touchEnd(event) {
event.preventDefault();
var slideEndX = event.changedTouches[0].pageX;
// Now add a minimum slide distance so that the links on the page are still clickable
if (Math.abs(slideEndX - slideBeginX) > 200) {
if (slideEndX - slideBeginX > 0) {
// It means the user has scrolled from left to right
} else {
// It means the user has scrolled from right to left.
};
};
};
This work for me on Android, iPhone and iPad.
<!doctype html>
<html>
<head>
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="minimum-scale=1.0, width=device-width, maximum-scale=1, user-scalable=no" name="viewport" />
<title>Main</title>
</head>
<body>
...
</body>
</html>
Following link might be useful to you, here vertical is disabled and horizontal enabled, you just need to tweak the code a little for your purpose.
jquery-tools-touch-horizontal-only-disable-vertical-touch
In case you aren't concerned about vertical sliding, you can try the following code also -
document.ontouchmove = function(e){
e.preventDefault();
}
Hope it helps.
If you dont use the meta you will always get a rubber band effect.
<meta name="viewport" content="width=device-width" />
Even if the page fitted exactly the user would still be able to stretch the page wider than it should be able to go, you must use the view port to prevent this, there is no other way...

how to resize / rezoom webpage in ipad

I have a website that uses jquery mobile for it's mobile version. I have a problem when I am changing it from portrait to landscape it zooms in correctly, but when I flip to portrait, it stays same zoom level and is wider then the view which breaks user experience.
I use regular:
<meta name="viewport" content="width=device-width, initial-scale=1">
from all the search I did, this should do. Unfortunately it isn't working for me.
Here is my question, I can use onorientationchange event to trigger resizing of the page, I am just not sure how to go about it. Can you help please?
P.S. website is here if you would like to take a peek http://tmg.dev.dakic.com/mobile
Thank you,
Zeljko
Try this, I had a similar issue:
$(window).bind('orientationchange', function(event) {
if (window.orientation == 90 || window.orientation == -90 || window.orientation == 270) {
$('meta[name="viewport"]').attr('content', 'height=device-width,width=device-height,initial-scale=1.0,maximum-scale=1.0');
$(window).resize();
$('meta[name="viewport"]').attr('content', 'height=device-width,width=device-height,initial-scale=1.0,maximum-scale=2.0');
$(window).resize();
} else {
$('meta[name="viewport"]').attr('content', 'height=device-height,width=device-width,initial-scale=1.0,maximum-scale=1.0');
$(window).resize();
$('meta[name="viewport"]').attr('content', 'height=device-height,width=device-width,initial-scale=1.0,maximum-scale=2.0');
$(window).resize();
}
}).trigger('orientationchange');
Try otherwise using the resize() function at certain events:
$(window).resize();
I typically use the orientationchangeevent to add / remove CSS classes to the content, and go from there, rather than re-size the viewport. Apple provide some stand-alone example code, although from memory I think that it only includes 90° and 0° orientations—you need -90° and 180° too, as in #zyrex comment.
iPhoneOrientation sample code (developer.apple.com)
Update per comment:
To clarify, I don't re-size HTML entities themselves, rather change the classes being used, and rely on CSS to style accordingly. To take a simplistic example, say I want to switch between two classes on the body element, depending on device orientation, I would do something like this in my Javascript:
window.onorientationchange = updateOrientation;
// (Might want to do this onload too)
function updateOrientation(){
var o = window.orientation, body = document.querySelector('body');
switch(o){
case 0: case 180:
body.className = 'portrait';
break;
case 90: case -90:
body.className = 'landscape';
break;
}
}
… and something like this in the default mark-up:
<body class="portrait">
<!-- stuff here -->
… and then CSS which does whatever is required—e.g. a different position for the body element's background:
body {background: url('images/something.png') no-repeat}
body.portrait {background-position: 30% 50%}
body.landscape {background-position: 10% 25%}
Update #2
You may also need to tinker with the maximum-scale directive in your meta tag. Mobile Safari typically does a zoom when changing from portrait to landscape, instead of re-doing the page layout, and that may be what you're seeing.
The maximum-scale value prevents this, but you should note that this also means users can't do the normal pinch-to-zoom thing. Here's how the tag would look:
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
Be sure to check the answers here too:
How do I reset the scale/zoom of a web app on an orientation change on the iPhone?
It seems no-one knows. From what I could see, content on the page somewhere is wider then device-width and this is where the problem originates. However, how to go about solving this is still not quite clear.

JavaScript is not able to convince the mouse to change its cursor

I have an ASP.NET page with an Infragistics webgrid on it. I handle the mouseover, mouseout events over the rows of the grid in a couple methods in Javascript to change the mouse cursor to the pointer and back to the default as they mouse over rows. I also toggle the color of the mouse-over'd row.
When I run the page in debug locally, it works fine. When I publish to the test server, and run it outside of VS in Iexplore (8), the mouse cursor does not change. It stays the arrow. The row toggles the background color correctly, though.
I figured this was a caching issue, but when I add an alert box in the methods to display the document.body.style.cursor, it shows the cursor state in the alert correctly; it just doesn't change the mouse cursor. I've cleared the cache in the browser, deleted and republished, added GUID querystrings to the javascript file links, etc.
If I try the page on the test server in Firefox, it shows the pointer cursor correctly.
function _projGrid_MouseOverHandler(gridName, id, objectType) {
if (objectType == 0) {
document.body.style.cursor = 'pointer';
// alert('mouse pointer should be: ' + document.body.style.cursor);
var cell = igtbl_getCellById(id);
var elem = cell.Element;
setRowBackColor(cell.Row, "F0E68C");
}
}
function _projGrid_MouseOutHandler(gridName, id, objectType) {
if (objectType == 0) {
document.body.style.cursor = 'default';
// alert('mouse pointer should be: ' + document.body.style.cursor);
var cell = igtbl_getCellById(id);
setRowBackColor(cell.Row, "white");
}
}
function setRowBackColor(row, color) {
var cells = row.getCellElements();
for (var i = 0; i < cells.length; i++) {
cells[i].style.backgroundColor = color;
}
Any ideas would be most welcome!
UPDATE: I am also having similar problems with CSS
Answer was found here
"When IE renders on localhost, it will use standard compliant mode.
However, when it renders on an Intranet, it will use compatibility mode.
Don't ask me why it does this, it's just one of those arbitrary MS things in order to spice up our developer lives.
Just add this to your header to force IE into standard compliant mode :
<meta http-equiv="X-UA-Compatible" content="IE=edge" />"
You should be setting the cursor on the cell level and not on the document level.
Not sure why you are setting the cursor with JavaScript in the first place when you can just set it in the CSS file for the tds in question.
Do it with CSS:
.grid .row:hover {
cursor: pointer;
background-color: #F0E68C;
}
OR
.grid tr:hover {
/* ... */
}
If you don't have the necessary classes, you can try setting them with something like jQuery:
$("selector").addClass("row"); You can also filter() with a custom function or work with each section individually if necessary:
$(".grid").each(function() {
$(this).find("tr > td").each(function() {
$(this).addClass("cell");
});
});
Note that the above example is for illustration purposes only.

Categories

Resources