Adding HTML web app to WordPress - javascript

I have created a small application locally on my machine using HTML, CSS and JavaScript. I am using a plugin to run the JavaScript on the site. My small application loads different pictures from drop down lists and uses a SendMail JavaScript function as well. How can I add this page as one of my WordPress pages? I used a BlankSlate plugin to clean one of my pages up and whenever I paste my code into the page it gets scrambled and doesent work. It loads my drop down lists and some titles but pictures are gone and background isnt present. I am new to using WordPress and I want to add this small app to my site. Any help would be great or suggestions and how to copy it over. ( Sorry for the messy, unorganized code. Still learning and practicing, but this is what I am trying to turn into a page )
<html lang="en"><head>
<meta charset="utf-8">
<meta name="description" content=" A page for exploring html documents">
<title>BuildIt-AR App</title>
<head>
<link href="https://fonts.googleapis.com/css?family=Rock+Salt" rel="stylesheet">
</head>
<style>
.body {max-width:1920px; margin:0 auto;}
.centered {max-width:720px; margin:0 auto;}
.floatLeft {
float:left;}
select {
display:block; clear:both;
}
.myBox{
clear:both;
max-width: 375px;
max-height: 225px;
padding-top:275px;
}
.textlines {
padding-top:350px;
}
body{
background-image: url("https://www.xmple.com/wallpaper/grey-gradient-linear-1920x1080-c2-708090-dcdcdc-a-285-f-14.svg");
background-repeat: repeat-x;
border: 5px inset lightgrey;
}
font{
font-family: 'Rock Salt', cursive;
position: fixed;
font-size: 350%;
top: 20%;
left: 50%;
margin-top: -50px;
margin-left: -100px;
letter-spacing: 3px;
text-shadow: 2.2px 1.5px grey;
}
select{
}
</style>
<script type="application/javascript">
var pictureList1 = [
"http://i66.tinypic.com/xds135.png",
"http://i68.tinypic.com/28cdhxh.png",
"http://i66.tinypic.com/169s4mc.png",
];
function change_image(id) {
var idx = document.getElementById('picDD').value - 1; // javascript is zero-indexed
document.getElementById('pic').src = pictureList1[idx];
y = document.getElementById("picDD");
//x.value = y.options[y.selectedIndex].text;
document.getElementById("stock").value = stock[y.selectedIndex];
}
var pictureList2 = [
"http://i65.tinypic.com/2wmqefs.png",
"http://i63.tinypic.com/s4za11.png",
"http://i66.tinypic.com/6e3ibq.png",
];
function change_image2(id) {
var idx = document.getElementById('picDD2').value - 1; // javascript is zero-indexed
document.getElementById('pic2').src = pictureList2[idx];
y = document.getElementById("picDD2");
//x.value = y.options[y.selectedIndex].text;
document.getElementById("body").value = body[y.selectedIndex];
}
var pictureList3 = [
"http://i65.tinypic.com/2n9dslt.png",
" http://i65.tinypic.com/289h35y.png",
"http://i64.tinypic.com/vxnpzd.png",
];
function change_image3(id) {
var idx = document.getElementById('picDD3').value - 1; // javascript is zero-indexed
document.getElementById('pic3').src = pictureList3[idx];
y = document.getElementById("picDD3");
//x.value = y.options[y.selectedIndex].text;
document.getElementById("barrel").value = barrel[y.selectedIndex];
}
var barrel = new Array();
var body = new Array();
var stock = new Array();
barrel[0] = "Assault Barrel $89.95";
body[0] = "BlackOut Body $231.95";
stock[0] = "Slide Stock $78.95";
barrel[1] = "Sniper Barrel $395.95";
body[1] = "SlideFire Body $278.95";
stock[1] = "Fold Stock $178.95";
barrel[2] = "Tactical Barrel $278.95";
body[2] = "Green Body $134.95";
stock[2] = "Steady Stock $78.95";
barrel[3] = 4;
body[3] = "asmith";
stock[3] = "Andy Smith";
// function change_image3() {
//x = document.getElementById("users");
//
function sendMail() {
var link = "mailto:example#gmail.com"
+ "?cc=gunbuilder#builditar.com"
+ "&subject=" + escape("BuildIt-AR Order Form")
+ "&body=" + escape(document.getElementById('name').value + "\n" + document.getElementById('barrel').value + "\n" + document.getElementById('body').value + "\n" + document.getElementById('stock').value);
window.location.href = link;
}
</script>
</head>
<body>
<div class="centered">
<div class="floatLeft">
<img id="pic" src="http://i66.tinypic.com/xds135.png" class="myBox">
<select id="picDD" onchange="change_image();">
<option value="1" selected="">Stock #1</option>
<option value="2">Stock #2</option>
<option value="3">Stock #3</option>
</select>
</div></div>
<div class="floatLeft">
<img id="pic2" src="http://i65.tinypic.com/2wmqefs.png" class="myBox">
<select id="picDD2" onchange="change_image2();">
<option value="1" selected="">Body #1</option>
<option value="2">Body #2</option>
<option value="3">Body #3</option>
</select>
</div>
<div class="floatLeft">
<img id="pic3" src="http://i64.tinypic.com/vxnpzd.png" class="myBox">
<select id="picDD3" onchange="change_image3();">
<option value="1" selected="">Barrel #1</option>
<option value="2">Barrel #2</option>
<option value="3">Barrel #3</option>
</select>
</div>
<div class="textlines">
<input type="text" placeholder="<Name>" id="name">
<p>Barrel <input type="text" id="barrel" name="id" ></p>
<p>Body <input type="text" id="body" name="username" ></p>
<p>Stock <input type="text" id="stock" name="full_name" ></p>
<font size="10">BuildIt-AR</font>
<button onclick="sendMail(); return false">Send</button>
</body></html>

