revealjs highlight newly revealed line of code - javascript

I want to incrementally reveal a code block with the following conditions:
Code not shown yet is hidden instead of greyed out
When new lines are revealed, they are highlighted with different background color
When transitioning between auto animated slides, new lines of code that are not hidden should also be highlighted
I've managed to do 1 by changing the opacity of .reveal .hljs.has-highlights tr:not(.highlight-line). For 2, I've tried to keep track of newly added lines with a script but it doesn't work since revealjs autogenerates a fragment for each transition. I guess the solution to 3, which I have not tried yet, would be similar to 2.
I'm new to JavaScript, so I'm not sure how to proceed, what's the best way to do this? Here's a MWE for my use case
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>reveal.js</title>
<link rel="stylesheet" href="dist/reset.css">
<link rel="stylesheet" href="dist/reveal.css">
<link rel="stylesheet" href="dist/theme/black.css">
<link rel="stylesheet" href="dist/custom.css">
<!-- Theme used for syntax highlighted code -->
<link rel="stylesheet" href="plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-state="stats" data-auto-animate>
<pre data-id="code-animation" ><code data-line-numbers="1,2|1-6">
function $initHighlight(block, cls) {
try {
if (cls.search(/\bno\-highlight\b/) != -1)
return process(block, true, 0x0F) +
` class="${cls}"`;
</code></pre>
</section>
<section data-state="stats" data-auto-animate>
<pre data-id="code-animation" ><code data-line-numbers="1-8|1-11|1-14">
function $initHighlight(block, cls) {
try {
if (cls.search(/\bno\-highlight\b/) != -1)
return process(block, true, 0x0F) +
` class="${cls}"`;
} catch (e) {
/* handle exception */
}
for (var i = 0 / 2; i < classes.length; i++) {
if (checkCondition(classes[i]) === undefined)
console.log('undefined');
}
</code></pre>
</section>
</div>
</div>
<script src="dist/reveal.js"></script>
<script src="plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
hash: true,
plugins: [ RevealHighlight ]
});
</script>
</body>
</html>

Related

How can I generate line number from css or javascript based on height of container

I have a situation where I have to make something that looks like a code editor and to acheive this I have to use HTML, CSS and Js without any libraries.
I have achieved pretty much everything except the line numbers and I am not sure how to do it.
So far I have achieved this:
and this is what actually is my target:
supposing that I have this html structure:
<html>
<head>
</head>
<body>
<div class="lines"></div>
<div class="code"></div>
</body>
</html>
how do I populate lines based on the height of content in code using CSS or JavaScript?
Here's something: (written fast, feel free to adjust CSS etc)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<style>
#code {
line-height: 15px;
}
.holder {
display: flex
}
</style>
</head>
<body>
<div class="holder">
<div>
<pre id="lines">
</pre>
</div>
<div>
<pre id="code">
.aaa {
bbb
}
.ccc {
ddd
}
</pre>
</div>
</div>
</body>
<script>
const codeHeight = document.getElementById('code').offsetHeight;
const lines = Math.ceil(codeHeight / 15);
let html = '';
for (i = 1; i < lines; i++) {
html += i + '<br>'
}
document.getElementById('lines').innerHTML = html;
</script>
</html>
Here's the JS fiddle: https://jsfiddle.net/4aowc26f/
Number 15 in calculation is due to 15px line height. Feel free to introduce variable for this one.
you should make every line as a div
<div><span>{line}</span> <span>some code</span> </div>

classlist.toggle() with force false still adding class

