Toggling lottie hamburger/menu animation on .nav-link click? - javascript

SOLVED, SEE MY SOLUTION BELOW
Hello so my navigation works fine like this apart from when the links are clicked, the lottie animation doesn't toggle back to it's first frame.
Could anyone help me with a solution to this as I've been trying for awhile now with no luck.
I'm using bootstrap and this is my navigation toggler button:
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#lowetoggle"
aria-controls="lowetoggle"
aria-expanded="false"
aria-label="Toggle navigation"
>
<div class="lowe-menu" style="width: 50px;"></div>
</button>
<lottie-player id="toggleLottie" src="assets/menu.json" style="width:50px;">"></lottie-player>
</button>
and this is my js:
let iconMenu = document.querySelector('.lowe-menu');
let animationMenu = bodymovin.loadAnimation({
container: iconMenu,
renderer: 'svg',
loop: false,
autoplay: false,
path: "/assets/menu.json"
});
var directionMenu = 1;
iconMenu.addEventListener('click', (e) => {
animationMenu.setDirection(directionMenu);
animationMenu.play();
directionMenu = -directionMenu;
});
var navLinks = document.querySelectorAll('.nav-link')
var menuToggle = document.getElementById('lowetoggle')
var bsCollapse = new bootstrap.Collapse(menuToggle, {toggle:false})
navLinks.forEach((l) => {
l.addEventListener('click', () => { bsCollapse.toggle() })
});

Bootstrap 5 Lottie Hamburger Menu
Solved this myself, So if you are using Lottie for your hamburger menu in Bootstrap, and your page is using anchor links to scroll to different sections, this code will make the hamburger close on clicking a .nav-link element.
Hope this is useful, as I've not found anyone else with a snippet for this online! Maybe I didn't far though!
let iconMenu = document.querySelector('.lowe-menu');
let animationMenu = bodymovin.loadAnimation({
container: iconMenu,
renderer: 'svg',
loop: false,
autoplay: false,
animationData: {"v":"5.7.4","fr":60,"ip":0,"op":39,"w":600,"h":600,"nm":"hamburger to x","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"ScaleCTRL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,300,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[391.026,391.026,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":39,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Line03","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":24,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":32,"s":[48]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[45]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":52,"s":[48]},{"t":60,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":15,"s":[0,30.5,0],"to":[0,-5.083,0],"ti":[0,5.083,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[0,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[0,0,0],"to":[0,5.083,0],"ti":[0,-5.083,0]},{"t":69,"s":[0,30.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-9.75,-20,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-63,-20],[43.5,-20]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":39,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Line02","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-9.75,-20,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-63,-20],[43.5,-20]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.411],"y":[1]},"o":{"x":[0.938],"y":[0]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":20,"s":[50]},{"i":{"x":[0.411],"y":[1]},"o":{"x":[0.938],"y":[0]},"t":58,"s":[50]},{"t":78,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.411],"y":[1]},"o":{"x":[0.938],"y":[0]},"t":1,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":20,"s":[50]},{"i":{"x":[0.411],"y":[1]},"o":{"x":[0.938],"y":[0]},"t":58,"s":[50]},{"t":78,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":39,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Line01","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":24,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":32,"s":[-48]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[-45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[-45]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":52,"s":[-48]},{"t":60,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":15,"s":[0,-30.5,0],"to":[0,5.083,0],"ti":[0,-5.083,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[0,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[0,0,0],"to":[0,-5.083,0],"ti":[0,5.083,0]},{"t":69,"s":[0,-30.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-9.75,-20,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-63,-20],[43.5,-20]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":39,"st":0,"bm":0}],"markers":[]}
});
var directionMenu = 1;
iconMenu.addEventListener('click', (e) => {
animationMenu.setDirection(directionMenu);
animationMenu.play();
directionMenu = -directionMenu;
});
var navLinks = document.querySelectorAll('.nav-link')
var menuToggle = document.getElementById('lowetoggle')
var bsCollapse = new bootstrap.Collapse(menuToggle, {toggle:false})
navLinks.forEach((l) => {
l.addEventListener('click', () => {
if (window.innerWidth < 992){ // This part fixes flickering on desktop nav-items!
bsCollapse.toggle()
animationMenu.setDirection(directionMenu);
animationMenu.play();
directionMenu = -directionMenu;
}
});
});
.navbar-lowe {background-color: black;}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<nav class="navbar navbar-expand-lg navbar-lowe">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<p>Logo</p>
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#lowetoggle"
aria-controls="lowetoggle"
aria-expanded="false"
aria-label="Toggle navigation"
>
<div class="lowe-menu" style="width: 50px;"></div>
</button>
<div class="collapse navbar-collapse" id="lowetoggle">
<div class="navbar-nav align-items-end">
<a class="nav-link active" href="#home">Home</a>
<a class="nav-link" href="#work">Work</a>
<a class="nav-link" href="#contact">Contact</a>
</div>
<div class="navbar-text ms-auto text-end">
<a class="btn nav-button" role="button">Call Today <strong>05555555 555</strong></a>
</div>
</div>
</div>
</nav>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.8.1/lottie.min.js"></script>
<script src="https://unpkg.com/#lottiefiles/lottie-player#latest/dist/lottie-player.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>

