I am working on a project to have a random word guessing game. So far most of the code is working but I am trying to implement some rules on the length of words displayed to the user as a measure of game difficulty (shorter words = easier, etc). I am using a drop-down menu to get the user's setting selection, and then have rules in the JS tags that are supposed to be handling this.
After toying around with this for several days, I was hoping that a fresh pair of eyes might have a suggestion about where I am going wrong to be able to enforce the rules I am trying to enforce?
The specific functions that should be handling this are setDifficulty(), getSelection(), and randomWord()
<html lang="en">
<head>
<style>
body {
background-color: rgb(231, 223, 223);
align-content: center;
margin: 2px;
padding: auto;
}
h1 {
text-align: center;
font-family:'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
border: rgb(187, 212, 235);
margin: auto;
}
h4 {
text-align: center;
font-family:'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
margin: auto;
}
div {
text-align: center;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
background-color: rgb(231, 223, 223);
}
button {
background-color: rgba(65, 127, 207, 0.781);
color: rgb(255, 255, 255);
padding: 1%;
margin-bottom: 2%;
flex-wrap: wrap;
font-size: xx-large;
border: 3px;
border-radius: 5px;
}
button:disabled {
background-color: rgba(65, 127, 207, 0.363);
}
label {
text-align: center;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
border: 3px;
border-radius: 5px;
}
</style>
<meta charset="UTF-8">
<title>Word Guessing Game</title>
</head>
<body>
<label for="difficulty">Choose difficulty level:</label>
<select name="difficulty" id="difficulty_setting">
<option value="Easy" onclick="setDifficulty()">Easy</option>
<option value="Medium" onclick="setDifficulty()">Medium</option>
<option value="Hard" onclick="setDifficulty()">Hard</option>
</select>
<div class="container">
<h1 class="text-center">Random Word Guessing Game</h1>
<div class="float-right" style="position: absolute; text-align: left;">Wrong Guesses: <span id='mistakes'>0</span> of <span id='maxWrong'></span></div>
<div class="text-center">
<h3>Guess the word:</h3>
<p style="font-size: 56px;" id="wordSpotlight">The word to be guessed goes here</p>
</div>
<div id="keyboard"></div>
<button class="btn btn-info" onClick="restart()">Restart</button>
</div>
<script type="text/javascript">
let random_words = [
"plankton",
"pitman",
"dexamethasone",
"marabout",
"wintertime",
"trencherman",
"subtilize",
"cursorial",
"asterism",
"jam",
"bacteriostat",
"unworn",
"nonuniformity",
"subpart",
"groats",
"quintette",
"blowtube",
"ethnographical",
"bulbous",
"cataphoretic",
"difficult",
"opacify",
"credence",
"sextette",
"mot",
"prosthodontics",
"whippletree",
"life",
"cook",
"toxic",
"quadrature",
"tawdrily",
"escalader",
"clincher",
"ataxia",
"chiton",
"pains",
"straining",
"tenderize",
"circadian",
"wreak",
"foam",
"artemisia",
"pietistic",
"commemoration",
"excise",
"phalanger",
"decidua",
"cinematography",
"supportable",
"unspoilt",
"hermeneutics",
"whipsaw",
"quartan",
"transportable",
"imbrue",
"oxtongue",
"flogging",
"intramolecular",
"mechanism",
"busted",
"talker",
"sedum",
"glial",
"youthful",
"deviationist",
"headpin",
"realise",
"hygiene",
"worst",
"isosmotic",
"narcoleptic",
"confidently",
"boneset",
"tugboat",
"bimanual",
"daredeviltry",
"bris",
"trip",
"notably",
"repartee",
"suckling",
"hymnody",
"pleating",
"graffiti",
"assuredly",
"moment",
"isotropic",
"absconder",
"microspore",
"adobe",
"photoconductivity",
"stray",
"stalk",
"squelch",
"animistic",
"pretentiousness",
"unsmoothed",
"goalmouth",
"exclusiveness",
"bullpen",
"unasked",
"dilettantish",
"dedication",
"happily",
"squealer",
"perineurium",
"whatchamacallit",
"appreciativeness",
"topographically",
"conjuncture",
"resurvey",
"vaned",
"homo",
"upcurved",
"houseful",
"microdot",
"hated",
"literature",
"hydrophilic",
"collie",
"phycoerythrin",
"canine",
"unmanful",
"scrim",
"wanted",
"enantiomorphism",
"theologian",
"gastronomical",
"bura",
"malocclusion",
"superincumbent",
"circumferential",
"interrelated",
"calamine",
"subsidizer",
"sarcoplasm",
"eagerly",
"incautiously",
"priorship",
"gooseneck",
"wearisome",
"preciously",
"lust",
"liger",
"ovary",
"garganey",
"slather",
"hisser",
"counterfoil",
"divisible",
"hypochondria",
"statute",
"education",
"byword",
"damp",
"hornbeam",
"levity",
"nucha",
"fauteuil",
"rho",
"soothsaying",
"decreased",
"faze",
"lamia",
"above",
"artful",
"schmuck",
"stocked",
"carabiner",
"incomparably",
"unfaithfully",
"parturient",
"erotism",
"menu",
"pall",
"technical",
"stile",
"expulsion",
"spitball",
"doubting",
"wheelchair",
"aptly",
"aedes",
"successfulness",
"abductor",
"offerer",
"bloody",
"tenderheartedness",
"amusive",
"streptococci",
"gnaw",
"curiousness",
"hemorrhage",
"theologise",
"uninhabited",
"strep",
"unadoptable",
"prophetic",
"somite",
"pythoness",
"governable",
"churlish",
"craniate",
"confusion",
"smilingly",
"accruement",
"oftener",
"coho",
"scripture",
"unprovoked",
"adenohypophysis",
"fitter",
"pronouncement",
"replacing",
"custodial",
"dynamiter",
"vespers",
"hostility",
"knoll",
"vendor",
"sprig",
"stave",
"raphia",
"canfield",
"paint",
"data",
"teleconference",
"tractability",
"knit",
"amazement",
"airfield",
"cesium",
"galactic",
"axial",
"buffalo",
"unsaddled",
"pygmy",
"brewer",
"hazel",
"inauthentic",
"herrenvolk",
"uncommercialized",
"exasperatingly",
"irony",
"solan",
"subsequence",
"outclass",
"etch",
"regalia",
"unanswered",
"prospective",
"rumormonger",
"forecastle",
"mineralogy",
"adorability",
"photogravure",
"pronucleus",
"underpopulated",
"disgrace",
"smutch",
"ohmage",
"cabomba",
"emptying",
"wordsmith",
"charitable",
"sadomasochism",
"web",
"railroader",
"allow",
"pennon",
"preservation",
"mollah",
"prematurity",
"puzzlement",
"megaloblast",
"adulterating",
"dowager",
"shirtfront",
"exchequer",
"transplanter",
"turntable",
"heedlessness",
"escapist",
"calf",
"aortic",
"rumored",
"sagamore",
"form",
"settle",
"persuasiveness",
"ineptitude",
"trembles",
"navigator",
"gabbro",
"disappear",
"thermocouple",
"spay",
"frisking",
"haft"
]
let answer = '';
let maxWrong = 8;
let mistakes = 0;
let guessed = [];
let wordStatus = null;
function handleGuess(chosenLetter) {
guessed.indexOf(chosenLetter) === -1 ? guessed.push(chosenLetter) : null;
document.getElementById(chosenLetter).setAttribute('disabled', true);
if (answer.indexOf(chosenLetter) >= 0) {
guessedWord();
checkIfGameWon();
} else if (answer.indexOf(chosenLetter) === -1) {
mistakes++;
updateMistakes();
checkIfGameLost();
updateHangmanPicture();
}
}
function checkIfGameWon() {
if (wordStatus === answer) {
document.getElementById('keyboard').innerHTML = 'You Won!!!';
}
}
function checkIfGameLost() {
if (mistakes === maxWrong) {
document.getElementById('wordSpotlight').innerHTML = 'The answer was: ' + answer;
document.getElementById('keyboard').innerHTML = 'You Lost!!!';
}
}
function guessedWord() {
wordStatus = answer.split('').map(letter => (guessed.indexOf(letter) >= 0 ? letter : " _ ")).join('');
document.getElementById('wordSpotlight').innerHTML = wordStatus;
}
function updateMistakes() {
document.getElementById('mistakes').innerHTML = mistakes;
}
function generateButtons() {
let buttonsHTML = 'abcdefghijklmnopqrstuvwxyz'.split('').map(letter =>
`
<button
class="btn btn-lg btn-primary m-2"
id='` + letter + `'
onClick="handleGuess('` + letter + `')"
>
` + letter + `
</button>
`).join('');
document.getElementById('keyboard').innerHTML = buttonsHTML;
}
function restart() {
mistakes = 0;
guessed = [];
randomWord();
guessedWord();
updateMistakes();
generateButtons();
}
function setDifficulty() {
mistakes = 0;
guessed = [];
randomWord();
guessedWord();
updateMistakes();
generateButtons();
}
document.getElementById('maxWrong').innerHTML = maxWrong;
var diff_setting = document.getElementById('difficulty_setting');
randomWord();
generateButtons();
guessedWord();
function getSelection(){
// select difficulty
//var selection = diff_setting;
let easy_game = random_words.filter((easy_words) => {
if(easy_words.length < 6){
return easy_words;}});
let medium_game = random_words.filter((med_words) => {
if(med_words.length <= 9){
return med_words;}});
let hard_game = random_words.filter((hard_words) => {
if(hard_words.length > 9){
return hard_words;}});
alert(diff_setting.value);
if(diff_setting.value == 'Easy'){
return easy_game;
} else if (diff_setting.value == 'Medium'){
return medium_game;
} else {
return hard_game;}
}
function randomWord() {
var arr = getSelection();
answer = random_words[Math.floor(Math.random() * arr.length - 1)];
}
</script>
</body>
</html>'''
Let's start by saving the difficulty setting in a variable along these :
let answer = '';
let maxWrong = 8;
let mistakes = 0;
let guessed = [];
let wordStatus = null;
let diff_setting = 'Easy';
then edit the setdifficulty function to change that variable
function setDifficulty(difficulty) {
diff_setting = difficulty;
mistakes = 0;
guessed = [];
randomWord();
guessedWord();
updateMistakes();
generateButtons();
}
then call the function each time the setting is changed
<label for="difficulty">Choose difficulty level:</label>
<select name="difficulty" id="difficulty_setting" onchange=" setDifficulty(this.value)">
<option value="Easy" >Easy</option>
<option value="Medium">Medium</option>
<option value="Hard">Hard</option>
</select>
comment this as its not needed anymore
// var diff_setting = document.getElementById('difficulty_setting');
and correct this :
let medium_game = random_words.filter((med_words) => {
if(med_words.length <= 9 && med_words.length>=6){
return med_words;}});
as it was also selecting words that are both medium and easy
also the randomWord function used to select a word from the unfiltered array not the new one you created so it would look like this :
function randomWord() {
var arr = getSelection();
answer = arr[Math.floor(Math.random() * arr.length - 1)];
}
and finally getSelection() should look like this :
function getSelection(){
// select difficulty
//var selection = diff_setting;
let easy_game = random_words.filter((easy_words) => {
if(easy_words.length < 6){
return easy_words;}});
let medium_game = random_words.filter((med_words) => {
if(med_words.length <= 9 && med_words.length>6){
return med_words;}});
let hard_game = random_words.filter((hard_words) => {
if(hard_words.length > 9){
return hard_words;}});
alert(diff_setting);
if(diff_setting == 'Easy'){
return easy_game;
} else if (diff_setting == 'Medium'){
return medium_game;
} else if(diff_setting == 'Hard'){
return hard_game;}
}
now it should work fine :)
I'm making a basic calculator and so far it "works". Users can only enter in a single digit from their keyboard. If they want to use double digits they're going to have to use the arrows in the text box. How can I make it so that users can enter in double digit numbers? If the user tries to type in double digit numbers the second number only get stored (so typing in 25 will only store 5)
// Base Variables
let result = 0;
let numb1 = 0;
let numb2 = 0;
let firstNumberEntered = false;
//This will be rewritten
let calculationDescription = `${numb1} + ${numb2}`;
document.querySelector('#input-number').addEventListener('keypress', numbersInput);
function numbersInput(e) {
if (!firstNumberEntered && e.key === 'Enter') {
numb1 = document.getElementById("input-number").value;
firstNumberEntered = true;
document.getElementById("input-number").innerHTML = "";
} else if (firstNumberEntered && e.key === 'Enter') {
numb2 = document.getElementById("input-number").value;
firstNumberEntered = false;
console.log(`${numb1} and ${numb2}`);
}
document.getElementById("input-number").value = "";
}
document.querySelector("#btn-add").addEventListener('click', sumNumbs);
document.querySelector("#btn-subtract").addEventListener('click', subtractNumbs);
document.querySelector("#btn-multiply").addEventListener('click', multiplyNumbs);
document.querySelector("#btn-divide").addEventListener('click', divideNumbs);
function sumNumbs() {
let numb1Final = parseInt(numb1);
let numb2Final = parseInt(numb2);
result = numb1Final + numb2Final;
calculationDescription = `${numb1} + ${numb2}`;
outputResult(result, calculationDescription);
}
function subtractNumbs() {
let numb1Final = parseInt(numb1);
let numb2Final = parseInt(numb2);
result = numb1Final - numb2Final;
calculationDescription = `${numb1} - ${numb2}`;
outputResult(result, calculationDescription);
}
function multiplyNumbs() {
let numb1Final = parseInt(numb1);
let numb2Final = parseInt(numb2);
result = numb1Final * numb2Final;
calculationDescription = `${numb1} x ${numb2}`;
outputResult(result, calculationDescription);
}
function divideNumbs() {
let numb1Final = parseInt(numb1);
let numb2Final = parseInt(numb2);
result = numb1Final / numb2Final;
calculationDescription = `${numb1} / ${numb2}`;
outputResult(result, calculationDescription);
}
<section id="calculator">
<input type="number" id="input-number" />
<div id="calc-actions">
<button type="button" id="btn-add">+</button>
<button type="button" id="btn-subtract">-</button>
<button type="button" id="btn-multiply">*</button>
<button type="button" id="btn-divide">/</button>
</div>
</section>
All this does is grab the elements on the HTML page and put them into variables and send info back to be displayed
const userInput = document.getElementById('input-number');
const addBtn = document.getElementById('btn-add');
const subtractBtn = document.getElementById('btn-subtract');
const multiplyBtn = document.getElementById('btn-multiply');
const divideBtn = document.getElementById('btn-divide');
const currentResultOutput = document.getElementById('current-result');
const currentCalculationOutput = document.getElementById('current-calculation');
function outputResult(result, text) {
currentResultOutput.textContent = result;
currentCalculationOutput.textContent = text;
}
Not sure if providing my CSS is necessary, but let me know and I'll make a change.
I just started learning JavaScript recently. I watched a few videos on a Udemy tutorial on doing this project, but I stopped watching and tried to figure the rest out myself.
What I did try doing was adding maxlength="6" to my HTML input element, but that didn't work.
function numbersInput(e) {
if(!firstNumberEntered && e.key === 'Enter') {
numb1 = document.getElementById("input-number").value;
firstNumberEntered = true;
document.getElementById("input-number").innerHTML = "";
document.getElementById("input-number").value = "";
}
else if(firstNumberEntered && e.key === 'Enter') {
numb2 = document.getElementById("input-number").value;
firstNumberEntered = false;
console.log(`${numb1} and ${numb2}`);
document.getElementById("input-number").value = "";
}
}
Add document.getElementById("input-number").value = "";
to the end of both if statements and remove from the end of the function
Here's my own basic calculator using HTML, CSS, and javascript only.
To be able to input one or more digit numbers, use arrays to function as storage of those numbers chosen and for your chosen arithmetic operation as well.
please see my source code for a clearer grasp of my idea.
//index.html
<!DOCTYPE html>
<html>
<head>
<title>My HTML/CSS/JS Calculator</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="outer-container">
<div class="items" id="items"></div>
<div class="calc-screen">
<div id="screen"></div>
</div>
<div class="keys-container">
<button type="button" class="keys" id="opm" onclick="opm()">*</button>
<button type="button" class="keys" id="opd" onclick="opd()">/</button>
<button type="button" class="keys" id="opa" onclick="opa()">+</button>
<button type="button" class="keys" id="ops" onclick="ops()">-</button>
<button type="button" class="keys" id="num9" onclick="num9()">9</button>
<button type="button" class="keys" id="num8" onclick="num8()">8</button>
<button type="button" class="keys" id="num7" onclick="num7()">7</button>
<button type="button" class="keys" id="num6" onclick="num6()">6</button>
<button type="button" class="keys" id="num5" onclick="num5()">5</button>
<button type="button" class="keys" id="num4" onclick="num4()">4</button>
<button type="button" class="keys" id="num3" onclick="num3()">3</button>
<button type="button" class="keys" id="num2" onclick="num2()">2</button>
<button type="button" class="keys" id="num1" onclick="num1()">1</button>
<button type="button" class="keys" id="num0" onclick="num0()">0</button>
<button type="button" class="keys" id="del" onclick="del()">Del</button>
<button type="button" class="keys" id="clr" onclick="clr()">Clr</button>
<button type="submit" class="keys" id="equals" onclick='equals()'>=</button>
</div>
</div>
<script type="text/javascript" src="js/js.js"></script>
</body>
</html>
//js.js
var item1, op, item2, arr1, arr2, text, x, prod, qout, sum, diff, a, b, c;
item1, item2, op = '';
arr1 = [];
arr2 = [];
function num9() {
if (op=='') {
arr1.push(document.getElementById("num9").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num9").innerHTML);
arr2Function();
}
}
function num8() {
if (op=='') {
arr1.push(document.getElementById("num8").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num8").innerHTML);
arr2Function();
}
}
function num7() {
if (op=='') {
arr1.push(document.getElementById("num7").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num7").innerHTML);
arr2Function();
}
}
function num6() {
if (op=='') {
arr1.push(document.getElementById("num6").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num6").innerHTML);
arr2Function();
}
}
function num5() {
if (op=='') {
arr1.push(document.getElementById("num5").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num5").innerHTML);
arr2Function();
}
}
function num4() {
if (op=='') {
arr1.push(document.getElementById("num4").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num4").innerHTML);
arr2Function();
}
}
function num3() {
if (op=='') {
arr1.push(document.getElementById("num3").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num3").innerHTML);
arr2Function();
}
}
function num2() {
if (op=='') {
arr1.push(document.getElementById("num2").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num2").innerHTML);
arr2Function();
}
}
function num1() {
if (op=='') {
arr1.push(document.getElementById("num1").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num1").innerHTML);
arr2Function();
}
}
function num0() {
if (op=='') {
arr1.push(document.getElementById("num0").innerHTML);
arr1Function();
}
else {
arr2.push(document.getElementById("num0").innerHTML);
arr2Function();
}
}
function opm() {
if (arr1=='') {
document.getElementById("screen").innerHTML = "Please press a number first!";
}
else if (op!='' && arr2!='') {
console.log("press equal sign");
}
else {
document.getElementById("screen").innerHTML = document.getElementById("opm").innerHTML;
op = '*';
console.log(op);
}
}
function opd() {
if (arr1=='') {
document.getElementById("screen").innerHTML = "Please press a number first!";
}
else if (op!='' && arr2!='') {
console.log("press equal sign");
}
else {
document.getElementById("screen").innerHTML = document.getElementById("opd").innerHTML;
op = '/';
console.log(op);
}
}
function opa() {
if (arr1=='') {
document.getElementById("screen").innerHTML = "Please press a number first!";
}
else if (op!='' && arr2!='') {
console.log("press equal sign");
}
else {
document.getElementById("screen").innerHTML = document.getElementById("opa").innerHTML;
op = '+';
console.log(op);
}
}
function ops() {
if (arr1=='') {
document.getElementById("screen").innerHTML = "Please press a number first!";
}
else if (op!='' && arr2!='') {
console.log("press equal sign");
}
else {
document.getElementById("screen").innerHTML = document.getElementById("ops").innerHTML;
op = '-';
console.log(op);
}
}
function equals() {
a = parseInt(item1); b = parseInt(item2);
if (op == '*') {
prod = a * b;
document.getElementById("items").innerHTML = a+' '+op+' '+b+' =';
c = prod;
document.getElementById("screen").innerHTML = c;
console.log('product: '+c);
result(c);
}
else if (op == '/') {
qout = a / b;
document.getElementById("items").innerHTML = a+' '+op+' '+b+' =';
c = qout;
document.getElementById("screen").innerHTML = c;
console.log('qoutient: '+c);
result(c);
}
else if (op == '+') {
sum = a + b;
document.getElementById("items").innerHTML = a+' '+op+' '+b+' =';
c = sum;
document.getElementById("screen").innerHTML = c;
console.log('sum: '+c);
result(c);
}
else if (op == '-') {
diff = a - b;
document.getElementById("items").innerHTML = a+' '+op+' '+b+ ' =';
c = diff;
document.getElementById("screen").innerHTML = c;
console.log('difference: '+c);
result(c);
}
else {
document.getElementById("screen").innerHTML = "Please press a number first!";
}
}
function result() {
console.log('function result: '+c);
arr1=[]; arr2=[]; item1, item2, op = '';
item1 = c;
console.log('function result new item1: '+item1);
arr1.push(item1);
arr1Function();
}
function del() {
if (arr1!='' && op=='' && arr2=='') {
arr1.pop();
console.log(arr1);
arr1Function();
}
else if (arr1!='' && op!='' && arr2=='') {
op = '';
document.getElementById("screen").innerHTML = op;
}
else if (arr1!='' && op!='' && arr2!='') {
arr2.pop();
console.log(arr2);
arr2Function();
}
}
function clr() {
arr1=[]; arr2=[]; item1,item2,op='';
console.log(arr1+', '+op+', '+arr2+', '+item1+', '+item2);
document.getElementById("screen").innerHTML = '';
document.getElementById("items").innerHTML = '';
}
function arr1Function() {
document.getElementById("screen").innerHTML = arr1;
text = ""; arr1.forEach(myFunction); text += "";
function myFunction(value) {
text += value;
x = parseInt(text);
document.getElementById("screen").innerHTML = x;
item1 = x;
console.log("Arr 1 Parse: "+x);
console.log("Arr 1: "+arr1);
console.log("Item 1: "+item1);
}
}
function arr2Function() {
document.getElementById("screen").innerHTML = arr2;
text = ""; arr2.forEach(myFunction); text += "";
function myFunction(value) {
text += value;
x = parseInt(text);
document.getElementById("screen").innerHTML = x;
item2 = x;
console.log("Arr 2 Parse: "+x);
console.log("Arr 2: "+arr2);
console.log("Item 2: "+item2);
}
}
//css
body {
background-color: orange;
}
.outer-container {
position: static;
background-color: black;
margin: auto;
border: solid black 2px;
width: 350px;
padding: 20px;
box-sizing: border-box;
border-radius: 20px;
}
.items {
background-color: silver;
border: solid white 1px;
display: inline-block;
color: black;
max-width: 100%;
font-size: 16px;
height: 20px;
box-sizing: border-box;
}
.calc-screen {
padding: 10px;
border: solid white 1px;
max-width: 100%;
width: 100%;
height: 50px;
background-color: silver;
color: white;
font-size: 25px;
box-sizing: border-box;
overflow-x: auto;
}
.keys-container {
margin-top: 20px;
width: 100%;
border: solid white 1px;
max-width: 100%;
display: inline-block;
}
#equals {
width: 100%;
}
.keys {
float: left;
border: solid black 1px;
box-sizing: border-box;
width: 25%;
height: 40px;
box-sizing: border-box;
text-align: center;
margin: auto;
font-size: 25px;
padding: 5px;
}
.keys:hover {
background-color: blue;
color: white;
}
Assume I have a page with an input box. The user types something into the input box and hits a button. The button triggers a function that picks up the value typed into the text box and outputs it onto the page beneath the text box for whatever reason.
Now this has been disturbingly difficult to find a definitive answer on or I wouldn't be asking but how would you go about outputting this string:
<script>alert("hello")</script> <h1> Hello World </h1>
So that neither the script is executed nor the HTML element is displayed?
What I'm really asking here is if there is a standard method of avoiding both HTML and Script injection in Javascript. Everyone seems to have a different way of doing it (I'm using jQuery so I know I can simply output the string to the text element rather than the html element for instance, that's not the point though).
You can encode the < and > to their HTML equivelant.
html = html.replace(/</g, "<").replace(/>/g, ">");
How to display HTML tags as plain text
myDiv.textContent = arbitraryHtmlString
as #Dan pointed out, do not use innerHTML, even in nodes you don't append to the document because deffered callbacks and scripts are always executed. You can check this https://gomakethings.com/preventing-cross-site-scripting-attacks-when-using-innerhtml-in-vanilla-javascript/ for more info.
A one-liner:
var encodedMsg = $('<div />').text(message).html();
See it work:
https://jsfiddle.net/TimothyKanski/wnt8o12j/
I use this function htmlentities($string):
$msg = "<script>alert("hello")</script> <h1> Hello World </h1>"
$msg = htmlentities($msg);
echo $msg;
From here
var string="<script>...</script>";
string=encodeURIComponent(string); // %3Cscript%3E...%3C/script%3
My solution using typescript + decorators + regex
const removeTag = new RegExp("(<[a-zA-Z0-9]+>)|(</[a-zA-Z0-9]+>)", "g");
return value.replace(removeTag, "");
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
function filter(target) {
return class extends target {
constructor(...args) {
super(...args);
}
setState(opts) {
const state = {
username: this.filter(opts.username),
password: this.filter(opts.password),
};
super.setState(state);
}
filter(value) {
const removeTag = new RegExp("(<[a-zA-Z0-9]+>)|(</[a-zA-Z0-9]+>)", "g");
return value.replace(removeTag, "");
}
};
}
let Form = class Form {
constructor() {
this.state = {
username: "",
password: "",
};
}
setState(opts) {
this.state = {
...this.state,
...opts,
};
}
getState() {
return this.state;
}
};
Form = __decorate([
filter,
__metadata("design:paramtypes", [])
], Form);
function getElement(key) {
return document.getElementById(key);
}
const button = getElement("btn");
const username = getElement("username");
const password = getElement("password");
const usernameOutput = getElement("username-output");
const passwordOutput = getElement("password-output");
function handleClick() {
const form = new Form();
form.setState({ username: username.value, password: password.value });
usernameOutput.innerHTML = `Username: ${form.getState().username}`;
passwordOutput.innerHTML = `Password: ${form.getState().password}`;
}
button.onclick = handleClick;
<!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" />
<style>
:root {
--bg: #1d1907;
--foreground: #e3e0cd;
--primary: #cfb53b;
--black: #333;
--white: #fafafa;
}
#keyframes borderColor {
from {
border-bottom: 1px solid var(--foreground);
}
to {
border-bottom: 1px solid var(--primary);
}
}
* {
outline: none;
border: none;
}
body {
padding: 0.5rem;
font-family: "Fira Code";
background-color: var(--bg);
color: var(--foreground);
}
input {
border-bottom: 1px solid var(--foreground);
background-color: var(--black);
color: var(--foreground);
padding: 0.5rem;
}
input:focus {
animation-name: borderColor;
animation-duration: 3s;
animation-fill-mode: forwards;
}
button {
padding: 0.5rem;
border-radius: 3px;
border: 1px solid var(--primary);
background-color: var(--primary);
color: var(--white);
}
button:hover,
button:active {
background-color: var(--white);
color: var(--primary);
}
.form {
margin-bottom: 2rem;
}
</style>
<title>Decorator</title>
</head>
<body>
<h1>Prevent Injection</h1>
<div class="form">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" placeholder="Type your username" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" placeholder="Type your password" />
</div>
<div class="form-group">
<button id="btn">Enviar</button>
</div>
</div>
<div class="form-result">
<p id="username-output">Username:</p>
<p id="password-output">Password:</p>
</div>
<script src="/dist/pratica1.js"></script>
</body>
</html>
Typescript Code bellow:
type State = {
username: string;
password: string;
};
function filter<T extends new (...args: any[]) => any>(target: T): T {
return class extends target {
constructor(...args: any[]) {
super(...args);
}
setState(opts: State) {
const state = {
username: this.filter(opts.username),
password: this.filter(opts.password),
};
super.setState(state);
}
filter(value: string) {
const removeTag = new RegExp("(<[a-zA-Z0-9]+>)|(</[a-zA-Z0-9]+>)", "g");
return value.replace(removeTag, "");
}
};
}
#filter
class Form {
private state: State;
constructor() {
this.state = {
username: "",
password: "",
};
}
setState(opts: State) {
this.state = {
...this.state,
...opts,
};
}
getState() {
return this.state;
}
}
function getElement(key: string): HTMLElement | null {
return document.getElementById(key);
}
const button = getElement("btn") as HTMLButtonElement;
const username = getElement("username") as HTMLInputElement;
const password = getElement("password") as HTMLInputElement;
const usernameOutput = getElement("username-output") as HTMLParagraphElement;
const passwordOutput = getElement("password-output") as HTMLParagraphElement;
function handleClick() {
const form = new Form();
form.setState({ username: username.value, password: password.value });
usernameOutput.innerHTML = `Username: ${form.getState().username}`;
passwordOutput.innerHTML = `Password: ${form.getState().password}`;
}
button.onclick = handleClick;
Try this method to convert a 'string that could potentially contain html code' to 'text format':
$msg = "<div></div>";
$safe_msg = htmlspecialchars($msg, ENT_QUOTES);
echo $safe_msg;
Hope this helps!
Use this,
function restrict(elem){
var tf = _(elem);
var rx = new RegExp;
if(elem == "email"){
rx = /[ '"]/gi;
}else if(elem == "search" || elem == "comment"){
rx = /[^a-z 0-9.,?]/gi;
}else{
rx = /[^a-z0-9]/gi;
}
tf.value = tf.value.replace(rx , "" );
}
On the backend, for java , Try using StringUtils class or a custom script.
public static String HTMLEncode(String aTagFragment) {
final StringBuffer result = new StringBuffer();
final StringCharacterIterator iterator = new
StringCharacterIterator(aTagFragment);
char character = iterator.current();
while (character != StringCharacterIterator.DONE )
{
if (character == '<')
result.append("<");
else if (character == '>')
result.append(">");
else if (character == '\"')
result.append(""");
else if (character == '\'')
result.append("'");
else if (character == '\\')
result.append("\");
else if (character == '&')
result.append("&");
else {
//the char is not a special one
//add it to the result as is
result.append(character);
}
character = iterator.next();
}
return result.toString();
}