I have a side navigation bar with a button to toggle showing just the icons or to show the icons and the text. There are multiple different HTML pages that share this nav bar, so I needed to save the nav bar's state for when you switch to each (Dashboard to Items, Contacts to Dashboard, etc). I do this using the follow code:
var navBar = document.querySelector(".side-bar");
var toggle = document.querySelector(".nav-toggle");
window.onload = () =>
{
let isClosed = localStorage.getItem("navState");
navBar.classList.toggle("nav-is-closed", isClosed);
}
toggle.addEventListener("click", () =>
{
let isClosed = navBar.classList.toggle("nav-is-closed");
localStorage.setItem("navState", isClosed);
});
.side-bar {
position: relative;
background-color: var(--default-back-color);
min-width: 200px;
}
.nav-is-closed {
min-width: inherit;
}
.nav-is-closed a h2 {
display: none;
}
<!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">
<link rel="stylesheet" href="resources/css/styles.css">
<!--Google Fonts-->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Neucha&family=Poppins:wght#300&display=swap" rel="stylesheet">
<title>Rucksack</title>
</head>
<body>
<header>
<div>
<img src="resources/images/rucksack.png" alt="">
<h1 class="title">Rucksack</h1>
</div>
<div>
<a class="smaller-icon" href="#"><img src="resources/images/gear.png" alt=""></a>
<img src="resources/images/blue-profile.png" alt="">
</div>
</header>
<main>
<section id="main-section">
<nav class="side-bar">
<a class="selected-nav" href="dashboard"><img src="resources/images/house-icon.png" alt=""><h2>Dashboard</h2></a>
<img src="resources/images/item-icon.png" alt=""><h2>Items</h2>
<hr class="nav-break">
<img src="resources/images/contacts-icon.png" alt=""><h2>Contacts</h2>
<hr class="nav-break">
<img src="resources/images/reports-icon.png" alt=""><h2>Reports</h2>
<div class="nav-toggle"><img src="resources/images/arrow-icon.png" alt=""></div>
</nav>
<div class="content">
<strong>Content</strong>
</div>
</section>
</main>
<script src="shell-controls.js"></script>
</body>
</html>
Everything works fine, except when you move to a new page while the nav is open. It closes even though in window.onload, isClosed is false. As far as I know, toggle with force set to false removes the class, but in this case it's still adding it.
As Kaiido said, isClosed was being pulled from localStorage as a string, which caused toggleClass to think the string of "false" was truthy, therefore still adding the 'nav-is-closed' class. Adding JSON.parse when getting isClosed and adding JSON.stringify when setting isClosed in localStorage solves the problem.

Splicing/Removing selected array elements removes the other elements after the selected element

I am making an offline application of a music website using JS and I am handling song queues using arrays. I added song blocks with skip buttons so users can choose which song to skip without spamming another skip button that only allows them to skip the first song of the queue. The problem is, splicing the array with the index of the selected song the users wanted to skip removes the rest of the songs after it.
Example array: ["songA","songB","songC","songD","songE"]
If the user choose to skip songC, the song queue will become ["songA","songB"] and the songC to songE will be removed, but in reality the expected outcome should be ["songA","songB","songD","songE"].
I have no idea what is wrong with the code and I have searched similar topics regarding this problem but still no results. I am still new to JS and my code's a bit rough but I'm pretty sure that's not the cause of the issue.
JS:
//function of skip buttons on song blocks
songPlaylist.addEventListener("DOMNodeInserted", function() {
iconList = document.querySelectorAll(".deleteIcon");
iconList.forEach(function(element) {
element.addEventListener('click', function() {
var nameOfSong = this.parentNode.childNodes[0].dataset.name;
var indexByName = songQueue.indexOf(nameOfSong);
var selectedBlock = this.parentNode;
if (songQueue.length == 1) {
songQueue.shift();
songPlaylist.removeChild(songPlaylist.firstChild);
var emptyMsgSpan = document.createElement("div");
emptyMsgSpan.className += "emptyMsgSpan";
var emptyMsg = document.createTextNode("Playlist is empty! How 'bout adding some music?");
emptyMsgSpan.appendChild(emptyMsg);
document.getElementById("playlistContainer").appendChild(emptyMsgSpan);
setTimeout(function() {
audioPlayer.src = "";
}, 1000);
} else {
songQueue.splice(indexByName,1); // <--- press first block output delete everything
// press any block after first deletes everything beneath it
songPlaylist.removeChild(selectedBlock);
for (var blockIndex = indexByName; blockIndex <= songQueue.length; blockIndex++) {
document.getElementById("playlistContainer").children[blockIndex].childNodes[1].dataset.index -= 1;
}
};
});
});
});
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">
<link rel="stylesheet" href="index.css">
<link href="https://fonts.googleapis.com/css?family=Bai+Jamjuree" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Jost&display=swap" rel="stylesheet">
<!--<div>Icons made by Roundicons from www.flaticon.com</div>-->
<title>Mue - Custom Playlist</title>
</head>
<body>
<div id="bg">
<div class="titleBar">
<button style="background: none; border: none; cursor: pointer;" onclick="location.reload(); return false;">
<span>MUE</span>
</button>
</div>
<div class="songNameDisplay">
<span id="nowPlaying"></span>
</div>
<div class="trackContainer">
<div class="btn play"></div>
<div class="audioTrack">
<div class="trackBtn"></div>
</div>
<div id="skipBtn">
<div class="triangle1"></div>
<div class="triangle2"></div>
<div class="rect"></div>
</div>
</div>
<button id="fileBtn" class="fileBtn"><span>Upload</span></button>
</div>
<audio id="audioPlayer" controls autoplay></audio>
<input type="file" id="file" />
<div id="playlistContainer"></div>
</body>
<script src="index.js"></script>
<script>
const bg = document.getElementById("bg");
window.addEventListener('scroll' , function() {
let offset= window.pageYOffset;
bg.style.backgroundPositionY = offset * 0.5 + "px";
});
</script>
</html>
Thanks in advance.