Related

How to hide bootstrap offcanvas in vue3 when router-link is clicked?

Good day, I would like to hide bootstrap-5/Offcanvas when I click on link inside. Here is Offcanvas:
//Button activate Offcanvas
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasDarkNavbar"
aria-controls="offcanvasDarkNavbar">
<span class="navbar-toggler-icon"></span>
</button>
//Offcanvas
<div class="offcanvas offcanvas-end text-bg-dark" tabindex="-1" id="offcanvasDarkNavbar"
aria-labelledby="offcanvasDarkNavbarLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasDarkNavbarLabel">Menu</h5>
</div>
<div class="offcanvas-body">
<ul class="nav nav-pills flex-column mb-sm-auto mb-0 align-items-center align-items-sm-start" id="menu">
<li class="nav-item">
<router-link to="/about" class="nav-link link-info align-middle px-0">
<i class="fs-4 bi-house"></i> <span class="ms-1 d-none d-sm-inline">Home</span>
</router-link>
</li>
</ul>
</div>
</div>
In official docs they say:
You can create an offcanvas instance with the constructor, for example:
var myOffcanvas = document.getElementById('myOffcanvas') OR
var bsOffcanvas = new bootstrap.Offcanvas(myOffcanvas)
and then use method "hide". I tried to use in router-link #click="hideThisCanvas" and then
methods: {
hideThisCanvas(){
let myOffcanvas = document.getElementById('offcanvasDarkNavbar')
myOffcanvas.hide();
}
}
but it gives the error myOffcanvas.hide is not a function. Please, help!
you have to create an offcanvas instance with the constructor, for example:
methods: {
hideThisCanvas(){
let myOffcanvas = document.getElementById('offcanvasDarkNavbar')
let bsOffcanvas = bootstrap.Offcanvas.getInstance(myOffcanvas);
bsOffcanvas.hide();
}
}
OR
methods: {
hideThisCanvas(){
let myOffcanvas = document.getElementById('offcanvasDarkNavbar')
let bsOffcanvas = new bootstrap.Offcanvas(myOffcanvas);
bsOffcanvas.hide();
}
}
Because using traditional document selectors is not ideal for modern JS framework, you can create a ref for your offCanvas like this.
<div ref="offCanvas" class="offcanvas offcanvas-start" tabindex="-1" id="example_canvas">
Then access it in your vuejs function the way you should
example
let myOffcanvas = this.$refs.offCanvas;
your final method should be something like this
methods: {
hideThisCanvas(){
let myOffcanvas = this.$refs.offCanvas;
let bsOffcanvas = new bootstrap.Offcanvas(myOffcanvas);
bsOffcanvas.hide();
}
}
I do not know so much about vuejs but I hope you get concept now and it helps you.