I think it's best to create a custom shortcode for this. Something like [buildit], this code then get's replaced by your app code.
You could use a free plugin like Snippy to do this. Full disclosure, I'm the author of the plugin.
Snippy lets you can create your own shortcodes and pick names for them. Then you can add pieces of HTML, CSS, and JavaScript to the shortcode (in Snippy these are named "bits"). You then place the shortcode on a page or post, and Snippy will output your HTML instead. A lot easier than learning the WordPress API or modify PHP files.
In your situation, I would advise to copy all the HTML inside the <body> tag and add it to an HTML "bit". You can move the font embed <link> in there as well. Snippy will take it from there.

Create a new page http://your-site.com/wp-admin/post-new.php?post_type=page then create a new page template in your theme folder
wp-content/your-theme/page-{slug}.php
and in that file add your app. If you like you can even create custom header and footer files too.
wp-content/your-theme/header-app.php
wp-content/your-theme/footer-app.php
Then in your page-{slug}.php file just add
<?php get_header('app'); ?>
<!-- your content -->
<?php get_footer('app'); ?>

Related

Unexpected duplication of form output

I'm currently making a program for my players in an RPG to be able to select their character skills from drop-down menus which will 1. Display the title of the skill under the results section and also in the Selected Advantages section(top right). 2. Display the description of the skill under its title.
It is working mostly as intended except for a bug I have discovered. I can select the desired advantage and it will appear as expected. It will also remove the selection when I click on the delete button under the Selected Advantages section at the top right of the page.
The problem is that if I reselect the same advantage it will display the advantage description twice at the bottom of the page, if I do the same again it will display three times, and so on.
When I delete a selection the container is removed but when they are selected again the subsequent descriptions are also contained in a single container instead of creating a new one.
Here is my code so far.
Note: I have only included the object for Absolute Direction but have tested with others and get the same duplication result.
const createDivElement = document.createElement('div');
//Creates containers for the selected advantage descriptions.
function createContainer(advantageName) {
const placeAdvantageDescription = document.getElementById('place-text');
placeAdvantageDescription.appendChild(createDivElement);
createDivElement.setAttribute("id", `container-${advantageName}`);
}
//Creates and adds the text for the selected advantages title, points and description.
//should I make this three seperate functions???
function addAdvantageText(advantageObject) {
const createTitleElement = document.createElement('p');
const createPointsElement = document.createElement('p');
const createDescriptionElement = document.createElement('p');
//creates Title
createDivElement.append(createTitleElement);
createTitleElement.classList.add("title");
createTitleElement.innerText = advantageObject.title;
//creates points
createDivElement.append(createPointsElement);
createPointsElement.classList.add("points");
createPointsElement.innerText = `${advantageObject.points}.`;
//creates description
createDivElement.append(createDescriptionElement);
createDescriptionElement.classList.add("description-text");
createDescriptionElement.innerHTML = advantageObject.description;
}
//creates sub catagories for selected advantage and adds the extra text if applicable.
function addSubCategories(advantageObject) {
if (advantageObject.subCategory1) {
let createSubCategory1 = document.createElement('p');
createDivElement.append(createSubCategory1);
createSubCategory1.innerHTML = `<strong>${advantageObject.subCategory1.name}:</strong> ${advantageObject.subCategory1.text}<br><strong><em>${advantageObject.subCategory1.sub1Points}</em></strong>.`;
}
if (advantageObject.subCategory2) {
let createSubCategory2 = document.createElement('p');
createDivElement.append(createSubCategory2);
createSubCategory2.innerHTML = `<strong>${advantageObject.subCategory2.name}:</strong> ${advantageObject.subCategory2.text}<br><strong><em>${advantageObject.subCategory2.sub2Points}</em></strong>.`;
}
if (advantageObject.subCategory3) {
let createSubCategory3 = document.createElement('p');
createDivElement.append(createSubCategory3);
createSubCategory3.innerHTML = `<strong>${advantageObject.subCategory3.name}:</strong> ${advantageObject.subCategory3.text}<br><strong><em>${advantageObject.subCategory3.sub3Points}</em></strong>.`;
}
if (advantageObject.subCategory4) {
let createSubCategory4 = document.createElement('p');
createDivElement.append(createSubCategory4);
createSubCategory4.innerHTML = `<strong>${advantageObject.subCategory4.name}:</strong> ${advantageObject.subCategory4.text}<br><strong><em>${advantageObject.subCategory4.sub4Points}</em></strong>.`;
}
if (advantageObject.extraText) {
let createExtraText = document.createElement('p');
createDivElement.appendChild(createExtraText);
createExtraText.innerHTML = advantageObject.extraText;
}
}
//adds name of chosen advantages in Selected Advantages column and a delete button for each.
function addToSelectedColumn(advantageName) {
const hr = document.createElement('hr');
const button = document.createElement('button');
const createSelectedAdvantageDiv = document.createElement('div');
const placeSelectedText = document.getElementById('selected-items');
placeSelectedText.appendChild(createSelectedAdvantageDiv);
createSelectedAdvantageDiv.append(advantageName.toUpperCase());
createSelectedAdvantageDiv.setAttribute("id", `selected-items-container-${advantageName}`);
createSelectedAdvantageDiv.append(button);
button.setAttribute("id", `delete-${advantageName}`);
createSelectedAdvantageDiv.append(hr);
}
function removeAdvantageText(removeThis) {
let advantageDescriptionToRemove = document.getElementById(`container-${removeThis}`);
let selectedAdvantageToRemove = document.getElementById(`selected-items-container-${removeThis}`);
advantageDescriptionToRemove.remove();
selectedAdvantageToRemove.remove();
}
function removeAdvantage(advantageToDelete) {
document.getElementById(`delete-${advantageToDelete}`).addEventListener("click", function() {
removeAdvantageText(advantageToDelete);
})
};
function addAdvantage(advantageInString, advantageObjectName) {
createContainer(advantageInString);
addToSelectedColumn(advantageInString);
addAdvantageText(advantageObjectName);
addSubCategories(advantageObjectName);
}
//Event listeners for when users select advantage. They will check for matching selection then call addAdvantage() with arguments.
//AAAAAAAAAAAAAAAA
document.getElementById("submit-advantage-a").addEventListener("click", function(e) {
e.preventDefault();
const userAdvantageA = document.getElementById('user-advantages-a').value;
if (userAdvantageA === 'absolute direction') {
addAdvantage('absolute direction', absoluteDirection);
removeAdvantage('absolute direction');
} else if (userAdvantageA === 'absolute timing') {
addAdvantage('absolute timing', absoluteTiming);
removeAdvantage('absolute timing');
} else if (userAdvantageA === 'acute senses') {
addAdvantage('acute senses', acuteSenses);
removeAdvantage('acute senses');
}
});
let absoluteDirection = {
title: "Absolute Direction",
points: "5 or 10 points",
description: "You have an excellent sense of direction.This ability comes in two levels:",
subCategory1: {
name: "Absolute Direction",
text: "You always know which way is north, and you can always retrace a path you have followed within the past month, no matter how faint or confusing. This ability does not work in environments such as interstellar space or the limbo of the astral plane, but it does work underground, underwater, and on other planets. This gives +3 to Body Sense and Navigation (Air, Land, or Sea).<br> (Note: The navigational sense that guides migratory creatures to their destination is too crude to qualify; treat it as a 0-point feature.)",
sub1Points: "5 points"
},
subCategory2: {
name: "3D Spatial Sense",
text: "As above, but works in three dimensions. This ability is useful in deep space – although it does not help you if you travel across dimensions. You get the skill bonuses to Piloting and +2 to Aerobatics, Free Fall, and Navigation (Hyperspace or Space).",
sub2Points: "10 points"
}
}
.container {
border-bottom: solid 2px black;
padding: 1rem 2rem;
}
.title {
font-size: 1.5rem;
font-weight: bolder;
text-align: center;
}
.points {
font-weight: bold;
}
#selected-items-container {
float: right;
background-color: gray;
color: white;
text-align: center;
width: 20rem;
margin-right: 4rem;
}
.forms {
margin-left: 2rem;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script type="text/javascript" src="/script.js" async></script>
<title>GCRC</title>
</head>
<body>
<a id="home-nav" href="*">Home</a>
<div class="make-choice">
<div id="selected-items-container"><strong>SELECTED ADVANTAGES</strong>
<hr>
<div id="selected-items"></div>
</div>
<div class="forms">
<h1>Select your characters advantages</h1>
<p>A.</p>
<form method="GET">
<select name="user-advantages-a" id="user-advantages-a">
<option value="absolute direction">Absolute Direction</option>
<option value="absolute timing">Absolute Timing</option>
<option value="acute senses">Acute Senses</option>
</select>
<input id="submit-advantage-a" type="submit" />
</form>
<p>B.</p>
<form method="GET">
<select name="user-advantages-b" id="user-advantages-b">
<option value="binding">Binding</option>
<option value="blessed">Blessed</option>
<option value="brachiator">Brachiator</option>
</select>
<input id="submit-advantage-b" type="submit" />
</form>
<p>C.</p>
<form method="GET">
<select name="user-advantages-c" id="user-advantages-c">
<option value="catfall">Catfall</option>
<option value="chameleon">Chameleon</option>
<option value="channeling">Channeling</option>
</select>
<input id="submit-advantage-c" type="submit" />
</form>
<p>D.</p>
<form method="GET">
<select name="user-advantages-d" id="user-advantages-d">
<option value="damage resistance">Damage Resistance</option>
<option value="danger sense">Danger Sense</option>
<option value="daredevil">Daredevil</option>
</select>
<input id="submit-advantage-d" type="submit" />
</form>
</div>
</div>
<hr>
<div class="display-choice">
<p>Advantages</p>
<div class="advantages">
<div id="place-text"></div>
</div>
</div>
</body>
</html>

Span value inside a style value

this maybe a very stupid question, but is this possibe ?
well i have a sort of a slider on a html page.
this is what it shows up like now:
<p>Illustrator</p>
<div class="w3-light-grey w3-round-xlarge w3-small">
<div class="w3-container w3-center w3-round-xlarge w3-teal" style="width:75%">75%</div>
</div>
This shows up a bar,
well what want to achieve is if its possible to change that value 75% to my script data :
style="width:75%">
like i have a script, it retrieves values from my server:
var input = "10;11;15";
var arr = input.split(";");
document.getElementById("humid").innerHTML = (arr[0 ]);
this shows up my data just normal
<span id="humid">0</span>
what i want to do is something like this, but i don't know how:
I want this value from style="width:75%"> to be the humid value.
so if my humid value is 50% the width goes 50%
i did try this but no result
style="width:humid+%">
or style="width:(humid)+%">
i'm still learning,
regards
<!DOCTYPE html>
<html>
<title>TESt</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto'>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
html,body,h1,h2,h3,h4,h5,h6 {font-family: "Roboto", sans-serif}
</style>
<body class="w3-light-grey">
<p>Original</p>
<div class="w3-light-grey w3-round-xlarge w3-small">
<div class="w3-container w3-center w3-round-xlarge w3-teal" style="width:75%">75%</div>
</div>
<p>Media</p>
<div class="w3-light-grey w3-round-xlarge w3-small">
<div class="w3-container w3-center w3-round-xlarge w3-teal" style="#humid">0</div>
</body>
<script>
var input = "10;11;15";
var arr = input.split(";");
//alert(arr[1 ]);
document.getElementById("humid").innerHTML = (arr[0]);
document.getElementById("temp").innerHTML = (arr[1 ]);
document.getElementById("uv").innerHTML = (arr[2 ]);
</script>
</html>
Retrieve my input:
function readForestall() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("ForestAll").innerHTML =
this.responseText;
}
};
xhttp.open("GET", "readFORESTALL", false);
xhttp.send();
}
setInterval(function() {
readForestall();
}, 5000);
If I understand your question right, you want to change the width of an element based on a variable you receive. In that case you can change the inline style with JavaScript. You just need to grab the element and set the style by assigning values to the properties of the element's style property.
If you want to change the width, you can use the following:
element.style.width = '50%'
It sets the width to 50%. You can also include a variable like this:
const width = 50
element.style.width = `${width}%`
I've created a snippet below where you can set the value by using an input and it updates both the width and the content of that div. You can click on the "Run code snippet button" and see the result in live.
const barLeft = document.querySelector('#bar-left');
const barRight = document.querySelector('#bar-right');
const input = document.querySelector('[name="width"]');
const error = document.querySelector('.error');
input.addEventListener('input', (e) => {
const widthLeft = Number(e.target.value);
const widthRight = 100 - widthLeft;
if (widthLeft < 0 || widthLeft > 100) {
error.textContent =
"We don't do that here. Width must be between 0 and 100.";
return;
}
error.textContent = '';
barLeft.textContent = `${widthLeft}%`;
barLeft.style.width = `${widthLeft}%`;
barRight.textContent = `${widthRight}%`;
barRight.style.width = `${widthRight}%`;
});
body {
font-family: sans-serif;
margin: 0;
text-align: center;
}
.outer {
display: flex;
margin-bottom: 2rem;
}
.inner {
background-color: lightcoral;
box-shadow: 0 -4px 0 rgba(0, 0, 0, 0.2) inset;
height: 100%;
padding: 1rem;
}
.inner--blue {
background-color: lightblue;
}
.controls {
margin-bottom: 1rem;
}
input {
font-family: inherit;
font-size: inherit;
padding: 0.5rem 1rem;
}
.error {
color: #d32f2f;
}
<div class="outer">
<div class="inner" id="bar-left" style="width: 75%">75%</div>
<div class="inner inner--blue" id="bar-right" style="width: 25%">25%</div>
</div>
<div class="controls">
<label for="width">First bar's width:</label>
<input type="number" name="width" id="width" min="5" max="95" value="75" />
</div>
<div class="error"></div>
Update: Updated your example below. Make sure you close your tags, and check out how to add ids to elements.
<body class="w3-light-grey">
<p>Media</p>
<div class="w3-light-grey w3-round-xlarge w3-small">
<div class="w3-container w3-center w3-round-xlarge w3-teal" id="humid">
0
</div>
</div>
div>
<script>
var input = '10;11;15';
var arr = input.split(';');
// update the content of the div with ID "humid"
document.getElementById('humid').textContent = arr[0];
// change the width of the div with ID "humid"
document.getElementById('humid').style.width = `${arr[0]}%`;
</script>
</body>
Tranq,
i am not exactly sure why you would want to call the width from an array and use DOM when you can simply use CSS to accomplish this with #media instead. correct me if i am wrong, but you're just trying to adjust the width based on values of the current width of the device? this seems like a whole lot of work for what is a simple solution.
use something like to set the appropriate widths depending on the screen widths:
#media only screen and (max-width: 600px) {
#humid { width: 75%; }
}
also, it is likely you're not passing your array properly and it is returning NULL(0). you can check this via a debugger and ensure it is being passed properly. FireFox has a Great built in debugger for this. use CMD/CTRL+SHIFT+K to open the debugger in FireFox.
P.S. you are not passing the array properly. you're setting it to change the 'innerHTML' which changes everything inside of the
document.getElementById("humid").innerHTML = (arr[0 ]);
if you change "(arr[0 ]);" to something like "string" it will replace the value 0 to "string".