jQuery UI does not load on $("#content").load page for .button

I seem to make a mistake in the following:
html: index.html, main.html, etc
js: jQuery, jQuery UI, own.js, own_main.js
The end result should be an index page that based on a menu choice loads a html in a div.
The HTML that loads has a button element that I want to use with jQuery UI.
Index.html
<html lang="us">
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Dev</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/kendo.dataviz.default.min.css" rel="stylesheet" />
<link href="css/kendo.dataviz.min.css" rel="stylesheet" />
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<link href="css/jquery-ui-1.10.3.custom.css" rel="stylesheet">
<link href="css/typ.css" rel="stylesheet" />
<script src="js/modernizr-2.6.2-respond-1.1.0.min.js"></script>
<script src="Scripts/jquery-2.0.3.js"></script>
<script src="js/jquery-ui-1.10.3.custom.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/typ.js"></script>
<script src="js/typ-persons.js"></script>
</head>
<body>
<div id="content"></div>
</body>
</html>
typ.js file
function currentLoc(goToLoc) {
if (CheckLogin() == 0) {
//Not logged in, go to main
$("#content").load("/main.html");
window.localStorage.globalLocation = "/main.html";
} else {
if (goToLoc == '') {
console.log("No GoToLoc: " + goToLoc);
if (window.localStorage.globalLocation == '') {
console.log("No Global location");
$("#content").load("/main.html");
window.localStorage.globalLocation = "/main.html";
} else {
console.log("Global Location " + window.localStorage.globalLocation);
$("#content").load(window.localStorage.globalLocation);
}
} else {
console.log("GoToLoc " + goToLoc);
$("#content").load(goToLoc);
window.localStorage.globalLocation = goToLoc;
}
}
}
persons.html
<script src="js/typ-persons.js"></script>
<div class="container">
<style>
#toolbar {
padding: 4px;
display: inline-block;
}
/* support: IE7 */
* + html #toolbar {
display: inline;
}
</style>
<div id="toolbar" style="width:100%;" class="ui-widget-header ui-corner-all">
<button id="btnNew" ></button>
<button id="btnSave"></button>
<label for="persons">Find Person by Name or ID: </label>
<input type="text" class="input-sm" id="persons">
<input type="hidden" id="person-id">
</div>
</div>
typ-persons.js
$(function () {
$("#btnNew").button({
text: false,
label: "New Person",
icons: {
primary: "ui-icon-document"
}
})
.click(function () {
});
$("#btnSave").button({
text: false,
label: "Save",
disabled: true,
icons: {
primary: "ui-icon-disk"
}
})
.click(function () {
});
});
On the persons page there is also an autocomplete element with json data.
This works like a charm.
The problem is that the toolbar does not get the buttons applied from the typ-persons.js.
When I add the jQuery UI to the persons.html the buttons do work and get styled as they are supposed to.
The problem then is that jQuery UI loads twice and the autocomplete drowdown disappears on mouse over.
Kind of a paradox here and I would like both to work.
Thanks for your help,
Joris
I have the hunch that your persons.html file is the main.html addressed in the code. Otherwise I can't see where do you load persons.html or what are you loading when you load main.html.
Why are you adding typ-persons.js to persons.html, if you already have it in your main html file? In the way it's added, there's going to be double binding on button clicks. More than once, I believe. It would work on first load and then screw button behavior for good.
EDIT: After OP clarifications, these are my suggestions.
First: instead of putting new JS into persons html, make it just plain html. Make sure you don't use id attributes when that content is prone to be loaded several times. In that case, it's best to use classes.
<div class="container">
<style>
#toolbar {
padding: 4px;
display: inline-block;
}
/* support: IE7 */
* + html #toolbar {
display: inline;
}
</style>
<div id="toolbar" style="width:100%;" class="ui-widget-header ui-corner-all">
<button class="btnNew" ></button>
<button class="btnSave"></button>
<label for="persons">Find Person by Name or ID: </label>
<input type="text" class="input-sm" id="persons">
<input type="hidden" id="person-id">
</div>
</div>
Second: since you won't load new JS in that ajax call, you need to give the new buttons their behavior somewhere, right? Try to do that after they're appended, using jQuery's callback. I'd reccomend you use get method instead of load to have a bit more control on new content. Instead of
$("#content").load("/persons.html");
Try
$.get("/persons.html",function(responseText) {
var newElement=jQuery(responseText);
$("#content").append(newElement);
$(".btnNew", newElement).button({
text: false,
label: "New Person",
icons: {
primary: "ui-icon-document"
}
}).click(function () {
});
$(".btnSave",newElement).button({
text: false,
label: "Save",
disabled: true,
icons: {
primary: "ui-icon-disk"
}
}).click(function () {
});
});
Third: whatever listener you need to be set on dynamic elements, delegate them to the document to avoid needing to redeclare it (with the risk of double binding). I see no examples of this in your original post, but if you have any case of click, focus, or blur listeners (to name a few) I'll include a practical example.