When I load two identical (confirmed by IntelliJ) JS scripts into my web app one produces different results than the other

TL;DR: IntelliJ confirms to different scripts are identical, but they produce different results when ran in the browser (using IntelliJ with Tomcat). Exact details below.
I am creating a web project using Spring MVC that allows me to play chess. I am using the chess.js library and the chessboard.js library.
According to the chess.js library README, it has a methodpgn() that returns the moves of the game as a string. You can optionally pass in a JSON to set a max_length and a newline character so that there is a new line character after black moves. For example game.pgn({ max_width: 5, newline_char: '<br />' }).
Here's my problem. I made a script called initgame.js that instantiates a chess game using the libraries and attempted to use the example above so that the moves printed out would be formatted to print a new line after each turn.
It wasn't working as I had hoped. So I created another script test_game.js to experiment and when I got the behavior I wanted I copy and pasted the contents of test_game.js into initgame.js. Changed the <script> tag point to initgame.js again and it was ignoring the line breaks again. Used IntelliJ to compare the files and IntelliJ confirms that the files are indeed identical.
Now I am just dumbfounded. I tried rebuilding the project, cleaning the Artifacts, cleaning Maven. Nothing. I even closed out of IntelliJ and restarted. When I run the program with test_game.js it works as desired. When I run it with initgame.js it ignores the line breaks.
As a potential hint, this doesn't happen when I use Visual Studio and load it into the browser as an .html instead of a .jsp Any insight is appreciated! Code and screen shots of output are below as well as a screen shot IntelliJ comparing the files.
initgame.js
// NOTE: this example uses the chess.js library:
// https://github.com/jhlywa/chess.js
var board = null;
const game = new Chess()
var $status = $('#status');
var $fen = $('#fen');
var $pgn = $('#pgn');
function onDragStart (source, piece, position, orientation) {
// do not pick up pieces if the game is over
if (game.game_over()) return false;
// only pick up pieces for the side to move
if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false
}
}
function onDrop (source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
});
// illegal move
if (move === null) return 'snapback';
updateStatus()
}
// update the board position after the piece snap
// for castling, en passant, pawn promotion
function onSnapEnd () {
board.position(game.fen())
}
function updateStatus () {
var status = '';
var moveColor = 'White';
if (game.turn() === 'b') {
moveColor = 'Black'
}
// checkmate?
if (game.in_checkmate()) {
status = 'Game over, ' + moveColor + ' is in checkmate.'
}
// draw?
else if (game.in_draw()) {
status = 'Game over, drawn position'
}
// game still on
else {
status = moveColor + ' to move';
// check?
if (game.in_check()) {
status += ', ' + moveColor + ' is in check'
}
}
$status.html(status);
$fen.html(game.fen());
$pgn.html(game.pgn({ max_width: 5, newline_char: '<br />' }))
}
var config = {
draggable: true,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
};
board = Chessboard('myBoard', config);
updateStatus();
test_game.js
// NOTE: this example uses the chess.js library:
// https://github.com/jhlywa/chess.js
var board = null;
const game = new Chess()
var $status = $('#status');
var $fen = $('#fen');
var $pgn = $('#pgn');
function onDragStart (source, piece, position, orientation) {
// do not pick up pieces if the game is over
if (game.game_over()) return false;
// only pick up pieces for the side to move
if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false
}
}
function onDrop (source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
});
// illegal move
if (move === null) return 'snapback';
updateStatus()
}
// update the board position after the piece snap
// for castling, en passant, pawn promotion
function onSnapEnd () {
board.position(game.fen())
}
function updateStatus () {
var status = '';
var moveColor = 'White';
if (game.turn() === 'b') {
moveColor = 'Black'
}
// checkmate?
if (game.in_checkmate()) {
status = 'Game over, ' + moveColor + ' is in checkmate.'
}
// draw?
else if (game.in_draw()) {
status = 'Game over, drawn position'
}
// game still on
else {
status = moveColor + ' to move';
// check?
if (game.in_check()) {
status += ', ' + moveColor + ' is in check'
}
}
$status.html(status);
$fen.html(game.fen());
$pgn.html(game.pgn({ max_width: 5, newline_char: '<br />' }))
}
var config = {
draggable: true,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
};
board = Chessboard('myBoard', config);
updateStatus();
.jsp page
<!doctype html>
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%#taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet"
href="${pageContext.request.contextPath}/static/javascript/chessboardjs/css/chessboard-1.0.0.min.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/bootstrap.min.css">
<title>Hello, world!</title>
</head>
<body>
<main>
<div class="container">
<div class="d-flex justify-content-between align-items-center">
<h1>Hello World</h1>
Login
</div>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">
<i class="fas fa-chess-queen"></i>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<!-- Replace with Spring security Login form -->
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<div class="container">
<div class="row justify-content-center mx-1 my-3">
<div id="myBoard" class="col-6"></div>
<div class="card bg-light col-3">
<div class="card-header">Header</div>
<div class="card-body">
<h5 class="card-title">PGN</h5>
<p class="card-text">Here are the moves of the game as printed by test_game.js</p>
<div class="card-text" id="pgn"></div>
</div>
<button type="button" class="btn btn-primary m-3">Reset Game</button>
</div>
</div>
<div class="row justify-content-center">
<label>Status:</label>
<div id="status"></div>
<label>FEN:</label>
<div id="fen"></div>
<!--
<label>PGN:</label>
<div id="pgn"></div> -->
</div>
</div>
</div>
</main>
<%-- jquery --%>
<script
src="https://code.jquery.com/jquery-3.4.1.js"
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<script src="${pageContext.request.contextPath}/static/javascript/chessboardjs/js/chessboard-1.0.0.min.js"></script>
<script src="${pageContext.request.contextPath}/static/javascript/node_modules/chess.js/chess.js"></script>
<script src="${pageContext.request.contextPath}/static/javascript/test_game.js"></script>
</body>
</html>
With initgame.js
With test_game.js
The results of the IntelliJ compare function
try this : replace
$pgn.html(game.pgn({ max_width: 5, newline_char: '<br />' c}))
by
var pgnn = game.pgn({ max_width: 5, newline_char: '<br />' })
pgnn = pgnn + " </br>"
$pgn.html(pgnn)
i'm not sure that it gonna work but i think

