Print page with javascript styling - javascript

I have a page with 60 different inputs. They are all numbers and need to be checked against one of the inputs. If that input is 3 greater than the parent div changes to red. Everything works beautifully except if I try to print the style I give through my javascript function (document.getElementById(classid).style.backgroundColor = "red";) does not display print. How do I get the page to print with the style given by the function?
<script type="text/javascript">
function CheckThisNumber(val, id){
var x = document.getElementById("a6").value;
var y = Number(x) +3;
var classid = "p" + id;
if((val)>=y) {
document.getElementById(classid).style.backgroundColor = "red"; }
else { document.getElementById(classid).style.backgroundColor = "white"; }
}
</script>
One of the many inputs:
<div class="a1" id="pa1">
<strong>A1</strong><br><input type="number" name="a1" id="a1" style="width:95%" onKeyUp="CheckThisNumber(this.value,this.id)">
</div>

As I said in the comments, it is based on the browser's print settings. You can enable it in the browser's settings and it would just print them normally, but by default it is disabled to save ink.
Some browser support a non-standard CSS to force the BG to print
-webkit-print-color-adjust: exact
info: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust
And another fall back would be to use box shadows
.redBG { box-shadow: inset 0 0 0 100px #FF0000; }
.whiteBG { box-shadow: inset 0 0 0 100px #FFFFFF; }
If you are using it on a large textarea, you might need to set the 100px to a much larger value.

Related

Detects when an element cross any div of a certain class

I have a dark-colored menu that sometimes crosses over sections with the same dark background, so am trying to switch its class to change its colors everytime it crosses over dark colored sections.
$(window).scroll(function(){
var fixed = $("section.fixed-header");
var fixed_position = $("section.fixed-header").offset().top;
var fixed_height = $("section.fixed-header").height();
var toCross_position = $(".dark").offset().top;
var toCross_height = $(".dark").height();
if (fixed_position + fixed_height < toCross_position) {
fixed.removeClass('light-menu');
} else if (fixed_position > toCross_position + toCross_height) {
fixed.removeClass('light-menu');
} else {
fixed.addClass('light-menu');
}
});
This works fine when I only have one div with the dark class inside the same page. However, if there are several different divs with the dark class inside the same page, it will only work for the first div. How could I include all the other divs with the same dark class in here?
Instead of listening to scroll event you should have a look at Intersection Observer (IO).
This was designed to solve problems like yours. And it is much more performant than listening to scroll events and then calculating the position yourself.
Of course you can continue using just scroll events, the official Polyfill from W3C uses scroll events to emulate IO for older browsers. Listening for scroll event and calculating position is not performant, especially if there are multiple elements. So if you care about user experience I really recommend using IO. Just wanted to add this answer to show what the modern solution for such a problem would be.
I took my time to create an example based on IO, this should get you started.
Basically I defined two thresholds: One for 20 and one for 90%. If the element is 90% in the viewport then it's save to assume it will cover the header. So I set the class for the header to the element that is 90% in view.
Second threshold is for 20%, here we have to check if the element comes from the top or from the bottom into view. If it's visible 20% from the top then it will overlap with the header.
Adjust these values and adapt the logic as you see.
Edit: Edited it according to your comment, please note that you may see the effect better if you remove the console.log from my code so they don't clutter up your view.
I added one div where the header doesn't change (the green one)
const sections = document.querySelectorAll('.menu');
const config = {
rootMargin: '0px',
threshold: [.2, .9]
};
const observer = new IntersectionObserver(function (entries, self) {
entries.forEach(entry => {
console.log(entry); // log the IO entry for demo purposes
console.log(entry.target); // here you have the Element itself.
// you can test for className here for example
if (entry.isIntersecting) {
var headerEl = document.querySelector('header');
if (entry.intersectionRatio > 0.9) {
//intersection ratio bigger than 90%
//-> set header according to target
headerEl.className=entry.target.dataset.header;
} else {
//-> check if element is coming from top or from bottom into view
if (entry.target.getBoundingClientRect().top < 0 ) {
headerEl.className=entry.target.dataset.header;
}
}
}
});
}, config);
sections.forEach(section => {
observer.observe(section);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.g-100vh {
height: 100vh
}
header {
min-height: 50px;
position: fixed;
background-color: green;
width: 100%;
}
header.white-menu {
color: white;
background-color: black;
}
header.black-menu {
color: black;
background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
<p>Header Content </p>
</header>
<div class="grid-30-span g-100vh menu" style="background-color:darkblue;" data-header="white-menu">
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
data-src="/images/example_darkblue.jpg"
class="lazyload"
alt="<?php echo $title; ?>">
</div>
<div class="grid-30-span g-100vh no-menu" style="background-color:green;" data-header="black-menu">
<h1> Here no change happens</h1>
<p>it stays at whatever state it was before, depending on if you scrolled up or down </p>
</div>
<div class="grid-30-span g-100vh menu" style="background-color:lightgrey;" data-header="black-menu">
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
data-src="/images/example_lightgrey.jpg"
class="lazyload"
alt="<?php echo $title; ?>">
</div>
The reason is that however the JQuery selector selects all elements with .dark classes, when you chain the .offset().top or .height() methods on it, it will only save the first one into the variable:
var toCross_position = $(".dark").offset().top;
var toCross_height = $(".dark").height();
You could map all positions and heights into arrays and then you should also make the
var toCross_position = $(".dark").offset().top;
var toCross_height = $(".dark").height();
// only the first div's pos and height:
console.log(toCross_height, toCross_position);
var positions = $('.dark').toArray().map(elem => $(elem).offset().top);
var heights = $('.dark').toArray().map(elem => $(elem).height());
console.log('all .dark positions:', positions);
console.log('all .dark heights:', heights);
.dark {
background-color: #222;
color: white;
margin-bottom: 2rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="dark">Dark</div>
<div class="dark">Dark</div>
<div class="dark">Dark</div>
<div class="dark">Dark</div>
check if your header crosses them by looping through those values.

Limit input to textarea without unnecessary constraints

I am looking for a method to limit input to a textarea in a way that enables user input to stay within a specified area WITHOUT unnecessary constraints to maximum number of characters.
The obvious method is maxlength, but that means maxlength will be determined by how much space an all caps input would take up, and that will require a maxlength that is unnecessarily low.
There are also various JS / jQuery solutions that limit the amount of lines possible to input in a text area (e.g. Limit number of lines in textarea and Display line count using jQuery), but these solutions, as far as I have been able to find, are dependent on the ENTER key, but doesn’t work if you copy-paste a piece of text into the text area.
To clarify
<!doctype html>
<head>
<style>
.one{
height: 60px;
width: 55px;
background-color: pink;
font-size: 16px;
}
</style>
</head>
<body>
<div class="one">i i i i i i i i i i i i i i i i i i</div>
<br>
<div class="one">M M M M M M M M M</div>
</body>
</html>
Div one can contain 18 lowercase “i” but only 9 capital “M”, so in order to ensure input would never exceed div one, the maxlength would have to be set to 9. The general result would be that the Div one area would generally not be fully used.
The above is merely a simple example to quickly explain which output I desire. The solution should ofc be tied to an input via a form textfield.
Ideas?
Cheers
I can't see this being an easy problem to solve. There is probably someone out there with more expertise than I, but the only way I can immediately think of to do this is to create a Map of characters and to assign them a width. Using this map, you could compare any new input against the map and determine how long/wide the input is.
Example pseudo code, this probably won't work as is;
// YOUR CHAR MAP WITH WIDTHS ASSIGNED TO LETTERS
var charMap = {
i: 1,
M: 2
}
// MAX AMOUNT OF CHARACTERS
var charLimit = 18;
// ASSUME THE TEXTAREA IS EMPTY, COULD GET ACTUAL WIDTH HERE INSTEAD
var currentChars = 0;
$('textarea').on('change', function{
// GET ALL NEW INPUT
var chars = $(this).val();
// FOR LIMITING THE INPUT, THIS IS THE FINAL STRING THAT WILL END UP IN THE TEXTBOX
var limitedUserInput = '';
// CHECK EACH CHAR ONE BY ONE, COMPARING ITS WIDTH USING THE MAP
for(var x = 0; x < chars.length; x++){
currentChars += chars[x];
// IF SIZE LIMIT NOT HIT, ADD CHARACTER TO OUTPUT STRING
if(currentChars < charLimit){
limitedUserInput += chars[x];
}
}
// DISPLAY THE OUTPUT IN THE TEXT AREA (TRIMMING ANY EXTRA CONTENT)
$(this).html = limitedUserInput;
})
This would allow you to have 18 x charMap.i (18) or 9 x charMap.M (18).
I hope that makes some kind of sense.
Here's my bid on a solution to the problem. There are a few bugs, but I'm quite satisfied with it.
I spend a lot of time trying to work something out by counting lines in the text area, but abandoned the effort as I came across increasingly complex solutions.
This solution depends on the div height and trims a .substring generated from the textarea user input so it fits within the desired div, in this case myDiv. The trimed string is also put into a second textarea which will be the one used in the form.
<!doctype html>
<head>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<style>
.myDiv{
min-height: 100px;
width: 100px;
background-color: pink;
position: absolute;
}
#mySecondDiv{
background-color: transparent;
border: 1px solid black;
};
</style>
</head>
<body>
<textarea id='userInput' cols="30" rows="7"></textarea>
<textarea id="toBeStored"></textarea>
<div class='myDiv'></div>
<div class='myDiv'></div>
<div class='myDiv' id='mySecondDiv'></div>
<script>
//For live versions set the 'left' property for .myDiv(0) and #toBeStored to negative so they are off screen
$('.myDiv').eq(0).offset({ top: 200, left: 350 });
$('#toBeStored').offset({ top: 10, left: 350});
$('.myDiv').eq(1).offset({ top: 200, left: 10 });
$('.myDiv').eq(2).offset({ top: 200, left: 10 });
var currentMaxChars = 0;
var testString = "";
var myDivHeight = $('.myDiv').height()
$(document).ready(function(){
while($('.myDiv').eq(0).height() <= myDivHeight ){
testString += " i";
$('.myDiv').eq(0).html(testString);
currentMaxChars++;
};
currentMaxChars = currentMaxChars*2;
maxChars = currentMaxChars;
$("#userInput").on('change keyup paste', function() {
var input = $(this).val().replace(/\n/g, '<br/>');
$('.myDiv').eq(1).html(input);
var str = $('#userInput').val().replace(/\n/g, '<br/>');
if(str.length == currentMaxChars){
currentMaxChars = maxChars;
};
if($('.myDiv').eq(0).height() <= myDivHeight){
$('.myDiv').eq(0).html(str.substring(0, currentMaxChars));
$('#toBeStored').html(str.substring(0, currentMaxChars));
} else {
while($('.myDiv').eq(0).height() > myDivHeight){
currentMaxChars--;
$('.myDiv').eq(0).html(str.substring(0, currentMaxChars));
$('#toBeStored').html(str.substring(0, currentMaxChars));
};
};
});
});
</script>
</body>
</html>

Refresh a page with new div grid

I'm trying to make a grid of divs that, when mouseentered change color. Then, when the a button is clicked and new number is entered to then generate a new grid with a side length of that many divs. I'm new to javascript and jQuery and can't figure out why my code won't generate the divs.
here's my script
$('.block').mouseenter(function () {
$(this).css('background-color', 'black');
});
function newGrid(x) {
for (i = 0; i > x * x; i++) {
$('.container').append('<div class="block"></div>');
}
$('.block').height(960 / );
$('.block').width(960 / );
}
function clearContainer() {
$('.block').remove();
}
function askGrid() {
var num = prompt("enter box length");
clearContainer();
newGrid(num);
}
function firstGrid() {
newGrid(16);
$('#reset').click(function () {
askGrid();
});
}
$(document).ready(firstGrid);
here's my css
.container {
margin: 30px auto 0px auto;
height: 960px;
width: 960px;
border: 1px solid black;
}
.block {
border:0px;
margin:0px;
padding:0px;
float:left;
background-color: yellow;
}
#reset {
display:block;
padding:5px 20px;
margin:0 auto;
}
html has a css reset and in the body i have a button with id="reset" and a div with class="container"
thanks!
Several problems:
The slash when setting height and width is wrong (either is 960 divided by something or just 960)
The for loop is wrong: it should be
for (i = 0; i < x * x; i++)
And the css thing is not going to apply since there are no .block elements when executed. You should probably move it into newGrid
You have a bug here for (i = 0; i > x * x; i++) it should be i < x.
And im not sure what this is
$('.block').height(960 / );
$('.block').width(960 / );
you can set the height and width respectively in the css
Also you need to this for the mouseenter event to work
$('.container').on('mouseenter','.block',function () {
$(this).css('background-color', 'black');
});
Since the items added are dynamic.
Welcome to jquery, a world of excitement and pain!
This code
$('.block').mouseenter(function () {
$(this).css('background-color', 'black');
});
binds the hover function to all existing .block elements on the page when it is run. It's at the top of your script so it'll execute once, binding this property to all .block elements when the page loads, but not to .block elements created after. To fix this add it inside your "newGrid" function so it rebinds each new element as they are created.
In your loop, you want for (i = 1; i < x * x; i++), starting index from 1 rather than 0, or else you'll have an off by 1 error and create an extra box.
To set the proper heights of .block, you want to divide your .container's dimentions by x, the size of block:
$('.block').height(960 / x);
$('.block').width(960 / x);
The following are general programming tips:
As a good practice, functions should have a specific job and only do that job. I moved the clearContainer call to inside newGrid, because it should be the function that builds the new grid that clears the old one, not the one called askGrid. askGrid should do as it is named, and only ask for your new grid dimension.
You should do a validation on the number received through askGrid. If the user types something that isn't a number, or a negative number, or 0, you shouldn't start making boxes or newGrid will break. I added a loop to keep asking for a size until a proper dimension is provided, but you can chose your behaviour.
I changed the variable "x" to "block_length" since variables should be given names indicative of that they mean, so that there aren't a bunch of mysterious variables all over the place called x, y, z that you can't tell what they mean from a glance.
Demo in this fiddle!

How to trace a computational error in JavaScript

I am working on developing a web site that dynamically creates a table and highlights prime numbers for the user at http://www.primenumbertable.com. I thought I had the computational flow mapped out properly, but after I included the ability for the user to include a starting point, something fell apart.
Instead of computing tables to the range specified, tables sometimes get cut short. For instance, if the user specifies that they want to check 100 numbers, and have a starting point of 1, the table will only generate numbers 1-9, instead of 1-100.
I even broke out a pen and pad and tried to do the computations step-by-step myself, to see where the error was coming, but my pen and pad calculations had no computational anomalies.
It seemed to me that the value that was being input was somehow getting the last "0" cut off before going into the table, but i couldn't find how that was happening. Then, I thought that this could not be the problem, because when i try to check 99 numbers, I get a table that goes all the way up to 102!
So, I really have two questions: 1 - How do I trace where the computational error is being made, and 2 - Can anyone see a fix for what is going wrong?
The following is my source code:
<!DOCTYPE HTML>
<html lang="en">
<!-- This page asks the user to input a number to search for primes and returns a base-6 table with primes highlighted -->
<head>
<meta charset="utf-8">
<meta name="keywords" content="prime numbers, prime, primes, prime twins">
<title>Prime Numbers</title>
<script type="text/javascript">
/* This function determines if a number is prime or not */
function isPrime(n) {
if (isNaN(n) || !isFinite(n) || n%1 || n<2) return false;
if (n%2==0) return (n==2);
if (n%3==0) return (n==3);
var m=Math.sqrt(n);
for (var i=5;i<=m;i+=6) {
if (n%i==0) return false;
if (n%(i+2)==0) return false;
}
return true;
}
/* This function creates the table and color codes the cells of prime numbers */
function tableCreate(X,Y){
var numCheck = X; /* assigns numCheck the value the user input for how many numbers are to be checked*/
var numRow = numCheck/6; /* assigns the value that will be used as the number of rows in the table. */
var numCell = Y; /* assigns the value that will be used in the table cell */
var body = document.body; /* assigns the value of the document body */
var tbl = document.createElement('table'); /* creates a table dynamically to be filled */
var highlightColor = document.getElementById('highlight').value; /* assign the value of the color the user requested for highlighting primes */
if(isNaN(numCheck)==true){
document.getElementById('tablearea').innerHTML='Please enter a number in arabic numerals.';
return; /* if the user did not enter a number to check, the function will instruct the user to do so properly. */
}
else{
for(var i = 0; i < numRow; i++){ /*continues the loop until the proper number of rows have been dynamically filled */
var tr = tbl.insertRow(-1); /* inserts a new row at the bottom */
for(var j = 0; j < 6; j++){ /*continues the loop until all data cells in the row have been filled */
if(i==numRow && j==6 || numCheck==(numCell + Y)-1){
break
}
else {
var td = tr.insertCell(-1); /* inserts a new data cell into the row */
if(isPrime(numCell) == true){ /* calls the function isPrime to test if the number going into the data cell is a prime */
if(highlightColor == ''){
td.style.backgroundColor='yellow'; /* uses the color yellow to highlight a cell if the user failed to specify a color */
}
else{
td.style.backgroundColor=highlightColor; /* uses the user's choice of color to highlight the cell if the number going in is prime */
}
}
td.appendChild(document.createTextNode(numCell)); /* prints the number in the data cell */
numCell++; /* increases the count of the number of numbers checked by 1 */
}
}
}
document.getElementById('tablearea').innerHTML=''; /* clears any previous tables that were written */
document.getElementById('tablearea').appendChild(tbl); /* writes the new table */
document.getElementById('backtotop').innerHTML="Back to top"; /* puts a 'back to top' link at the bottom */
document.getElementById('backtotop').href="#top"; /* links the btt link to the top */
}
}
/* This function clears the tablearea when called */
function tableClear(){
document.getElementById('tablearea').innerHTML='';
document.getElementById('backtotop').innerHTML='';
}
</script>
<style type="text/css">
body{
background-image: url('primesbackground.png');
}
h1{
width: 700px;
margin: auto;
text-align: center;
background-color: white;
}
table{
width: 50%;
border: 1px solid black;
background-color: gray;
position: relative;
}
td{
border: 1px solid black;
background-color: white;
}
.parameters{
float: left;
width: 300px;
height: 100%;
margin: 10px;
display: inline-block;
}
.tablearea{
text-align: center;
display: inline-block;
}
</style>
</head>
<body>
<a id="top"></a>
<h1>Welcome to the Prime Number Table Generator.</h1>
<div>
<div class="parameters">
<form name="primes">
<p style="text-align: center; margin: 10px">
How many numbers would you like to check for primes?<br />
<input type="text" id="nums"><br />
What number would you like to use as a starting point?<br />
<input type="text" id="startpoint"><br />
What color would you like primes highlighted?<br />
<input type="text" id="highlight"><br />
<input type="button" value="Check'em!" onClick="tableCreate(document.primes.nums.value,document.primes.startpoint.value)">
<input type="reset" onClick="tableClear()"><br />
To suggest improvements to this site, please send an email to webmaster#primenumbertable.com.<br />
</p>
</form>
</div>
<div id="tablearea" class="tablearea">
<!-- This area is filled by the function tableCreate() -->
</div>
<p style="text-align: center; float: bottom"></p>
</div>
</body>
</html>
Chrome also has developer tools (press F12)
It seems to be a problem with your numRow property.
var numRow = numCheck/6;
When numCheck is 100, this sets numRow to be a floating point number: 16.666666666666668
Later you're checking this value to break out of your for loop
if(i==numRow && j==6 || numCheck==(numCell + Y)-1){
but i will never equal numRow because i is an integer and numRow is a float
I would try and parse numCheck to be an integer using the parseInt method by replacing this line
var numRow = numCheck/6;
with
var numRow = parseInt(numCheck/6);
Using Google Chrome, you can insert log in your JavaScript like this: console.log("YOUR LOG");. You can then enter the developer tools (press F12) and select the console tab to check the logs.
I have looked into your code, the main problem lies in the following if condition in your tableCreate method:
if(i==numRow && j==6 || numCheck==(numCell + Y)-1){
break
}
Javascript interprets numCell as string, so numCell + Y becomes string concatenation. You should force Javascript to perform integer computation to fix your issue:
var count = parseInt(numCell) + parseInt(Y) - 1;
if(i==numRow && j==6 || numCheck==count){
break
}

How to mark line numbers in javascript ace editor?

As you can see in the following screenshot:
Ace editors have a 'gutter' on the left-hand side that contains the line numbers. I would like to detect a click on this gutter and insert a marker for a breakpoint, as in the following screenshot from chrome dev tools
I've had a look at the Ace editor API, but can't figure out how to do it, could someone tell me the best way to go about it?
Thanks
See this thread https://groups.google.com/d/msg/ace-discuss/sfGv4tRWZdY/ca1LuolbLnAJ
you can use this function
editor.on("guttermousedown", function(e) {
var target = e.domEvent.target;
if (target.className.indexOf("ace_gutter-cell") == -1)
return;
if (!editor.isFocused())
return;
if (e.clientX > 25 + target.getBoundingClientRect().left)
return;
var row = e.getDocumentPosition().row;
e.editor.session.setBreakpoint(row);
e.stop();
})
and don't forget to add some styling for breakpoints e.g.
.ace_gutter-cell.ace_breakpoint{
border-radius: 20px 0px 0px 20px;
box-shadow: 0px 0px 1px 1px red inset;
}
Breakpoints are often toggled. To achieve this behavior, use
...
var breakpoints = e.editor.session.getBreakpoints(row, 0);
var row = e.getDocumentPosition().row;
if(typeof breakpoints[row] === typeof undefined)
e.editor.session.setBreakpoint(row);
else
e.editor.session.clearBreakpoint(row);
...
Notice the strange use of EditSession.getBreakpoints(), which doesn't return an array of row numbers as documentation suggests, but rather an array with indices corresponding to the row numbers.

Categories

Resources