Swipe images in phoneap + jquery issue

I am building a phonegap app using javacsript and jquery.I wrote this piece of code to swipe images.
$('#fullscreen').swipeleft(function () {
//Show next image
showNext();
alert('Left');
});
function showNext() {
$("#fullscreen").attr('src', "images/next.png");
}
But when I swipe, the image doesn't change and I get the error "09-13 14:49:21.188: W/webview(20238): Miss a drag as we are waiting for WebCore's response for touch down."
After browsing through some forums I added the following code.
var fullScr = document.getElementById("fullscreen");
fullScr.addEventListener( "touchstart", function(e){ onStart(e); }, false );
function onStart ( touchEvent ) {
if( navigator.userAgent.match(/Android/i) ) {
touchEvent.preventDefault();
}
}
But it still doesn't work.Although when I change my screen orientation from portrait to landscape, the image changes.
What is it that happens when I change the orientation and how could I get it working in the same orientation (portrait/landscape) please?
Thanks in advance.
Well it worked for me :S... I used version 1.5.0 of Cordova and run the app on Android simulator 4.0.3. Could you try the following example?
HTML content:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<!-- BASIC INCLUDES - TO BE MODIFIED ACCORDING TO YOUR CONVENIENCE -->
<link rel="stylesheet" href="./css/jquery.structure-1.1.0.min.css" />
<link rel="stylesheet" href="./css/jquery.mobile-1.1.0.min.css" />
<script type="text/javascript" charset="utf-8" src="cordova-1.5.0.js"></script>
<script type="text/javascript" src="./js/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="./js/jquery.mobile-1.1.0.min.js"></script>
<!-- END - BASIC INCLUDES -->
<script type="text/javascript" charset="utf-8">
$(function() {
$('#fullscreen').swipeleft(function () {
//Show next image
showNext();
});
function showNext() {
$("#fullscreen").attr('src', "./images/next.png");
}
});
</script>
</head>
<body>
<div data-role="page">
<div data-role="content">
<img id="fullscreen" src="./images/previous.png"></img>
</div>
</div>
</body>
</html>
NB: Make sure of the following things:
Modify the source of the "basic includes" of the code to your convenience (source of the CSS / JS files of jQuery / jQuery Mobile)
Change the source of the version of cordova if yours is not 1.5.0
Hope this will work for you too. Anyway, let me know about your result.

Categories

Resources