how to make Intersection Observer to replicate bootstrap scroll spy behavior

I'm building a blazor application where I should keep java script code to minimal. So I'm using only bootstrap css in my parallax page. I have made scroll spy like behavior work with window.onscroll since it cannot be done with c# as of now; but it gives poor performance.
After googling, I recently came across IntersectionObserver API. so I thought of making my existing window.onscroll logic to work with IntersectionObserver API. However I'm not able to achieve it.
Here is what I'm trying to do. In my parallax page with fixed top nav bar and I would like to apply active css class to a.nav-items when the user scroll reaches the respective section he wants to view.
Here is the HTML:
<body data-spy="scroll" data-target=".site-nav" data-offset="55">
<header id="page-hero" class="site-header d-flex flex-column align-content-between">
<nav class="site-nav family-sans navbar navbar-expand-md navbar-dark fixed-top">
<div class="container-fluid">
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#myTogglerNav" aria-controls="myTogglerNav"
aria-label="Toggle Navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand text-uppercase" href="#page-hero">
<i class="fas fa-cube mr-2"></i> Layout Components</a>
<div class="collapse navbar-collapse" id="myTogglerNav">
<div class="navbar-nav ml-auto font-weight-regular text-uppercase">
<a class="nav-item nav-link" href="#page-hero">home</a>
<a class="nav-item nav-link" href="#page-multicolumn">columns</a>
<a class="nav-item nav-link" href="#page-media">media</a>
<a class="nav-item nav-link" href="#page-photogrid">grid</a>
<a class="nav-item nav-link" href="#page-carousel">carousel</a>
<a class="nav-item nav-link" href="#page-nested">nested</a>
<a class="nav-item nav-link" href="#page-icons">icons</a>
<a class="nav-item nav-link" href="#page-floater">floater</a>
<a class="nav-item nav-link" href="#page-cards">cards</a>
</div>
</div>
</div>
</nav>
<section class="layout-hero jumbotron jumbotron-fluid d-flex align-items-center mt-5 text-reverse">
<div class="container text-center">
......
......
......
<article id="page-multicolumn" class="page-section vertical-padding">
<header class="page-section-header container">
.....
.....
.....
<article id="page-media" class="page-section vertical-padding">
<header class="page-section-header container text-center">
....
I have article tag with id matching href of a in top .nav-item. I have only pasted few of the html as the skeleton is same for all article tags.
Here is my existing window.onscroll:
var sections = {};
document.querySelectorAll(".page-section,.site-header").forEach(section => sections[section.id] = section.offsetTop);
window.onscroll = function () {
document.querySelector('header nav').classList.toggle('inbody', document.documentElement.scrollTop > 380);
document.querySelector('#page-media .layout-animation').style['visibility'] = 'hidden';
var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
Object.keys(sections).forEach(key => {
if (sections[key] <= scrollPosition + 55) {
document.querySelectorAll('a.nav-item').forEach(a => a.classList.remove('active'));
document.querySelector('a[href="#' + key + '"]').classList.add('active');
if (key === 'page-media') {
document.querySelector('#page-media .layout-animation').classList.add('animated', 'fadeInRight');
}
}
});
};
The above code works. But I would like to use the right API.
Here is my IntersectionObserver:
if (window.IntersectionObserver) {
let observer = new IntersectionObserver(
(entries, observer) => {
console.log(entries);
entries.forEach(entry => {
/* Here's where we deal with every intersection */
document.querySelectorAll('a.nav-item').forEach(a => a.classList.remove('active'));
if (entry.isIntersecting) {
document.querySelector('header nav').classList.toggle('inbody', entry.target.id !== 'page-hero');
document.querySelector('#page-media .layout-animation').style['visibility'] = 'hidden';
document.querySelector('a[href="#' + entry.target.id + '"]').classList.add('active');
if (entry.target.id === 'page-media') {
document.querySelector('#page-media .layout-animation').classList.add('animated', 'fadeInRight');
}
}
});
}, { root: document.querySelector('.site-nav'), rootMargin: "0px", threshold: 0 });
document.querySelectorAll('.page-section,.site-header').forEach(section => observer.observe(section));
}
But my intersection observer is not working. I tired using console.log(entry) to see what happens. All the entries gets logged only on page load and not working after that. Please assist on where I'm wrong.
The reason the code here doesn't work is that it's running at the wrong time. The call to document.querySelectorAll('.page-section,.site-header') needs to be executed after those elements have been rendered into the DOM, otherwise it won't match anything.
Here is how I made it to work, I tweaked the function little bit as shown below,
function highlightMenu() {
const sections = document.querySelectorAll('.page-section,.site-header');
const config = {
rootMargin: '-55px 0px -85%'
};
let observer = new IntersectionObserver(function
(entries, self) {
entries.forEach(entry => {
if (entry.isIntersecting) {
intersectionHandler(entry);
}
});
}, config);
sections.forEach(section => observer.observe(section));
}
function intersectionHandler(entry) {
const id = entry.target.id;
document.querySelector('header nav').classList.toggle('inbody', id !== 'page-hero');
if (id === 'page-media') {
document.querySelector('#page-media .layout-animation').classList.add('animated', 'fadeInRight');
}
const currentlyActive = document.querySelector('nav a.nav-item.active');
const shouldBeActive = document.querySelector('nav a.nav-item[href="#' + id + '"]');
if (currentlyActive) {
currentlyActive.classList.remove('active');
}
if (shouldBeActive) {
shouldBeActive.classList.add('active');
}
}
and called from inside my component OnAfterRenderAsync using JS interop in blazor,
#code{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeVoidAsync("highlightMenu");
}
}
}

