HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URL's added here will be added as <link>
s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
If the stylesheet you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<!-- NAV BAR SECTION -->
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Email Templates</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li>
<select class="form-control" name="" id="templateSelect">
<option value="totalLoss">Total Loss Offer</option>
</select>
</li>
</ul>
</div><!-- /.container -->
</nav>
<div class='container'>
<div class='row'>
<div id="errDiv" class="alert alert-danger .alert-dismissible" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
</div>
<!-- EMAIL INPUTS SECTION -->
<div class='col-sm-5' id='userInput'>
<div class='thumbnail'>
<div class='caption'>
<form id='emailForm'>
<!-- To email -->
<div class="form-group row">
<label for='toEmail' class="col-sm-3 col-form-label">To Email:</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="toEmail" id="toEmail" placeholder="SendTo@example.com" autofocus required>
<span class="tooltip-text">Insert the recipient's email address here</span>
</div>
</div>
<!-- To name -->
<div class="form-group row">
<label for='toName' class="col-sm-3 col-form-label">To Name:</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="toName" id="toName" placeholder="Optional Recipient Name">
<span class="tooltip-text">Optionally Insert the recipient's name here</span>
</div>
</div>
<!-- CC email -->
<div class="form-group row">
<label for="ccEmail" class="col-sm-3 col-form-label">CC Email:</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="ccEmail" id="ccEmail" placeholder="Optional CC Email">
<span class="tooltip-text">Optionally add an email address to CC here</span>
</div>
</div>
<!-- Main ref -->
<div class="form-group row">
<label for="aRef" class="col-sm-3 col-form-label">Main ref:</label>
<div class="col-sm-9">
<input type="text" class="form-control DPA" name="aRef" id="aRef" placeholder="Insert Our Reference" required>
<span class="tooltip-text">Insert the reference for this claim here</span>
</div>
</div>
<!-- other ref -->
<div class="form-group row">
<label for="oRef" class="col-sm-3 col-form-label">Your ref:</label>
<div class="col-sm-9">
<input type="text" class="form-control DPA" name="oRef" id="oRef" placeholder="Insert Other Reference">
<span class="tooltip-text">Insert any broker or third party references here</span>
</div>
</div>
<!-- DOA -->
<div class="form-group row">
<label for="doa" class="col-sm-3 col-form-label">DOA:</label>
<div class="col-sm-9">
<input type="text" class="form-control DPA" name="doa" id="doa" placeholder='DD/MM/YYYY'>
<span class="tooltip-text">Insert the date of accident</span>
</div>
</div>
<!-- Our INSD Clinet -->
<div class="form-group row">
<label for="insd" class="col-sm-3 col-form-label">INSD:</label>
<div class="col-sm-9">
<input type="text" class="form-control DPA" name="insd" id="insd" placeholder="Optional INSD Name">
<span class="tooltip-text">Optionally insert the insured client's name here</span>
</div>
</div>
<!-- VAT status -->
<div class="form-group row">
<label for="vat" class="col-sm-3 col-form-label">VAT Status:</label>
<div class="col-sm-9">
<select class="form-control" name="vat" id="vat">
<option value="">VAT status unknown</option>
<option value="yes">Yes - Taxable</option>
<option value="no">No - Non Taxable</option>
</select>
<span class="tooltip-text">Select the INSD VAT status if known</span>
</div>
</div>
<!-- VRN -->
<div class="form-group row">
<label for="phVrn" class="col-sm-3 col-form-label">INSD's VRN:</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="phVrn" id="phVrn" placeholder="INSD's VRN" required>
<span class="tooltip-text">Insert the registration of the vehicle being total lossed</span>
</div>
</div>
<!-- Excess -->
<div class="form-group row">
<label for="excess" class="col-sm-3 col-form-label">Excess:</label>
<div class="col-sm-9">
<input type="number" class="form-control totalLoss" name="excess" id="excess" placeholder='Client Excess' min="0" step="1" required>
<span class="tooltip-text">Insert the client's excess</span>
</div>
</div>
<!-- PAV -->
<div class="form-group row">
<label for="pav" class="col-sm-3 col-form-label">PAV:</label>
<div class="col-sm-9">
<input type="number" class="form-control totalLoss" name="pav" id="pav" placeholder='Pre-accident Value' min="0" step="1" required>
<span class="tooltip-text">Insert the pre-accident value of the vehicle</span>
</div>
</div>
<!-- Additional Costs section -->
<div id="addCostBtnDiv" class="form-group row">
<label class="col-sm-3 col-form-label">Other Costs:</label>
<button id="addCostBtn" class="btn btn-success">Add Cost</button>
</div>
<!-- Salvage CAT -->
<div class="form-group row">
<label for="salCat" class="col-sm-3 col-form-label">Salvage CAT:</label>
<div class="col-sm-9">
<select class="form-control totalLoss" name="salCat" id="salCat">
<option value="">Vehicle CAT unavailable</option>
<option value="A">A - Scrap</option>
<option value="B">B - Breaker</option>
<option value="C">C - repairable TL</option>
<option value="D">D - contsructive TL</option>
<option value="T">Stolen Vehicle</option>
</select>
<span class="tooltip-text">Select the vehicle's salvage category if known</span>
</div>
</div>
<!-- Customer Retention? -->
<div class="form-group row">
<label for="custRetain" class="col-sm-3 col-form-label">Retain?</label>
<div class="col-sm-9">
<select class="form-control totalLoss" name="custRetain" id="custRetain">
<option value="">No - Customer didn't request</option>
<option value="retain">Yes - Customer to retain</option>
</select>
<span class="tooltip-text">If the customer has explicitly asked to retain the salvage, select here to add salvage costs to email body</span>
</div>
</div>
<!-- Salvage cost -->
<div class="form-group row" id="salValDiv">
<label for="salCostType salCostInput" class="col-sm-3 col-xs-12 col-form-label">Salvage Cost:</label>
<div class="col-md-3 col-sm-4 col-xs-5">
<select class="form-control totalLoss" name="salCostType" id="salCostType">
<option value="cost">£</option>
<option value="percent">%</option>
</select>
<span class="tooltip-text">Select whether salvage given as cost or percent</span>
</div>
<div class="col-md-6 col-sm-5 col-xs-7">
<input type="number" class="form-control totalLoss" name="salCostInput" id="salCostInput">
<span class="tooltip-text">Insert salvage cost here</span>
</div>
</div>
<!-- XXX -->
<!-- Template for new inputs
<div class="form-group row">
<label for="XXX" class="col-sm-3 col-form-label">XXX: </label>
<div class="col-sm-9">
<input type="text" class="form-control" name="XXX" id="XXX" placeholder='XXX'>
</div>
</div>
-->
<!-- Extra text -->
<div class="form-group row">
<label for="extraText" class="col-sm-3 col-form-label">Extra Text:</label>
<div class="col-sm-9">
<textarea class="form-control" name="extraText" id="extraText"></textarea>
<span class="tooltip-text">You can add any additional information to the email using this input</span>
</div>
</div>
<!-- confirm okay to copy to clipboard -->
<div class="row">
<div class="col-xs-12" id="confText">
<hr>
<p>
<strong>***PLEASE READ***</strong>
<br>
This app will copy the body of the generated email to clipboard and open a new message in your email client containing the recipient's email addess and the subject line.<br/>You can then use <strong>CTRL</strong> + <strong>V</strong> to paste in the email body.
</p>
<p>
<input type="checkbox" id="userConfCheck">
Tick this box to proceed - <em>your choice will be saved.</em>
</p>
</div>
</div>
</form>
</div> <!-- /caption -->
</div> <!-- /thumbnail -->
</div> <!-- /userInput -->
<!-- EMAIL EXAMPLE SECTION -->
<div class='col-sm-7' id='exampleEmail'>
<div class='thumbnail'>
<div class='caption'>
<div class='col-xs-2'>
<div class="form-group row">
<div>
<button class='btn btn-default' id='sendBtn'>
Create<br>
Email<br>
<span class="glyphicon glyphicon-send" aria-hidden="true"></span>
</button>
</div>
</div>
</div>
<!-- group to & cc examples -->
<div class='col-xs-10 '>
<!-- to example -->
<div class="input-group form-group">
<span class="input-group-addon">To:</span>
<div class="form-control" id="toEmailExamp" aria-describedby="basic-addon1" readonly> XXX </div>
</div>
<!-- CC example -->
<div class="input-group form-group">
<span class='input-group-addon'>CC:</span>
<div class="form-control" id="ccEmailExamp" readonly> XXX </div>
</div>
</div> <!-- end group to & cc examples -->
<!-- Subject example -->
<div class="form-group row">
<label for="subExamp" class="col-sm-2 col-form-label">Subject:</label>
<div class="col-sm-10">
<div class="form-control" id="subExamp" readonly>
XXX
</div>
</div>
</div>
<!-- Body example -->
<div class="form-group">
<div id='bodyExamp' class='form-control' readonly>
*** Please enable javascript ***
</div>
</div>
</div><!-- /caption -->
</div><!-- end thumbnail -->
</div> <!-- /exampleEmail-->
</div> <!-- /row (both columms) -->
</div> <!-- /container all -->
<textarea id="copyPlaceholder"></textarea>
/* ============== */
/* VARIABLES */
/* ============== */
$tooltip-bg: rgba( 0, 0, 0, 0.7 );
/* ============== */
/* CODE */
/* ============== */
body{
background: #649173; /* fallback for old browsers */
background: -webkit-linear-gradient(to right, #DBD5A4, #649173); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #DBD5A4, #649173); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
#addCostBtn{
margin: 5px 15px;
}
div{
min-height:35px;
}
textarea{
resize: none;
overflow: scrollbar;
}
h4 {
font-weight: bold;
}
.navbar-default{
border: none;
/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#ffffff+0,f3f3f3+50,ededed+51,ffffff+100;White+Gloss+%232 */
background: rgb(255,255,255); /* Old browsers */
background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(243,243,243,1) 50%, rgba(237,237,237,1) 51%, rgba(255,255,255,1) 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(243,243,243,1) 50%,rgba(237,237,237,1) 51%,rgba(255,255,255,1) 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,rgba(243,243,243,1) 50%,rgba(237,237,237,1) 51%,rgba(255,255,255,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */
}
.form-control{
height: auto;
overflow-wrap: break-word;
}
.input-group-addon{
min-width: 50px;
}
.navbar-brand{
font-size: 200%;
margin: 0px;
margin-top: 8px;
}
.error{
background-color: rgb(235, 204, 209);
border-color: rgb(235, 204, 209);
}
.thumbnail{
box-shadow: 3px 3px 10px rgba( 0, 0, 0, 0.5 );
box-shadow: 6px 6px 10px rgba( 0, 0, 0, 0.2 );
}
#errDiv{
display: none;
}
#send{
padding: 0;
height:85px;
width:90%;
}
#templateSelect{
margin: 15px;
width: 200px
}
#salValDiv{
display: none;
}
#confText{
text-align: center
}
#userConfCheck{
position: relative;
top: 2px;
margin-right: 3px;
}
#copyPlaceholder{
position: relative;
left: -9999px;
}
/* Tool tip styles */
.form-control{
& + .tooltip-text{
visibility: hidden;
opacity: 0;
width: 90%; // rough fall back for calc
width: calc(100% - 30px);
background-color: $tooltip-bg;
color: #fff;
text-align: center;
padding: 5px;
margin-right: 20px;
border-radius: 6px;
// Position the tooltip text
position: absolute;
bottom: 100%;
margin-bottom: 5px;
z-index: 2;
transition: opacity 1s;
// add arrow after tooltip
&::after {
content: " ";
position: absolute;
top: 100%;
left: 50%;
border-width: 5px;
border-style: solid;
border-color: $tooltip-bg transparent transparent transparent ;
}
}
// on focus show tip
&:focus + .tooltip-text {
animation: fadeTip 10s ease;
}
}
@keyframes fadeTip{
0% {
visibility: hidden;
opacity: 0;
}
10%{
visibility: visible;
opacity: 1;
}
90%{
visibility: visible;
opacity: 1;
}
100%{
visibility: hidden;
opacity: 0;
}
}
// Run JS in IIFE to prevent var clash
(function(){
/*==================*/
/* Variables */
/*==================*/
var template = "totalLoss",
// subject
DPA = document.querySelectorAll(".DPA"),
// TL inputs
allTL = document.querySelectorAll(".totalLoss"),
// text vars
taxable = "This value does not include VAT which we would not pay due to your VAT registered status.",
salvageText = {
// salvage cat descriptions
A : "Please note that as a CAT A Total loss, your vehicle has no economically salvageable parts and has value only for scrap metal.",
B : "Please note that as a CAT B Total loss, your vehicle should not be repaired. The vehicle should be broken down for spares and the main structure of the vehicle will be destroyed.",
C : "Please note that as a CAT C Total loss, The cost of repairs exceeded the pre-accident value of the vehicle.",
D : "Please note that as a CAT D Total loss, The repair costs are less than the pre-accident value of the vehicle and for economic reasons it has been decided to deal with the vehicle as a Constructive Total Loss.",
T : "Please note that as a stolen vehicle, we will be transferred ownership of the vehicle after settlement is complete. In the event of the vehicle ever being recovered after settlement, you will no longer be the legal owner of the vehicle.",
// text if PH wants to retain
retainStd : '<p>Since you have decided to retain ownership of your vehicle, we will need to deduct the salvage value of the vehicle. This is the value of the vehicle if it was sold in its current condition which we have valued at £<span id="salCostExamp">0</span>. <br/> Therefore if your decide to keep the vehicle, after salvage and excess deductions we will pay you £<span id="salPayoutExamp">0</span>.</p>',
retainDestroy : '<p>We must inform customers that the salvage category placed on the vehicle describes the vehicle as scrap and can result in the vehicle remains being classed as hazardous waste - the remains should be disposed of in line with legislative requirements. DVLA will not reissue a V5 for your vehicle and it is the customers responsibility to ensure that they comply with all the necessary legislation and documentation which can include removing allowable salvageable parts and ensuring that the Bodyshell is crushed and a Certificate of Destruction V860 is produced. All costs associated with the above procedures will be borne by the customer and will be their personal responsibility.</p>',
retainRepair : '<p>Please be aware that you will be responsible for any repair work necessary to make the vehicle roadworthy again.</p>',
collect: ' ensuring we are aware of the vehicle\'s location for collection by our salvage agent Copart',
};
/*==================*/
/** FUNCTIONS */
/*==================*/
function addEvent( id, event, func ){
// get element by Id or element
var element = document.getElementById(id) || id;
// check and anssign appropriate event handler
if( element.attachEvent ){
return element.attachEvent( 'on' + event, func );
} else {
return element.addEventListener( event, func, false );
}
}
function removeEvent( id, event, func ){
// get element by Id or element
var element = document.getElementById(id) || id;
// check and anssign appropriate event handler
if( element.attachEvent ){
return element.detachEvent( 'on' + event, func );
} else {
return element.removeEventListener( event, func, false );
}
}
String.prototype.roundInput = function(){
// set to zero if negative
if( this < 0 ){
return 0;
} else {
// otherwise force 2 nums after decimal points if needed
return this > ~~this ? parseFloat(this).toFixed(2): ~~this;
}
}
String.prototype.capName = function(){
// seperate name words into an array
var nameArr = this.split(" "),
capStr = "";
// iterate through array
for(var i = 0; i < nameArr.length; i++){
var str = nameArr[i];
capStr += " " + str.charAt(0).toUpperCase() + str.slice(1);
}
return capStr;
}
function checkId( source ){
// round number input
source.value = source.type === "number" ? source.value.roundInput() : source.value ;
// identify special cases by ID
switch ( source.id ){
case "vat":
return source.value !== "no" ? taxable : "";
case "phVrn":
source.value = source.value.toUpperCase();
return source.value || "XXX";
case "toName":
source.value = source.value.capName();
return source.value ? source.value : "";
default:
return source.value;
}
}
function assignValue( target, source ){
// uppercase for VRN
var sourceVal = checkId( source );
// check if input
if( target.value ){
target.value = sourceVal;
} else {
target.textContent = sourceVal;
}
}
function updateSelf(){
var target = document.getElementById( this.id + "Examp" ),
targetClass = document.getElementsByClassName( this.id + "Examp" ),
targetName = document.getElementsByClassName( this.name + "Examp" ) ;
// check that getElementById returns an item
if ( target ){
// assign value to one field
assignValue( target , this );
// otherwise search by class instead using id or name
} else if ( targetClass.length || targetName.length ) {
target = targetClass.length ? targetClass : targetName;
// assign values via loop instead
for( var i = 0; i < target.length; i++ ){
assignValue( target[i] , this );
}
}
}
function newElement(type, bootstrapClass, id){
var newContain = document.createElement(type);
// add class to div and return
newContain.className = bootstrapClass;
newContain.id = id;
return newContain;
}
function createInput(type, placeholder, classes){
var newInput = document.createElement("input");
// set default values for arguments
type = type || "text",
placeholder = placeholder || "insert " + type,
// set attributes
newInput.type = type;
newInput.placeholder = placeholder;
newInput.className = classes;
return newInput;
}
// ADD COST FUNCTION
function addCost(evt){
var rowDiv = newElement("div", "form-group row"),
targetDiv = document.getElementById("otherCosts"),
nameInputContain = newElement("div", "col-xs-6"),
amountInputContain = newElement("div", "col-xs-6"),
amountInputGrp = newElement("div", "input-group"),
nameInput = createInput("text",
"Name - Additional Cost",
"form-control otherCostsName"),
amountInput = createInput("number",
"Amount - Additional Cost",
"form-control otherCostsAmount"),
deleteBtnSpan = newElement("span", "input-group-btn"),
deleteBtn = newElement("button", "btn btn-danger");
// prevent form submit
evt.preventDefault();
// create targetDiv if not yet present
if(!targetDiv){
var addCostBtnDiv = document.getElementById("addCostBtnDiv");
// create element for div
targetDiv = newElement("div", null, "otherCosts");
addCostBtnDiv.insertAdjacentElement("afterend", targetDiv);
}
// add number attr to input
amountInput.min = 0;
amountInput.step = 1;
// add event listeners to inputs
addEvent( nameInput, "change", updateOtherCosts );
addEvent( amountInput, "change", updateOtherCosts );
addEvent( deleteBtn, "click", deleteCost );
// Assemble button
deleteBtn.textContent = "X";
deleteBtnSpan.appendChild(deleteBtn);
// assemble amount input group
amountInputGrp.appendChild(amountInput);
amountInputGrp.appendChild(deleteBtnSpan);
// add inputs to containers
nameInputContain.appendChild(nameInput);
amountInputContain.appendChild(amountInputGrp);
// add containers to NewDiv
rowDiv.appendChild(nameInputContain);
rowDiv.appendChild(amountInputContain);
// append to additional costs section
targetDiv.appendChild(rowDiv);
}
function deleteCost(evt){
var deleteBtn = this,
// target container for both inputs 4 lvls up
targetDiv = deleteBtn.parentNode.parentNode.parentNode.parentNode,
otherCostsContainer = document.getElementById("otherCosts"),
otherCostsArr = document.getElementsByClassName("otherCostsName");
// prevent submit
evt.preventDefault();
// disconnect event listener
removeEvent( deleteBtn, "click", deleteCost );
// check if last cost element
if( otherCostsArr.length <= 1 ){
// remove entire container
otherCostsContainer.remove();
} else {
// remove cost element
targetDiv.remove();
}
updateOtherCosts();
updateTlSect();
}
// CREATE GREETING FUNTION
function greet() {
var t = new Date(),
h = t.getHours(),
msg = "";
//Decide whether Morning or afternoon and assign to var
if (h < 12) {
msg = "Good morning";
} else {
msg = "Good afternoon";
}
return msg += '<span id="toNameExamp"></span>,';
}
// UPDATE SUBJECT FUNCTION
function createSubject() {
// create array for subject - text container and counter
var subjectArr = document.getElementsByClassName('DPA'),
subjectText = "Offer our services",
limit = 3;
// loop through subjectArr
for(var i = 0; i < subjectArr.length; i++){
// create var for current loop item
var itemVal = subjectArr[i].value;
// check that current element does not push past limit
if( itemVal && limit > 0){
var containingDiv = subjectArr[i].parentElement,
labelText = containingDiv.previousElementSibling.innerText;
// add label & value to subjectText
subjectText += " - ";
subjectText += labelText;
subjectText += " " + itemVal;
limit--;
}
}
return subjectText;
} // end createSubject func
function updateSubject(){
var subjectText = createSubject();
document.getElementById("subExamp").textContent = subjectText;
}
// UPDATE BODY FUNCTION
function selectTemplate() {
// Create text holder var
var bodyText = "<p>" + greet() + "</p>";
bodyText += '<p>After conducting my own research and conferring with our engineer, we have decided that a pre-accident value of £<span id="pavExamp">0</span> would be an acceptable valuation for your vehicle <span id="phVrnExamp">ABC123</span>. <span id="otherCostsExamp"></span> <span id="vatExamp">' + taxable + '</span> <br/>After the deduction of your £<span id="excessExamp">0</span> excess, we would pay you a total of £<span id="payoutExamp">0</span> for your vehicle, after which ownership of the vehicle will be transferred to ourselves.</p>' +
'<span id="catExamp"></span>' +
'<span id="retainExamp"></span>' +
'<p>If you accept our offer, please confirm your payment details for settlement<span id="collectExamp">' + salvageText.collect + '</span>.</p>' +
'<p>We will be able to make swifter payment upon acceptance of any offer if you can provide your bank details comprising of sort-code, account number & account name.</p>' +
'<p id="extraTextExamp"><p>';
return bodyText;
} // end selectTemplate()
function matchOtherCosts(){
var matches = [],
otherCostsName = document.getElementsByClassName("otherCostsName"),
otherCostsAmount = document.getElementsByClassName("otherCostsAmount");
for( var i = 0; i < otherCostsName.length; i++ ){
// round number input and update
otherCostsAmount[i].value = otherCostsAmount[i].value.roundInput() ;
// check that both matching inputs have values
if( otherCostsName[i].value &&
//convert to number to prevent "0" as string reading as true
parseFloat( otherCostsAmount[i].value )
){
// add values to assoc array
matches.push({
name: otherCostsName[i].value,
/* convert amount value to a Number ensures they
can be added together without coercion to String */
cost: otherCostsAmount[i].value,
});
}
}
return matches;
}
// UPDATE OTHER COSTS FUNCTION
function updateOtherCosts(){
var otherCostsExamp = document.getElementById("otherCostsExamp"),
matches = matchOtherCosts(),
payout = calcPayout(),
msg = "We will also cover the cost of ";
// add values to string for display
for( var i = 0; i < matches.length ; i++ ){
msg += matches[i].name + " at £" + matches[i].cost;
// add approbriate connector
switch ( matches.length - i ){
case 1:
msg += "."; break;
case 2:
msg += " and "; break;
default:
msg += ", "; break;
}
}
// display message in placeholder
otherCostsExamp.textContent = matches.length > 0 ? msg : null;
updateTlSect();
}
function updateTlSect(){
// Needed inputs
var salCat = document.getElementById("salCat"),
custRetain = document.getElementById("custRetain"),
// retaining if customer requests and salvage cat has appropriate value
retaining = custRetain.value && ( salCat.value && salCat.value !== "T" ),
// set up cost vars
salDesc = salCat.value ? "<p>" + salvageText[salCat.value] + "</p>" : "",
salCost = 0,
payout = 0,
salPayout = 0;
// calculate costs
payout = calcPayout();
salCost = calcSalCost();
salPayout = payout - salCost;
// round costs to 2 decimal places
payout = payout > Math.floor(payout) ? payout.toFixed(2): payout;
salCost = salCost > Math.floor(salCost) ? salCost.toFixed(2): salCost;
salPayout = salPayout > Math.floor(salPayout) ? salPayout.toFixed(2): salPayout;
// check if retain - adjust accordingly
salDisplay( salCat, salCost, salPayout, retaining );
// set example fileds to new value
document.getElementById("payoutExamp").innerText = payout || "0";
document.getElementById("catExamp").innerHTML = salDesc || "";
}
function calcPayout(){
var pavVal = document.getElementById("pav").value,
xsVal = document.getElementById("excess").value,
matches = matchOtherCosts(),
otherCostsTotal = 0;
// calc other costs total
for( var i = 0; i < matches.length; i++){
otherCostsTotal += parseFloat(matches[i].cost);
}
// return sum
return (pavVal - xsVal + otherCostsTotal);
}
function calcSalCost(){
// set variables
var pavVal = document.getElementById("pav").value,
salCostType = document.getElementById("salCostType").value,
salCostVal = document.getElementById("salCostInput").value;
// calculate sal cost based on input
switch (salCostType){
case "percent":
return (salCostVal / 100) * pavVal;
case "cost":
// retun as a number
return parseFloat(salCostVal);
default:
return 0;
}
}
function salDisplay( salCat, salCost, salPayout, retaining ){
var salValDiv = document.getElementById("salValDiv"),
retainExamp = document.getElementById("retainExamp"),
colEx = document.getElementById("collectExamp"),
retainState = "retain" + ( salCat.value === "C" || salCat.value === "D" ? "Repair" : "Destroy" );
// if retaining set display to block
displayProp = retaining ? "block" : "none" ;
// hide/show salvage percentage input if necessary
salValDiv.style.display = displayProp;
// adjust example text as needed
if( retaining ){
// adjust text for retaining
retainExamp.innerHTML = salvageText.retainStd + salvageText[retainState];
colEx.innerText = "";
// set example values
document.getElementById("salCostExamp").innerText = salCost || "0";
document.getElementById("salPayoutExamp").innerText = salPayout || "0";
} else {
// adjust costs for not retaining
retainExamp.innerHTML = "";
colEx.innerText = salCat !== "T" ? salvageText.collect : "";
}
}
// CREATE EMAIL FUNCTION
function createEmail(){
if( !validateInputs() || !userConfirm() ){
return;
}
var checkbox = document.getElementById("userConfCheck");
localStorage.userConfirm = checkbox.checked = true;
// gather inputs for sending mail
var toEmail = document.getElementById('toEmail').value,
ccEmail = document.getElementById('ccEmail').value,
subject = document.getElementById('subExamp').innerText;
// copy email body to clipboard using one of two methods
copyBody();
// copyToClipboard("bodyExamp");
//construct mailto link
var message = "mailto: " + toEmail +
"?cc= " + ccEmail +
"&subject=" + subject ;
// execute mailto link
window.location.href = message;
}
function copyBody(){
var placeholder = document.getElementById("copyPlaceholder"),
body = document.getElementById("bodyExamp");
// set placeholder value to body and select contents
placeholder.value = body.innerText;
placeholder.select();
// copy and delete contents of placeholder
document.execCommand("cut");
}
function userConfirm(){
// create text var for confirm message
var confText = "***PLEASE READ*** \nThis will copy the body of the generated email to clipboard and open a new message in your email client containing the recipient's email address and the subject line.\nYou can then use CTRL + V to paste in the email body.\nDo you wish to proceed?",
checkbox = document.getElementById("userConfCheck");
// check whether checkbox is ticked
if(checkbox.checked){
return true;
}
//check user wants to copy to clipboard
return confirm(confText);
}
function validateInputs(){
try{
//* ***IN PROGRESS ERROR CHECKING***
// create err container array
var err = [],
//inputs = document.querySelectorAll("input:not(#userConfCheck):not(.otherCostsName):not(.otherCostsAmount), select:not(#templateSelect)"),
inputs = document.querySelectorAll("input, select"),
excess = document.getElementById("excess"),
pav = document.getElementById("pav"),
payoutExamp = document.getElementById("payoutExamp"),
custRetain = document.getElementById("custRetain"),
salCat = document.getElementById("salCat"),
salCostType = document.getElementById("salCostType"),
salCostInput = document.getElementById("salCostInput"),
// if salPayout is undefined set to payout Examp for err checking purposes
salPayoutExamp = document.getElementById("salPayoutExamp") || payoutExamp;
// iterate through inputs
for(var i = 0; i < inputs.length; i++){
// create label var for current input
var containingDiv = inputs[i].parentElement,
//labelText = containingDiv.previousElementSibling.innerText.slice(0, -1) ,
prevDiv = containingDiv.previousElementSibling,
labelText = prevDiv ? prevDiv.textContent.slice(0, -1) : "",
isEmail = inputs[i].type === "email";
// check if required & blank
if( !inputs[i].value && inputs[i].required ){
errorColor( inputs[i], true );
err.push("<strong>" + labelText + "</strong> field cannot be empty");
// check if type is email
} else if ( inputs[i].value && isEmail) {
// check if there is err with email & set color based o result
var emailError = !isEmailValid( inputs[i].value );
errorColor( inputs[i], emailError );
// push err message if necessary
if(emailError){
err.push("Value of <strong>" + labelText + "</strong> is not a valid email");
}
// check for valid percentage if vehicle type set to custom
} else {
// if not captured by other statements set to standard color
errorColor( inputs[i], false );
}
}
// check for retain w/ no CAT
if( custRetain.value && !salCat.value ){
errorColor( salCat, true );
err.push("Customer cannot retain the vehicle without a <strong>salvage CAT</strong>");
}
// check for valid percentage if vehicle type set to custom
if( salCostType.value === "percent" && (salCostInput.value < 0 || salCostInput.value > 100) ){
errorColor( salCostInput, true );
err.push("<strong>Salvage percentage</strong> should be between 0 and 100");
}
// check for negative offers
if ( payoutExamp.innerText <= 0 || salPayoutExamp.innerText < 0 ) {
errorColor( excess, true );
errorColor( pav, true );
errorColor( salCostType, true );
errorColor( salCostInput, true );
err.push("we cannot offer a <strong>negative value!</strong>");
}
// throw err array
throw err;
} catch(err){
// find errDiv on page
var errDiv = document.getElementById("errDiv");
// if there are items in err array
if(err.length){
var ul = document.createElement("ul"),
h3 = document.createElement("h4");
h3.innerHTML = '<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>' +
'<span class="sr-only">Error:</span> ' +
'Please correct the following errors';
// reset errDiv and create ul
errDiv.innerHTML = "";
errDiv.style.display = "block";
errDiv.appendChild(h3);
errDiv.appendChild(ul);
// loop through err items and list them
for(var x = 0; x< err.length; x++){
var li = document.createElement("li");
ul.appendChild(li);
li.innerHTML = err[x];
}
//redirect to show errors
window.location.href = "#errDiv";
return false;
} else {
// if no items in err array
// remove errDiv from page
errDiv.style.display = "none";
return true;
}
}
}
function errorColor( target, error ){
error ? target.classList.add("error") : target.classList.remove("error");
}
function isEmailValid( email ){
var regEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regEx.test(email);
}
/*==================*/
/* ACTUAL CODE */
/*==================*/
// update body text
document.getElementById("bodyExamp").innerHTML = selectTemplate();
/* EVENT LISTENERS */
// add cost function
addEvent( "addCostBtn", "click", addCost );
// update to email preview on type
addEvent( "toEmail", "change", updateSelf );
// update toName
addEvent( "toName", "change", updateSelf );
// update cc email preview on type
addEvent( "ccEmail", "change", updateSelf );
//update vat
addEvent( "vat", "change", updateSelf );
// update ph Vrn
addEvent( "phVrn", "change", updateSelf );
// update Excess
addEvent( "excess", "change", updateSelf );
// update PAV
addEvent( "pav", "change", updateSelf );
// update extra text
addEvent( "extraText", "input", updateSelf );
// Create template on click
addEvent( "sendBtn", "click", createEmail );
// update subject when a subject field is altered
[].forEach.call(DPA, function(input){
debugger
addEvent(input, "change", updateSubject)
});
// update TL section on update
for(var x = 0; x < allTL.length; x++){
allTL[x].onchange = updateTlSect;
};
// remember state of checkbox locally
if(window.localStorage){
var checkbox = document.getElementById("userConfCheck");
checkbox.checked = localStorage.userConfirm;
// change storage on click
checkbox.onchange = function(){
if (checkbox.checked){
localStorage.userConfirm = checkbox.checked;
} else {
localStorage.removeItem("userConfirm");
}
};
};
// end IIFE
})()
Also see: Tab Triggers