CSSStyleSheet.insertRule - trouble with indexing and dynamic variables using Javascript

I've read up on inserting css rules using Javascript and have managed to get it working (after some trial & error). So I have 2 questions:
Q.1 Why is an index < 1 not working - see Mozilla example (and many others) below:
// push a new rule onto the top of my stylesheet - doesn't work...
myStyle.insertRule("#blanc { color: white }", 0); // returns Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to insert the rule.
// change the index and it works!
myStyle.insertRule("#blanc { color: white }", 1);
This article by David Walsh (very helpful), explains that the default for index is -1. He uses 1 in his example, which is what worked for me. Anything less than 1, ie 0 or -1 (as per the default) threw the following errors:
Index -1 error:
Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': The index provided (4294967295) is larger than the maximum index (2071).
Index 0 error:
Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to insert the rule.
It's not a huge problem, but it does mean I can't control specificity. I can use !important or rework the css/inserted rule so that it overrides any existing styles, but as I'm just learning JavaScript, I'd really like to know why it's not working as expected. Does anyone have any ideas?
Q.2 Having got it to work using index 1, I now want to pull in values dynamically. I have the item names in an array, which is used to create multiple objects, inside which are the property values I want to use for the individual style rules for that object.
Basically what I'm trying to output is this (which works):
styleSheet.insertRule("#item { border-top-color: #000000; border-right-color: #ffffff; }", 1);
But using variables, something like this:
styleSheet.insertRule("[itemName] { border-top-color: [itemName.value1]; border-right-color: [itemName.value2]; }", 1); // itemName.valueX being the object's array item
I've tried heaps of things, but I can't get the array item bit to work, ie colour and colour4 should actually be itemName.value1/2 or a var that equals the same. This is the closest I've got so far...
styleSheet.insertRule("#" + name + " { border-top-color: " + colour + "; border-right-color: " + colour4 + " !important; }", 1); // 1st rule works, 2nd doesn't show anything
It all works lovely if I write it manually (as per the 1st example), but how to do it dynamically? I've found info on insertRule, but not using dynamic values - can anyone help/point me in the right direction?
Many thanks in advance!
Expanded WIP for more clarity:
function itemColours() {
for (i = 3; i < itemsArray.length; i++) {
let name = itemsArray[i];
let colour = #000000;
console.log(item1.value); // returns the hex value I want to use in the rule
styleSheet.insertRule("#" + name + " { border-top-color: " + colour + "; border-right-color: " + name + ".value !important; }", 1);
// rule 1 works, rule 2 doesn't...
}
Update 2
This demo:
can accept user data to use insertRule() and deleteRule().
has an Add Set button which will create and append a clone of the <form> part of the document
has 3 styleSheets Bootstrap [0], CSSOM, and the <style> tag.
Demo 4
// Just for demo
.as-console-wrapper {
width: 170px;
max-height: 40px;
transform: translateX(340px)
}
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' title='Bootstrap-3.3.7'>
<link href='https://glpjt.s3-us-west-1.amazonaws.com/ir/cssom.css' rel="stylesheet" title='CSSOM'>
<style title='Tag'>
body {
max-width: 96%;
visibility: hidden;
font: 400 16px/1.2 Verdana
}
ul.x-list.x-list {
margin-left: 0;
padding-left: 1em;
text-indent: -1em;
list-style-type: none;
}
li.x-item.x-item {
list-style: none;
line-height: 1.5;
}
.x-flex.x-flex {
display: flex;
justify-content: center;
align-items: center;
}
.x-col {
display: flex;
flex-direction: column
}
option::before {
content: attr(name)
}
#idx {
max-width: 6ch;
}
label {
margin: 10px auto 10px -15px
}
#add {
position: fixed;
z-index: 1;
top: 50px;
left: 20px
}
</style>
</head>
<body>
<main class='container' style='padding:50px 0 20px 20px'>
<form id='cssom' class='row x-col'>
<div class='btn-group col-sm-12'>
<input id='add' class='btn-lg btn-success' type='button' value='Add Set'>
</div>
<section class='row'>
<!--=================================[0]-->
<fieldset class='set0 col-sm-12'>
<hr>
<div class='row x-flex'>
<!--=================================[1]-->
<label class='form-control-label col-sm-2'>CSS Rule</label>
<textarea id='rul0' class='form-control col-sm-10' rows='2'>li.x-item.x-item::before {content: '\1f539\00a0';list-style:none;font-size:small;position:relative;bottom:2px}</textarea>
</div>
<div class='form-inline row'>
<label class='form-control-label col-sm-2'>Stylesheet</label>
<select id='sht0' class='form-control col-sm-4'>
<optgroup label="LINK">
<!--================================[3]-->
<option value='0' selected name='Bootstrap-3.3.7'> [0]</option>
<option value='1' name='CSSOM'> [1]</option>
</optgroup>
<optgroup label="STYLE">
<option value='2' name='Tag'> [2]</option>
</optgroup>
</select>
<label class='form-control-label col-sm-1'>Rule Index</label>
<input id='idx0' class='form-control col-sm-1' type='number' min='-1' value='0'>
<!--==========[4]-->
<div class="btn-group col-sm-4">
<!--=====[5]-->
<input id='ins0' class='btn btn-primary' type='button' value='Insert Rule' onclick='modRule(this)'>
<!--======[6]-->
<input id='del0' class='btn btn-danger' type='button' value='Delete Rule' onclick='modRule(this)'>
</div>
</div>
</fieldset>
</section>
<hr><br>
</form>
<hgroup class='x-inline'>
<!--====================================[hgroup.x-inline]-->
<h1 class='h1'>CSSStyleSheet</h1>
<h2 class='h2'>.insertRule()</h2>
</hgroup>
<article class='text-primary'>
<blockquote class='blockquote'>
<h3 id="Restrictions" class='h3'>Restrictions</h3>
<p>CSS stylesheet rule-lists have a number of intuitive and not-so-intuitive <a class="external" href="https://drafts.csswg.org/cssom/#insert-a-css-rule">restrictions</a> affecting how and where rules can be inserted. Violating these will likely
cause an error raised as a <a title="The DOMException interface represents an abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API." href="https://developer.mozilla.org/en-US/docs/Web/API/DOMException"><code>DOMException</code></a> </p>
<!--==========================[ul.x-list | li.x-fade]-->
<ul id='list' class='list-group-flush x-list'>
<li class='list-group-item-text fade x-fade x-item'>If index > number of rules in the stylesheet (the <a title="A CSSRuleList is an (indirect-modify only) array-like object containing an ordered collection of CSSRule objects." href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRuleList"><code>CSSRuleList</code></a>.length),
then aborts with IndexSizeError.</li>
<li class='list-group-item-warning x-item'>If rule cannot be inserted at index 0 due to some CSS constraint, then aborts with HierarchyRequestError.</li>
<li class='list-group-item-danger x-item'>If more than one rule is given in the rule parameter, then aborts with SyntaxError</li>
<li class='list-group-item-text x-fade x-item'>If trying to insert an #import at-rule after a style rule, then aborts with HierarchyRequestError.</li>
<li class='list-group-item-text x-fade x-item'>If rule is #namespace at-rule and list has more than just #import at-rules and/or #namespace at-rules, then aborts with InvalidStateError.</li>
</ul>
</blockquote>
<footer class='blockquote-footer'>
<!--===============================[[cite.x-cite]-->
<cite class='x-cite'><a href='https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule#Restrictions'>CSSStyleSheet.insertRule() - Wed APIs #Restrictions | MDN</a></cite> </footer>
</article>
</main>
<script>
var cnt = 0;
var form = document.forms[0];
var add = document.getElementById('add');
function modRule(ID) {
var e = window.event;
var i = ID.id.split('').pop();
console.log('ruleIndex: ' + i);
var sheets = document.styleSheets;
var sheet = document.getElementById('sht' + i);
var rulez = document.getElementById('rul' + i);
var index = document.getElementById('idx' + i);
var vSht = parseInt(sheet.value, 10);
var vIdx = parseInt(index.value, 10);
var vRul = rulez.value;
if (e.target.value === 'Delete Rule') {
switch (vSht) {
case 0:
sheets[0].deleteRule(vIdx);
break;
case 1:
sheets[1].deleteRule(vIdx);
break;
case 2:
sheets[2].deleteRule(vIdx);
break;
default:
sheets[0].deleteRule(vIdx);
break;
}
} else if (e.target.value === 'Insert Rule') {
switch (vSht) {
case 0:
sheets[0].insertRule(vRul, vIdx);
break;
case 1:
sheets[1].insertRule(vRul, vIdx);
break;
case 2:
sheets[2].insertRule(vRul, vIdx);
break;
default:
sheets[0].insertRule(vRul, vIdx);
break;
}
} else {
return;
}
}
add.addEventListener('click', addSet, false);
function addSet(e) {
cnt++;
var set = document.querySelector('.set0');
var opt = document.options
var dupe = set.cloneNode(true);
dupe.className = 'set' + cnt;
var fields = Array.from(dupe.querySelectorAll('[id]'));
var ids = fields.map(function(ID, idx) {
var zero = ID.id.lastIndexOf("0");
ID.id = ID.id.slice(0, zero);
ID.id = ID.id + cnt;
if (ID.id === 'rul' + cnt) {
ID.textContent = 'p {color:red}';
}
console.log('id: ' + ID.id + ' val: ' + ID.value);
return ID.value;
});
form.appendChild(dupe);
}
</script>
</body>
</html>
Update
If the stylesheet is big, wouldn't it be more efficient to dynamically create a new stylesheet for them?
Yes, but not an external <link> it's far more efficient and a ton more easier to dynamically manipulate a <style> block at the bottom of the </head>.
Not only is it simple, it's powerful since it's at the bottom of the cascade it'll override anything from an external <link>.
Also another thing to consider is that a HTTP request isn't needed unlike an external file which requires it and that' adds to your website's latency.
Demo 3 features 3 functions:
injectCSS() will be called mere microseconds before it's counterpart injectJS() at window.onload. It will create a <style> block within the </head> along with whatever styles we want initially.
injectJS() loads after injectCSS() because as a general rule style should always load before script. It will create a <script> tag and append it as the last child of the <body> tag specifically right before the closing </body> tag. Just like injectCSS() it may have anything within its tags that's script.
inject() calls both injectCSS() and injectJS() asynchronously to ensure that the former will always load before the latter.
As far as this demo relates to the OP, injectCSS() is the function that we should concern ourselves with as was already explained previously.
Details are commented in the demo
For faster loading time, please review the PLUNKER instead.
Demo 3
<!DOCTYPE html>
<html>
<head>
<style>
html {
font: 400 100%/1 Consolas;
}
html,
body {
height: 100%;
width: 100%;
}
main {
height: auto;
width: 100%;
padding: 10px;
}
section {
height: auto;
width: 100%;
padding: 10px
}
fieldset {
min-width: 70%;
margin: 20px 0;
padding: 10px;
}
var {
background: rgba(0, 0, 0, .7);
color: lime;
}
</style>
</head>
<body>
<h1></h1>
<main>
<p><var>injectCSS =</var> All paragraphs will be red</p>
<section>
<form id='test0'>
<fieldset>
<legend>Test Log</legend>
<label for='msg0'>injectCSS()...:
<output id='msg0'></output></label>
<br>
<label for='msg1'>injectJS()....:
<output id='msg1'></output></label>
</fieldset>
</form>
</section>
<section>
</section>
</main>
<footer>
<p>Review this page with Firebug/DevTools and we'll see an extra <style> tag in the <head> and we'll see an extra <script> tag right before the closing <\body> tag.</p>
</footer>
<script>
// HTMLFormControlsCollection★
var x0 = document.forms[0].elements;
var m0 = x0.msg0;
var m1 = x0.msg1;
// Input strings of styles and scripts that are to be injected
var css = "p {color:red}";
var js = "document.querySelector('h1').innerHTML = '<var>injectJS =</var> H1 HTML'";
/* This function manages injectCSS() and injectJS() functions by using
|| the async/await★ keywords. Times are provided by
|| performance.now()★ method.
*/ //* ✎ Delete/add the first * to disable/enable this version of inject().
// The proceeding edit ✎ must be done as well.
var inject = async function() {
var wait0 = injectCSS.call(this, css);
var wait1 = injectJS.call(this, js);
m0.value = performance.now();
var init1 = await wait1;
m1.value = performance.now()
return false;
};
/*/// ✎ Delete/add the first / to enable/disable this version of inject().
// The previous edit ✎ must be done as well.
var inject = function() {
injectCSS.call(this, css);
m0.value = performance.now();
injectJS.call(this, js);
m1.value = performance.now()
return false;
};
/* These 2 functions do the same thing but with different content.
|| They could be refactored into one function but I made them
|| separately to show injectCSS() sepatately for QA SO46985099.
|| Both creates a tag, then writes the code in it, and then appends
|| it to DOM.
*/
function injectCSS(style) {
var sty = document.createElement("style");
sty.innerHTML = style;
document.querySelector('head').appendChild(sty);
}
function injectJS(script) {
var scr = document.createElement("script");
scr.innerHTML = script;
document.body.appendChild(scr);
}
/* The main function inject() is called at window.load. This is the last
|| loading event possible in which we are able call our function. This
|| ensures that specific CSS is loaded before specific JS is called.
|| This is the last step in the loading process, therefore there should be
|| no more styles to render or script that blocks.
*/
window.onload = inject;
</script>
</body>
</html>
Demo Outline
Collects all <link> and <style> into a styleSheetList using document.stylesheets
Converts it into an array called sheetArray with Array.from()
The target is the 3rd <link> which is sheetArray[2]
Then there are 2 rules inserted at index 0 and index 1 successfully.
This is done through a for loop and arrays as the dynamic parameters and interpolation of Template Literals.
This demo does not function on SO, go to PLUNKER for a functioning demo.
Note: In the demo content is an excerpt from MDN that defines the restrictions of insertRule(). The highlighted items may apply to your specific errors.
Demo 1 - index.html [Review PLUNKER for a working demo]
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css' rel='stylesheet'>
<link href="style.css" rel="stylesheet">
<link href='cssom.css' rel="stylesheet">
</head>
<body>
<main class='container'>
<hgroup class='x-inline'>
<!--====================================[hgroup.x-inline]-->
<h1 class='h1'>CSSStyleSheet</h1>
<h2 class='h2'>.insertRule()</h2>
</hgroup>
<article class='text-primary'>
<blockquote class='blockquote'>
<h3 id="Restrictions" class='h3'>Restrictions</h3>
<p>CSS stylesheet rule-lists have a number of intuitive and not-so-intuitive <a class="external" href="https://drafts.csswg.org/cssom/#insert-a-css-rule">restrictions</a> affecting how and where rules can be inserted. Violating these will likely
cause an error raised as a <a title="The DOMException interface represents an abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API." href="https://developer.mozilla.org/en-US/docs/Web/API/DOMException"><code>DOMException</code></a> </p>
<!--==========================[ul.x-list | li.x-fade]-->
<ul class='list-group-flush x-list'>
<li class='list-group-item-text x-fade'>If index > number of rules in the stylesheet (the <a title="A CSSRuleList is an (indirect-modify only) array-like object containing an ordered collection of CSSRule objects." href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRuleList"><code>CSSRuleList</code></a>.length),
then aborts with IndexSizeError.</li>
<li class='list-group-item-warning'>If rule cannot be inserted at index 0 due to some CSS constraint, then aborts with HierarchyRequestError.</li>
<li class='list-group-item-danger'>If more than one rule is given in the rule parameter, then aborts with SyntaxError</li>
<li class='list-group-item-text x-fade'>If trying to insert an #import at-rule after a style rule, then aborts with HierarchyRequestError.</li>
<li class='list-group-item-text x-fade'>If rule is #namespace at-rule and list has more than just #import at-rules and/or #namespace at-rules, then aborts with InvalidStateError.</li>
</ul>
</blockquote>
<footer class='blockquote-footer'>
<!--===============================[[cite.x-cite]-->
<cite class='x-cite'><a href='https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule#Restrictions'>CSSStyleSheet.insertRule() - Wed APIs #Restrictions | MDN</a></cite> </footer>
</article>
</main>
<script>
var sheets = document.styleSheets;
var sheetArray = Array.from(sheets);
var sel = ['ul.x-list', 'li::before'];
var dec = [`margin-left: 0; padding-left: 1em; text-indent: -1em;`, `content: '🔹';`];
var idx = [0, 1];
var qty = idx.length;
for (let r = 0; r < qty; r++) {
sheetArray[2].insertRule(`${sel[r]} {${dec[r]}}`, idx[r]);
}
</script>
</body>
</html>
Deno 2 - cssom.css
/*0*/
hgroup.x-inline {display:flex; justify-content:center; align-items: center;}
/*1*/
ul.x-list.x-list {list-style: none;}
/*2*/
li.x-fade.x-fade {color:rgba(0,0,0,.3);}
/*3*/
cite.x-cite.x-cite {position:relative; left:60%}
/*4*/
cite.x-cite.x-cite::before {content:"\2014 \00A0"}
/*5*/
.blockquote-footer::before {content: '';}
/*6*/
li.list-group-item {line-height:1.5}
/*7*/
a {text-shadow: 2px 5px 3px rgba(192,192,192,.8)}

jQuery/Javascript : How to prepend elements without going back to the top of last prepended element?

Whenever I click prepend, after all elements are prepended, the view of the chat area switches to the top of the chat area or the last prepended element. This is different from append, whereby after all elements are appended, the view of the chat area does not switch to the end of the chat area or last appended element but still stays at its previous position.
How do I make the prepend function act in the same way as append in the sense that the view of the chat area does not change similar to FB's load previous message function?
Here is a sample code that illustrates what I mean.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
</head>
<style type="text/css">
.chatbox{
border:1px solid #2a6496;
height: 600px;
margin-top:50px;
}
.chatbox div{
height: 100%;
}
.rightP{
border-left: 1px solid #2a6496;
}
.rightP .contents{
border-bottom: 1px solid #2a6496;
height: 70%;
}
.rightP .send{
padding : 5% 5% 5% 5%;
height: 30%;
}
#response{
height: 200px;
overflow-y: scroll;
overflow-wrap: break-word;
}
</style>
<script>
function appendMessage()
{
var data = 'hello';
var message = document.createElement('p');
message.innerHTML = data;
console.log(message.innerHTML);
$('#response').append(message);
$('#response').append($('.load'));
}
function prependMessage()
{
for(var $i = 0;$i<10;$i++)
{
var data = 'hello'+$i;
var message = document.createElement('p');
message.innerHTML = data;
console.log(message.innerHTML);
$('#response').prepend(message);
$('#response').prepend($('.load2'));
}
}
</script>
<body>
<div class="container">
<div class="chatbox">
<div class="col-sm-8 rightP">
<div class="row contents">
<div class="row msg">
<div id="response" class="msg form-group">
<a onclick="return appendMessage()" class="load btn btn-default">Append</a>
<a onclick="return prependMessage()" class="load2 btn btn-default">Prepend</a>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
In HTML there should be return in your onlick:
<a onclick="return loadMessage();" class="load btn btn-default">Load More Msg</a>
In JS you need to add return false to your function loadMessage.
var loadMessage = function(){
var firstMessage = $messagesWrapper.find('> p:nth-child(2)');
$.ajax({
....
if(messages.length<10){
$('.load').hide();//hide the load button if remaining messages to load is <10
}
success: function(messages){
$.each(messages, function() {
prependMessage(this);
});
},
....
});
return false;
};
Try this:
<div id="response" class="msg form-group">
<a onclick="loadMessage(); return false;" class="load btn btn-default">Load More Msg</a>
</div>
If this doesn't work, try another way:
var loadMessage = function(){
e.preventDefault(); // preventing any scroll action
var firstMessage = $messagesWrapper.find('> p:nth-child(2)');
(...)
And
var prependMessage = function(data){
e.preventDefault(); // preventing any scroll action
var message = document.createElement('p');
(...)
If this doesn't work please provide the whole code so we can reproduce.

Change CSS class with Javascript to be able to change color

I am creating a BMI index calculator so far everything hass been good and I am lost when i think about how I should be able to change the background color of the div class to certain color according to their BMI result.
for example:
if the person is underweight it should be: grey
if the person is normal it should be: blue
if the person is overweight it should be: orange
if the person is obese it should be: red
How do i do this please help...
Here is the HTML CSS and Javascript
<html>
<head>
<title>BMI Calculator</title>
<script type="text/javascript">
function computeBMI() {
//Obtain user inputs
var height = Number(document.getElementById("height").value);
var heightunits = document.getElementById("heightunits").value;
var weight = Number(document.getElementById("weight").value);
var weightunits = document.getElementById("weightunits").value;
if (heightunits == "inches") height /= 39.3700787;
if (weightunits == "lb") weight /= 2.20462;
var BMI = weight / Math.pow(height, 2);
document.getElementById("output").innerText = Math.round(BMI * 100) / 100;
var result;
if (BMI <= 18.5) {
result = 'underweight';
} else if (BMI <= 24.9) {
result = 'Normal';
} else if (BMI <= 29.9) {
result = 'Overweight';
} else {
result='Obese';
}
}
</script>
<style type="text/css">
.resultclass{ background-color:yellow; width:500px; height:300px;}
.underweight{ background-color:grey; width:500px; height:300px;}
.normal{ background-color:blue; width:500px; height:300px;}
.overweight{ background-color:orange; width:500px; height:300px;}
.obese{ background-color:red; width:500px; height:300px;}
</style>
</head>
<body>
<h1>Body Mass Index Calculator</h1>
<p>Enter your height: <input type="text" id="height"/>
<select type="multiple" id="heightunits">
<option value="metres" selected="selected">metres</option>
<option value="inches">inches</option>
</select>
</p>
<p>Enter your weight: <input type="text" id="weight"/>
<select type="multiple" id="weightunits">
<option value="kg" selected="selected">kilograms</option>
<option value="lb">pounds</option>
</select>
</p>
<input type="submit" value="computeBMI" onclick="computeBMI();">
<div class="resultclass">
<h1>Your BMI is: <span id="output">?</span></h1>
<h1>This means you are: <span id="resultdiv">?</span></h1>
</div>
</body>
</html>
In your computeBMI() function you set the class to what you want like this:
document.getElementById("resultdiv").className = "obese";
You can have a dictionary like:
var bg_colors = {'underweight': 'gray', 'Normal': 'blue', 'Overweight': 'red', 'Obese': '#ABC'}
and add:
document.getElementById("resultDiv").style.backgroundColor=bg_colors[result];
after calculating your result.
Note that I gave and id "resultDiv" to the div element.
In CSS, you can have classes that are a certain color:
.underweight {
color: grey;
}
.overweight {
color: blue;
}
...
Then as Severian said, you can add the class to the div depending on the BMI value. To save any existing classes you should use the 'classList' attribute, which works in most browsers except IE 8:
document.getElementById("resultdiv").classList.add("underweight");
And remember to remove any previous BMI classes when the user enters new information.
You could use jQuery to do this with one line of code:
$("#resultdiv").addClass("obese");
http://api.jquery.com/addclass/
If you need to remove a class first it would be like this:
$("#resultdiv").removeClass("classname").addClass("obese");
https://api.jquery.com/removeClass/

Categories

Resources