Changing the menu color based on the hue of the slider image

Another update I found a way to get the RGB of the image using https://github.com/lokesh/color-thief,like #Ivan Arambula suggested.
now I am trying to compare the RGB of the color with the RGB of white and black then changing the menu color depending on the result I am using a code from an answer from #cyang answer
but I have the following error
(index):240 Uncaught TypeError: Cannot read property 'substr' of undefined
at getContrastYIQ ((index):240)
at HTMLElement.<anonymous> ((index):247)
at HTMLElement.dispatch (jquery-3.2.1.min.js:3)
at HTMLElement.q.handle (jquery-3.2.1.min.js:3)
at Object.trigger (jquery-3.2.1.min.js:4)
at HTMLElement.<anonymous> (jquery-3.2.1.min.js:4)
at Function.each (jquery-3.2.1.min.js:2)
at r.fn.init.each (jquery-3.2.1.min.js:2)
at r.fn.init.trigger (jquery-3.2.1.min.js:4)
at $.Unslider.self.animate (unslider.js:439)
the JS code
<script type="text/javascript">
$(function() {
var colorThief = new ColorThief();
var slider = $('.my-slider').unslider();
slider.on('unslider.change', function(event, index, slide) {
image = slide.find('img')[0];
color = colorThief.getColor(image,5);
// color logic here
function getContrastYIQ(color){
var r = parseInt(color.substr(0,2),16);
var g = parseInt(color.substr(2,2),16);
var b = parseInt(color.substr(4,2),16);
var yiq = ((r*299)+(g*587)+(b*114))/1000;
return yiq ;
}
var colors = getContrastYIQ();
if (colors >= 128) {
$('.marker').css('color', 'black');
}else {
$('.marker').css('color', 'white');
}
})
});
</script>
my original question
I made a slider using A very simple jQuery slider. [http://idiot.github.io/unslider/][1].
and I have a fixed hamburger menu, which I would like to change colors (white and blue) depending on the hue of the image, I have searched a lot and I couldn't find a solution,
the libraries that I used till now are
https://github.com/kennethcachia/background-check (with this one I succeed to change the color but only on scrolling not sliding and it doesn't switch to the other color).
https://github.com/jamiebrittain/colourBrightness.js (no luck)
https://github.com/lokesh/color-thief (no luck)
If you could tell me the best technic or js library to do that it will be great
I am using laravel 5.4
My header code is
<header>
<div class="logo">
<h3>Petronius 1926</h3>
</div>
</header>
<!-- menu -->
<button type="button" class="navbar-toggle js-navToggleButton is-open">
<span class="icon-bar icon-bar--first"></span>
<span class="icon-bar icon-bar--middle"></span>
<span class="icon-bar icon-bar--second"></span>
<span class="navbar-toggleTitle">Menu</span>
</button>
<span class="marker-left"><i class="fa fa-chevron-left" aria-hidden="true"></i></span>
<span class="marker"><i class="fa fa-square" aria-hidden="true"></i></span>
<span class="marker-right"><i class="fa fa-chevron-right" aria-hidden="true"></i></span>
<nav class="pushy pushy-left">
<div class="pushy-content">
<div class="diamond">
<button type="button" class="navbar-toggle navbar-toggle--innerNav js-navToggleButton close">
<span class="icon-bar icon-bar--first"></span>
<span class="icon-bar icon-bar--middle"></span>
<span class="icon-bar icon-bar--second"></span>
</button>
</div>
<span class="navbar-toggleTitle">Menu</span>
<div class="marker-inner outer"><i class="fa fa-square" aria-hidden="true"></i></div>
<ul>
<li class="pushy-link">Home</li>
<li class="pushy-link">Who we are</li>
<li class="pushy-link">How is it made</li>
<li class="pushy-link">Collection</li>
<li class="pushy-link">Contact</li>
</ul>
<div class="marker-inner inverse"><i class="fa fa-square" aria-hidden="true"></i></div>
</div>
</nav>
<div class="site-overlay"></div>
My home page code is
#extends('layouts.master')
#section('styles')
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="/css/unslider.css">
<link rel="stylesheet" href="/css/unslider-dots.css">
#endsection
#section('title')
Home Page
#endsection
#section('content')
<div id="fullpage" class="fullpage-wrapper">
<section id="home" class="my-slider">
<ul>
#foreach( $gallery as $image )
<li><img id="slider-image" src="{!! '/images/'.$image->image !!}" alt="Home page image slider"></li>
#endforeach
</ul>
</section>
</div>
#endsection
#section('scripts')
<!-- Slider -->
<script src="js/unslider.js"></script>
<script src="js/script.js"></script>
$(function() {
var colorThief = new ColorThief();
var slider = $('.my-slider').unslider();
slider.on('unslider.change', function(event, index, slide) {
image = slide.find('img')[0];
color = colorThief.getColor(image,5);
// color logic here
function getContrastYIQ(color){
var r = parseInt(color.substr(0,2),16);
var g = parseInt(color.substr(2,2),16);
var b = parseInt(color.substr(4,2),16);
var yiq = ((r*299)+(g*587)+(b*114))/1000;
return yiq ;
}
var colors = getContrastYIQ();
if (colors >= 128) {
$('.marker').css('color', 'black');
}else {
$('.marker').css('color', 'white');
}
</script>
#endsection
Using Color Thief something like this might work.
$(function() {
var colorThief = new ColorThief();
var slider = $('.my-slider').unslider();
slider.on('unslider.change', function(event, index, slide) {
image = slide.find('img')[0];
color = colorThief.getColor(image);
// color logic here
})
});

Response menu not collapsing and reloads page

At http://www.dentalo.se/contact it is using a responsive menu for mobile devices.
When clicking on the menu button it collapses the menu but the same time reloads the page.
Can anyone tell my why and how I can fix it?
Thanks for the time you are taking to help me.
Edit
HTML
<div class="container">
<div class="navbar-header">
<!-- BEGIN RESPONSIVE MENU TOGGLER -->
<button type="button" class="navbar-toggle btn navbar-btn" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- END RESPONSIVE MENU TOGGLER -->
<!-- BEGIN LOGO (you can use logo image instead of text)-->
<a class="navbar-brand logo-v1" href="/">
<img src="/assets/img/logo_blue.png" id="logoimg" alt="">
</a>
<!-- END LOGO -->
</div>
<!-- BEGIN TOP NAVIGATION MENU -->
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li id="MainMenuHome">Start</li>
<li class="dropdown" id="MainMenuDentalo">
<a class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" data-delay="0" data-close-others="false" href="#">
Dentalo
<i class="icon-angle-down"></i>
</a>
<ul class="dropdown-menu">
<li id="SubMenuAbout">Om Dentalo</li>
<li id="SubMenuJob">Lediga tjänster</li>
<li id="SubMenuConnect">Anslut</li>
</ul>
</li>
<li id="MainMenuLogIn">Logga in</li>
<li id="MainMenuContact">Kontakt</li>
<li class="menu-search">
<span class="sep"></span>
<i class="icon-search search-btn"></i>
<div class="search-box">
<form action="#">
<div class="input-group input-large">
<asp:TextBox runat="server" placeholder="Sök..." CssClass="form-control" ID="textBoxSearch"></asp:TextBox>
<span class="input-group-btn">
<asp:Button runat="server" CssClass="btn theme-btn" ID="ButtonSearch" OnClick="ButtonSearch_Click" Text="Sök" />
</span>
</div>
</form>
</div>
</li>
</ul>
</div>
<!-- BEGIN TOP NAVIGATION MENU -->
</div>
JavaScript
/*
* Project: Twitter Bootstrap Hover Dropdown
* Author: Cameron Spear
* Contributors: Mattia Larentis
*
* Dependencies?: Twitter Bootstrap's Dropdown plugin
*
* A simple plugin to enable twitter bootstrap dropdowns to active on hover and provide a nice user experience.
*
* No license, do what you want. I'd love credit or a shoutout, though.
*
* http://cameronspear.com/blog/twitter-bootstrap-dropdown-on-hover-plugin/
*/
;(function($, window, undefined) {
// outside the scope of the jQuery plugin to
// keep track of all dropdowns
var $allDropdowns = $();
// if instantlyCloseOthers is true, then it will instantly
// shut other nav items when a new one is hovered over
$.fn.dropdownHover = function(options) {
// the element we really care about
// is the dropdown-toggle's parent
$allDropdowns = $allDropdowns.add(this.parent());
return this.each(function() {
var $this = $(this),
$parent = $this.parent(),
defaults = {
delay: 500,
instantlyCloseOthers: true
},
data = {
delay: $(this).data('delay'),
instantlyCloseOthers: $(this).data('close-others')
},
settings = $.extend(true, {}, defaults, options, data),
timeout;
$parent.hover(function(event) {
// so a neighbor can't open the dropdown
if(!$parent.hasClass('open') && !$this.is(event.target)) {
return true;
}
if(shouldHover) {
if(settings.instantlyCloseOthers === true)
$allDropdowns.removeClass('open');
window.clearTimeout(timeout);
$parent.addClass('open');
}
}, function() {
if(shouldHover) {
timeout = window.setTimeout(function() {
$parent.removeClass('open');
}, settings.delay);
}
});
// this helps with button groups!
$this.hover(function() {
if(shouldHover) {
if(settings.instantlyCloseOthers === true)
$allDropdowns.removeClass('open');
window.clearTimeout(timeout);
$parent.addClass('open');
}
});
// handle submenus
$parent.find('.dropdown-submenu').each(function(){
var $this = $(this);
var subTimeout;
$this.hover(function() {
if(shouldHover) {
window.clearTimeout(subTimeout);
$this.children('.dropdown-menu').show();
// always close submenu siblings instantly
$this.siblings().children('.dropdown-menu').hide();
}
}, function() {
var $submenu = $this.children('.dropdown-menu');
if(shouldHover) {
subTimeout = window.setTimeout(function() {
$submenu.hide();
}, settings.delay);
} else {
// emulate Twitter Bootstrap's default behavior
$submenu.hide();
}
});
});
});
};
// helper variables to guess if they are using a mouse
var shouldHover = false,
mouse_info = {
hits: 0,
x: null,
y: null
};
$(document).ready(function() {
// apply dropdownHover to all elements with the data-hover="dropdown" attribute
$('[data-hover="dropdown"]').dropdownHover();
// if the mouse movements are "smooth" or there are more than 20, they probably have a real mouse
$(document).mousemove(function(e){
mouse_info.hits++;
if (mouse_info.hits > 20 || (Math.abs(e.pageX - mouse_info.x) + Math.abs(e.pageY - mouse_info.y)) < 4) {
$(this).unbind(e);
shouldHover = true;
}
else {
mouse_info.x = e.pageX;
mouse_info.y = e.pageY;
}
});
});
// for the submenu to close on delay, we need to override Bootstrap's CSS in this case
var css = '.dropdown-submenu:hover>.dropdown-menu{display:none}';
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
$('head')[0].appendChild(style);
})(jQuery, this);
It appears that your button element (navbar-btn) is submitting your form. Try adding type="button" to the button element.
Also in the click event handler you can also try to add e.preventDefault() to your click event handler.
I cant seem to find the JavaScript from the click event of your button so I can help much more. If this does not work, please edit your question to show the relevant HTML and JavaScript sections.

Categories

Resources