I have JS code on a webpage that loads questions in from mysql db and displays the text . What happens is that it cuts off words at the end of the line and continues the word on the next line at the start. So all text across the screen starts/ends at the same point.
This seems to be the code where it displays the text.
For example the text will look like at the end of a line 'cont' and then on next line at the start 'inue'.
How do i fix this?
var questions = <?=$questions;?>;
// Initialize variables
//------------------------------------------------------------------
var tags;
var tagsClass = '';
var liTagsid = [];
var correctAns = 0;
var isscorrect = 0;
var quizPage = 1;
var currentIndex = 0;
var currentQuestion = questions[currentIndex];
var prevousQuestion;
var previousIndex = 0;
var ulTag = document.getElementsByClassName('ulclass')[0];
var button = document.getElementById('submit');
var questionTitle = document.getElementById('question');
//save class name so it can be reused easily
//if I want to change it, I have to change it one place
var classHighlight = 'selected';
// Display Answers and hightlight selected item
//------------------------------------------------------------------
function showQuestions (){
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
if (currentIndex != 0) {
// create again submit button only for next pages
ulTag.innerHTML ='';
button.innerHTML = 'Submit';
button.className = 'submit';
button.id = 'submit';
if(quizPage<=questions.length){
//update the number of questions displayed
document.getElementById('quizNumber').innerHTML = quizPage;
}
}
//Display Results in the final page
if (currentIndex == (questions.length)) {
ulTag.innerHTML = '';
document.getElementById('question').innerHTML = '';
if(button.id == 'submit'){
button.className = 'buttonload';
button.innerHTML = '<i class="fa fa-spinner fa-spin"></i>Loading';
}
showResults();
return
}
questionTitle.innerHTML = "Question No:" + quizPage + " "+currentQuestion.question.category_name +"<br/>"+ currentQuestion.question.text;
if(currentQuestion.question.filename !== ''){
var br = document.createElement('br');
questionTitle .appendChild(br);
var img = document.createElement('img');
img.src = currentQuestion.question.filename;
img.className = 'imagecenter';
img.width = 750;
img.height = 350;
questionTitle .appendChild(img);
}
// create a for loop to generate the options and display them in the page
for (var i = 0; i < currentQuestion.options.length; i++) {
// creating options
var newAns = document.createElement('li');
newAns.id = 'ans'+ (i+1);
newAns.className = "notSelected listyle";
var textAns = document.createTextNode(currentQuestion.options[i].optiontext);
newAns.appendChild(textAns);
if(currentQuestion.options[i].file !== ''){
var br = document.createElement('br');
newAns .appendChild(br);
var img1 = document.createElement('img');
img1.src = currentQuestion.options[i].file;
img1.className = 'optionimg';
img1.width = 250;
img1.height = 250;
newAns .appendChild(img1);
newAns .appendChild(br);
}
var addNewAnsHere = document.getElementById('options');
addNewAnsHere.appendChild(newAns);
}
//.click() will return the result of $('.notSelected')
var $liTags = $('.notSelected').click(function(list) {
list.preventDefault();
//run removeClass on every element
//if the elements are not static, you might want to rerun $('.notSelected')
//instead of the saved $litTags
$liTags.removeClass(classHighlight);
//add the class to the currently clicked element (this)
$(this).addClass(classHighlight);
//get id name of clicked answer
for (var i = 0; i < currentQuestion.options.length ; i++) {
// console.log(liTagsid[i]);
if($liTags[i].className == "notSelected listyle selected"){
//store information to check answer
tags = $liTags[i].id;
// tagsClass = $LiTags.className;
tagsClassName = $liTags[i];
}
}
});
//check answer once it has been submitted
button.onclick = function (){
if(button.id == 'submit'){
button.className = 'buttonload';
button.innerHTML = '<i class="fa fa-spinner fa-spin"></i>Loading';
}
setTimeout(function() { checkAnswer(); }, 100);
};
}
//self calling function
showQuestions();
The website is on my local now but i can upload a screenimage if need be and the whole code of the webpage. Or is the issue in html?
edit: here is html/css code
<style>
/*========================================================
Quiz Section
========================================================*/
/*styling quiz area*/
.main {
background-color: white;
margin: 0 auto;
margin-top: 30px;
padding: 30px;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
/*white-space: nowrap;*/
}
/*Editing the number of questions*/
.spanclass {
font-size: x-large;
}
#pages{
border: 3px solid;
display: inline-flex;
border-radius: 0.5em;
float: right;
}
#question{
word-break: break-all;
}
/*format text*/
p {
text-align: left;
font-size: x-large;
padding: 10px 10px 0;
}
.optionimg{
border: 2px solid black;
border-radius: 1.5em;
}
/*Form area width*/
/*formatting answers*/
.listyle {
list-style-type: none;
text-align: left;
background-color: transparent;
margin: 10px 5px;
padding: 5px 10px;
border: 1px solid lightgray;
border-radius: 0.5em;
font-weight: normal;
font-size: x-large;
display: inline-grid;
width: 48%;
height: 300px;
overflow: auto;
}
.listyle:hover {
background: #ECEEF0;
cursor: pointer;
}
/*Change effect of question when the questions is selected*/
.selected, .selected:hover {
background: #FFDEAD;
}
/*change correct answer background*/
.correct, .correct:hover {
background: #9ACD32;
color: white;
}
/*change wrong answer background*/
.wrong, .wrong:hover {
background: #db3c3c;
color: white;
}
/*========================================================
Submit Button
========================================================*/
.main button {
text-transform: uppercase;
width: 20%;
border: none;
padding: 15px;
color: #FFFFFF;
}
.submit:hover, .submit:active, .submit:focus {
background: #43A047;
}
.submit {
background: #4CAF50;
min-width: 120px;
}
/*next question button*/
.next {
background: #fa994a;
min-width: 120px;
}
.next:hover, .next:active, .next:focus {
background: #e38a42;
}
.restart {
background-color:
}
/*========================================================
Results
========================================================*/
.circle{
position: relative;
margin: 0 auto;
width: 200px;
height: 200px;
background: #bdc3c7;
-webkit-border-radius: 100px;
-moz-border-radius: 100px;
border-radius: 100px;
overflow: hidden;
}
.fill{
position: absolute;
bottom: 0;
width: 100%;
height: 80%;
background: #31a2ac;
}
.score {
position: absolute;
width: 100%;
top: 1.7em;
text-align: center;
font-family: Arial, sans-serif;
color: #fff;
font-size: 40pt;
line-height: 0;
font-weight: normal;
}
.circle p {
margin: 400px;
}
/*========================================================
Confeeti Effect
========================================================*/
canvas{
position:absolute;
left:0;
top:11em;
z-index:0;
border:0px solid #000;
}
.imagecenter{
display: block;
margin: 0 auto;
}
.buttonload {
background-color: #04AA6D; /* Green background */
border: none; /* Remove borders */
color: white; /* White text */
padding: 12px 24px; /* Some padding */
font-size: 16px; /* Set a font-size */
}
/* Add a right margin to each icon */
.fa {
margin-left: -12px;
margin-right: 8px;
}
#media only screen and (max-width: 900px){
.listyle {
width: 100% !important;
height: auto !important;
}
.imagecenter {
width: 100% !important;
}
.listyle img{
width: inherit !important;
height: unset !important;
}
.ulclass
{
padding:0px !important;
}
}
</style>
<!-- Main page -->
<div class="main">
<!-- Number of Question -->
<div class="wrapper" id="pages">
<span class="spanclass" id="quizNumber">1</span><span class="spanclass">/<?=$count?></span>
</div>
<!-- Quiz Question -->
<div class="quiz-questions" id="display-area">
<p id="question"></p>
<ul class="ulclass" id="options">
</ul>
<div id="quiz-results" class="text-center">
<button type="button" name="button" class="submit" id="submit">Submit</button>
</div>
</div>
</div>
<canvas id="canvas"></canvas>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
I'm guessing that #question{ word-break: break-all; } is probably the culprit then? –
CB..yes that fixed it:)
I have a list of players that user scrolls through and I'm trying create an always-visible player control, so user don't have to scroll through the list looking for the player that is playing sound.
I'd like somehow "clone" <audio> element to make it not actually play anything, just show information about currently playing media in another player and visually be identical to original player.
Currently I generate my own "player" and use media events to gather/display information about playing player, but it probably looks different in different browsers/systems.
Any suggestions?
const content = document.getElementById("content");
const eventHandler = (e =>
{
const remote = document.getElementById("remote"), //our custom "player"
progress = remote.querySelector(".progress"),
time = remote.querySelector(".time"),
position = time.querySelector(".position"),
duration = time.querySelector(".duration");
;
let player = null; //this will hold current player
//list of event handlers
const handler = {
play: e =>
{
if (player && player !== e.target)
player.pause();
player = e.target;
remote.classList.add("player");
remote.classList.add("play");
content.querySelector(".selected")?.classList.remove("selected");
player.classList.add("selected");
handler.timeupdate(e);
handler.durationchange(e);
},
pause: e =>
{
if (player.paused)
remote.classList.remove("play");
},
timeupdate: e =>
{
if (player !== e.target)
return;
position.textContent = readableTime(e.target.currentTime);
progress.value = e.target.currentTime;
},
durationchange: e =>
{
if (player !== e.target)
return;
duration.textContent = readableTime(e.target.duration);
progress.max = e.target.duration;
}
}
const readableTime = (t, ms) =>
{
const seconds = ~~t,
minutes = ~~(seconds / 60);
return ("" + minutes).padStart(1, "0") + ":" +
("" + seconds % 60).padStart(2, "0") +
(ms ? "." + (t.toFixed(1)+".0").substr((""+t).indexOf(".")+1, 1) : "");
}
remote.querySelector(".playpause").addEventListener("click", e =>
{
player[player.paused ? "play" : "pause"]();
});
progress.addEventListener("input", e =>
{
player.currentTime = progress.value;
});
return e =>
{
try{handler[e.type](e)}catch(er){console.error(er)};
};
})();
document.addEventListener("play", eventHandler, true);
document.addEventListener("pause", eventHandler, true);
document.addEventListener("timeupdate", eventHandler, true);
/* show players list */
{
const files = ["Zh[Wci", "ceei[", "iY_\\_", "ZWdY[", "^eki[", "fefZWdY["];
let file,
player = document.createElement("audio");
player.setAttribute("controls", "");
player.setAttribute("nodownload", "");
while((file = files.splice(~~(Math.random() * files.length), 1)).length)
{
/* https://www.bensound.com/ */
player.src = `^jjfi0%%mmm$X[diekdZ$Yec%X[diekdZ#cki_Y%X[diekdZ#${file[0]}$cf)`.replace(/./g,a=>String.fromCharCode(a.charCodeAt(0)+10) ) ;
content.appendChild(player);
player = player.cloneNode(true);
}
}
.content
{
display: flex;
margin: auto;
}
#content
{
display: grid;
max-height: 7em;
overflow-y: auto;
margin-top: 1em;
}
#remote
{
font-family: Roboto-Regular, Roboto, sans-serif;
font-size: 14px;
display: flex;
user-select: none;
cursor: default;
border: 1px solid black;
background-color: white;
color: black;
border-radius: 2em;
width: fit-content;
height: 2em;
padding: 0.5em 1.3em;
align-items: center;
gap: 10px;
max-height: 2em;
}
#remote:not(.player)
{
pointer-events: none;
opacity: 0.5;
}
/* play/pause button */
#remote .playpause
{
height: 1em;
width: 1em;
padding: 0.5em;
margin: auto -0.3em;
border-radius: 100%;
text-align: center;
cursor: pointer;
}
/* play */
#remote .playpause:after
{
--size: 1em;
width: var(--size);
height: var(--size);
content: "";
display: inline-block;
box-sizing: border-box;
border-style: solid;
border-width: calc(var(--size) / 2) 0 calc(var(--size) / 2) var(--size);
border-color: transparent transparent transparent black;
transition: all 100ms ease-in-out;
}
/* pause */
#remote.play .playpause:after
{
border-style: double;
border-width: 0 0 0 var(--size);
}
#remote .playpause:hover
{
background-color: rgba(32, 33, 36, 0.06);
}
#remote .progress
{
cursor: pointer;
}
#remote span
{
}
audio
{
border: 2px solid transparent;
border-radius: 2em;
height: 2.5em;
}
audio.selected
{
outline: 0;
border-color: orange;
}
<div id="remote">
<span class="playpause"></span>
<span class="time">
<span class="position">0:00</span>
/
<span class="duration">0:00</span>
</span>
<input type="range" class="progress" min="0" value="0">
</div>
<div class="content">
<div id="content">
</div>
</div>
I apologize in advance for my English but I am a Slovak and I also helped a bit with Google Translator :)
I hope to find help here for my problem ...
I have a loan calculator examples will be given below.
I try to make sure that when I have a calculator on the domain.xx/loan page, I need to achieve that when I choose the loan amount, loan maturity and when I click the button I want the page to redirect to domain.xx/request ... where the form will be ready
The problem is that I don't know how to send the information from the calculator to the second page so that it is attached to the form that will be filled in and it will be sent to the DB
I hope you understand my problem.
I use: Laravel and JS
$("document").ready(function() {
const rangeSliderAmount = document.querySelector('.lc-range-slider-amount');
const rangeSliderMonth = document.querySelector('.lc-range-slider-month');
const rangeValueBarAmount = document.querySelector('#lc-range-value-bar-amount');
const rangeValueBarMonth = document.querySelector('#lc-range-value-bar-month');
const rangeValueAmount = document.querySelector('#lc-range-value-amount');
const rangeValueMonth = document.querySelector('#lc-range-value-month');
const rangeAmount = document.getElementById("lc-amount");
const rangeMonth = document.getElementById("lc-month");
let isDown = false;
function dragHandler() {
isDown = !isDown;
if (!isDown) {
rangeValueAmount.style.setProperty('opacity', '0');
rangeValueMonth.style.setProperty('opacity', '0');
} else {
rangeValueAmount.style.setProperty('opacity', '0');
rangeValueMonth.style.setProperty('opacity', '0');
}
}
function dragOn(e) {
if (!isDown) return;
rangeValueHandler();
}
function rangeValueHandler() {
amountPercentage = `${((rangeSliderAmount.value - 500) * 100) / (6000 - 500)}%`;
monthPercentage = `${((rangeSliderMonth.value - 6) * 100) / (60 - 6)}%`;
rangeValueBarAmount.style.setProperty('width', amountPercentage);
rangeValueBarMonth.style.setProperty('width', monthPercentage);
rangeValueAmount.innerHTML = `${rangeSliderAmount.value}`;
rangeValueMonth.innerHTML = `${rangeSliderMonth.value}`;
rangeAmount.innerHTML = `${rangeSliderAmount.value}`;
rangeMonth.innerHTML = `${rangeSliderMonth.value}`;
vypocetSplatka();
}
rangeValueHandler();
rangeSliderAmount.addEventListener('mousedown', dragHandler);
rangeSliderAmount.addEventListener('mousemove', dragOn);
rangeSliderAmount.addEventListener('mouseup', dragHandler);
rangeSliderAmount.addEventListener('click', rangeValueHandler);
rangeSliderAmount.addEventListener('touchstart', dragHandler);
rangeSliderAmount.addEventListener('touchmove', dragOn);
rangeSliderAmount.addEventListener('touchend', dragHandler);
rangeSliderAmount.addEventListener('touchstart', rangeValueHandler);
rangeSliderMonth.addEventListener('mousedown', dragHandler);
rangeSliderMonth.addEventListener('mousemove', dragOn);
rangeSliderMonth.addEventListener('mouseup', dragHandler);
rangeSliderMonth.addEventListener('click', rangeValueHandler);
rangeSliderMonth.addEventListener('touchstart', dragHandler);
rangeSliderMonth.addEventListener('touchmove', dragOn);
rangeSliderMonth.addEventListener('touchend', dragHandler);
rangeSliderMonth.addEventListener('touchstart', rangeValueHandler);
function slideValue(inputElement) {
var sliderElement = inputElement.closest('.lc-ranger-box').find('.slider');
var val = parseInt(inputElement.val().replace(' ', '')) || 0;
var sliderMax = $(sliderElement).slider('option', 'max');
var sliderMin = $(sliderElement).slider('option', 'min');
if (val > sliderMax) {
val = sliderMax;
}
if (val < sliderMin) {
val = sliderMin;
}
$(sliderElement).slider('value', val);
val = formatNumber(val, 0, ',', ' ');
if (inputElement.val() !== val) {
inputElement.val(val);
}
}
$('.slider-value .value').change(function(){
slideValue($(this));
vypocetSplatka();
});
vypocetSplatka();
$('.insurance-box').on('change', 'input[name=poistenie]', function(){
vypocetSplatka();
});
function formatNumber(number, decimals, dec_point, thousands_sep) {
var str = number.toFixed(decimals ? decimals : 0).toString().split('.');
var parts = [];
for (var i = str[0].length; i > 0; i -= 3) {
parts.unshift(str[0].substring(Math.max(0, i - 3), i));
}
str[0] = parts.join(thousands_sep ? thousands_sep : ',');
return str.join(dec_point ? dec_point : '.');
}
function vypocetSplatka() {
var mesiace = parseInt($('[data-value="months"]').html());
var pozicka = parseInt($('[data-value="loan"]').html().replace(' ', ''));
var poplatok = (pozicka / 100) * 2;
$('.hascharge').show();
if(pozicka <= -1){
poplatok = 0;
$('.hascharge').hide();
}
var benefit = 2;
var perc, payment_mpr, payment_mpr_full, insurance, payment_month, payment_month_full, suma, suma_full, rateValue, rpmn;
$('[data-value="charge"]').text(poplatok);
$('[data-value="months-val"]').text(mesiace);
$('span[data-value="loan"]').text(price_format(pozicka));
if (pozicka <= 300) {
perc = 15.18;
} else if (pozicka <= 700) {
perc = 13.9;
} else if (pozicka <= 1499) {
perc = 11.4;
} else {
perc = 8.9;
}
if (pozicka <= 300 && mesiace<=60 && mesiace>=6) {
perc = 15.18;
} else if (pozicka <= 679 && mesiace<=60 && mesiace>=6) {
perc = 13.9;
} else if (pozicka <= 720 && mesiace<=60 && mesiace>=6) {
perc = 10.01;
} else if (pozicka <= 1499 && mesiace<=60 && mesiace>=6) {
perc = 11.4;
} else if (mesiace<=60 && mesiace>=6) {
perc = 8.9;
}
var diff = (Math.round((perc - benefit) * 100) / 100).toFixed(2);
diff = diff.replace('.', ',');
$('[data-value="interest"]').text(diff);
var pmt_ir_full = perc / 1200;
var pmt_ir = (perc - benefit) / 1200;
//pmt_ir = 13.9 / 1200;
var pmt_np = mesiace;
var pmt_pv = -pozicka;
if (pmt_np > 0 && pmt_pv < 0) {
payment_mpr = pmt(pmt_ir, pmt_np, pmt_pv);
payment_mpr_full = pmt(pmt_ir_full, pmt_np, pmt_pv);
$('.insurance-label').text('');
// poistenie
insurance = 0;
if ($('input[name=poistenie]:checked').val() === '1') {
insurance += 0.081 * pozicka / 100;
$('.insurance-label').text('vrátane poistenia');
}
if ($('input[name=poistenie]:checked').val() === '2') {
insurance += 0.148 * pozicka / 100;
$('.insurance-label').text('vrátane poistenia');
}
//payment_mpr += ' €';
payment_month = rd(payment_mpr + insurance);
payment_month_full = rd(payment_mpr_full + insurance);
payment_mpr = rd(payment_mpr);
suma = payment_month * mesiace + poplatok;
suma_full = payment_month_full * mesiace + poplatok;
$('#clientsave').html(price_format(suma_full - suma) + ' €');
} else {
payment_mpr = '';
}
$('[data-value="fee"]').html(price_format(payment_month));
$('[data-value="fee-val"]').text(price_format(payment_mpr));
rateValue = rate(pmt_np, payment_mpr, -pozicka + poplatok);
rpmn = (Math.pow(rateValue + 1, 12) - 1) * 100;
$('[data-value="rpmn-val"]').text(price_format(rpmn));
$('[data-value="sum"]').text(price_format(payment_mpr * mesiace + poplatok));
$('#vyskaF').val(pozicka);
$('#splatnostF').val(mesiace);
if ($('input[name=poistenie]:checked').val() === '0') { $('#poistenieF').val("bez poistenia"); };
if ($('input[name=poistenie]:checked').val() === '1') { $('#poistenieF').val("základné"); };
if ($('input[name=poistenie]:checked').val() === '2') { $('#poistenieF').val("rozšĂÂrenĂ©"); };
//bez benefitu repre priklad *NEW 16.11:2017 -- START
var diffWo = (Math.round((perc) * 100) / 100).toFixed(2);
diffWo = diffWo.replace('.', ',');
payment_mpr_full = rd(payment_mpr_full);
var rateValue_full, rpmn_full;
rateValue_full = rate(pmt_np, payment_mpr_full, -pozicka + poplatok);
rpmn_full = (Math.pow(rateValue_full + 1, 12) - 1) * 100;
$('[data-value="interest-wo"]').text(diffWo);
$('[data-value="fee-val-wo"]').text(price_format(payment_mpr_full));
$('[data-value="rpmn-val-wo"]').text(price_format(rpmn_full));
$('[data-value="sum-wo"]').text(price_format(payment_mpr_full * mesiace + poplatok));
// *NEW 16.11:2017 -- END
}
function rd(n) {
var r = Math.round(n * 100) / 100;
return r;
}
function price_format(number, decimals, decPoint, thousandsSep) {
decimals = decimals || 2;
number = parseFloat(number);
if (!decPoint || !thousandsSep) {
decPoint = ',';
thousandsSep = ' ';
}
var roundedNumber = Math.round(Math.abs(number) * ('1e' + decimals)) + '';
var numbersString = decimals ? roundedNumber.slice(0, decimals * -1) : roundedNumber;
var decimalsString = decimals ? roundedNumber.slice(decimals * -1) : '';
var formattedNumber = '';
while (numbersString.length > 3) {
formattedNumber += thousandsSep + numbersString.slice(-3);
numbersString = numbersString.slice(0, -3);
}
return (number < 0 ? '-' : '') + numbersString + formattedNumber + (decimalsString ? (decPoint + decimalsString) : '');
}
//function pmt(ir, np, pv, fv = 0, type = 0) { //defaul value nie je vsade podporovane!!! RBR
function pmt(ir, np, pv, fv, type) {
var fv = (typeof fv !== 'undefined') ? fv : 0;
var type = (typeof type !== 'undefined') ? type : 0;
/*
* ir - interest rate per month
* np - number of periods (months)
* pv - present value
* fv - future value
* type - when the payments are due:
* 0: end of the period, e.g. end of month (default)
* 1: beginning of period
*/
if (ir === 0) {
return -(pv + fv) / np;
}
var pvif = Math.pow(1 + ir, np);
var pmt = -ir * pv * (pvif + fv) / (pvif - 1);
if (type === 1) {
pmt /= (1 + ir);
}
return pmt;
}
function rate(paymentsPerYear, paymentAmount, presentValue, futureValue, dueEndOrBeginning, interest) {
//If interest, futureValue, dueEndorBeginning was not set, set now
if (interest == null) {
interest = 0.01;
}
if (futureValue == null) {
futureValue = 0;
}
if (dueEndOrBeginning == null) {
dueEndOrBeginning = 0;
}
var FINANCIAL_MAX_ITERATIONS = 128; //Bet accuracy with 128
var FINANCIAL_PRECISION = 0.0000001; //1.0e-8
var y, y0, y1, x0, x1 = 0,
f = 0,
i = 0;
var rate = interest;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = presentValue * (1 + paymentsPerYear * rate) + paymentAmount * (1 + rate * dueEndOrBeginning) * paymentsPerYear + futureValue;
} else {
f = Math.exp(paymentsPerYear * Math.log(1 + rate));
y = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
}
y0 = presentValue + paymentAmount * paymentsPerYear + futureValue;
y1 = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
// find root by Newton secant method
i = x0 = 0.0;
x1 = rate;
while ((Math.abs(y0 - y1) > FINANCIAL_PRECISION) &&
(i < FINANCIAL_MAX_ITERATIONS)) {
rate = (y1 * x0 - y0 * x1) / (y1 - y0);
x0 = x1;
x1 = rate;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = presentValue * (1 + paymentsPerYear * rate) + paymentAmount * (1 + rate * dueEndOrBeginning) * paymentsPerYear + futureValue;
} else {
f = Math.exp(paymentsPerYear * Math.log(1 + rate));
y = presentValue * f + paymentAmount * (1 / rate + dueEndOrBeginning) * (f - 1) + futureValue;
}
y0 = y1;
y1 = y;
++i;
}
return rate;
}
});
/*=================================================================*/
/* LOAN CALCULATOR
/*=================================================================*/
.lc-wrapper {
width: 100%;
margin: 0 auto;
padding: 5px 0;
overflow: hidden;
display: flex;
flex-direction: row;
border-radius: 10px;
background: #302f4e;
}
.lc-ranger-content {
width: 70%;
padding: 0 10px;
}
.lc-ranger-box {
width: 100%;
position: relative;
margin: 0;
padding: 0;
}
.lc-ranger-box:first-child {
margin-bottom: 5px;
border-bottom: 1px solid #28263e;
}
.lc-ranger-box-top {
width: 100%;
padding: 7px 25px;
display: flex;
justify-content: space-between;
align-items: center;
}
.lc-amount {
width: 90px;
height: 90px;
position: relative;
display: block;
padding-top: 20px;
line-height: 30px;
text-align: center;
font-size: 24px;
font-weight: 700;
color: #FF4C60;
font-style: normal;
line-height: normal;
border-radius: 50%;
box-sizing: border-box;
transform-origin: center center;
border: 5px solid #5E5C7F;
background: #F9F9FF;
}
.lc-amount::after {
display: block;
content: "EUR";
font-size: 16px;
letter-spacing: 0.07em;
margin-top: -2px;
}
.lc-month {
width: 90px;
height: 90px;
position: relative;
display: block;
padding-top: 20px;
line-height: 30px;
text-align: center;
font-size: 24px;
font-weight: 700;
color: #FF4C60;
font-style: normal;
line-height: normal;
border-radius: 50%;
box-sizing: border-box;
transform-origin: center center;
border: 5px solid #5E5C7F;
background: #F9F9FF;
}
.lc-month::after {
display: block;
content: "Mon.";
font-size: 16px;
letter-spacing: 0.07em;
margin-top: -2px;
}
.lc-ranger-box-sliding {
padding: 15px 0;
position: relative;
}
.lc-ranger-container {
position: relative;
padding: 15px 0;
}
.lc-ranger-box-bottom {
width: 100%;
padding: 7px 25px;
display: flex;
justify-content: space-between;
align-items: center;
}
.lc-pyment-content {
width: 30%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
position: relative;
padding: 0;
border-left: 1px solid #28263e;
}
.lc-payment-head {
width: 100%;
padding: 5px;
text-align: center;
}
.lc-payment-show {
width: 100%;
}
.lc-payment {
width: 200px;
height: 200px;
margin: 0 auto;
padding-top: 60px;
line-height: 60px;
display: block;
font-size: 36px;
font-weight: 700;
text-align: center;
position: relative;
border-radius: 100%;
box-sizing: border-box;
border: 5px solid #5E5C7F;
background: #F9F9FF;
color: #FF4C60;
}
.lc-payment::after {
display: block;
content: "EUR/MON.";
font-size: 16px;
letter-spacing: 0.07em;
margin-top: -2px;
}
.lc-payment-btn {
width: 100%;
padding: 4px 0 8px 0;
text-align: center;
}
.lc-text {
color: #F9F9FF;
}
.representative-example {
width: 100%;
position: relative;
margin: 50px 0;
padding: 15px;
font-size: 13px;
color: #F9F9FF;
border-radius: 5px;
background: #302f4e !important;
}
.representative-example span.span-bold {
font-weight: 500;
color: #FF4C60;
}
.representative-example span {
font-weight: 400;
color: #FF4C60;
}
#lc-range-value-bar-amount {
width: 100%;
content: "0";
background-color: #FF4C60;
position: absolute;
z-index: 100;
height: 25px;
top: 0;
margin: 0;
border-radius: 5px;
}
#lc-range-value-bar-month {
width: 100%;
content: "0";
background-color: #FF4C60;
position: absolute;
z-index: 99;
height: 25px;
top: 0;
margin: 0;
border-radius: 5px;
}
input[type='range'] {
width: 100%;
cursor: pointer;
position: absolute;
top: 0;
margin: 0;
border-radius: 5px
}
input[type=range]:focus {
outline: none;
}
input[type='range'],
input[type='range']::-webkit-slider-runnable-track,
input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type='range']::-webkit-slider-runnable-track {
width: 100%;
height: 25px;
cursor: pointer;
animate: 0.2s;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: #F9F9FF;
border-radius: 5px;
border: 0px solid #000101;
}
input[type='range']::-webkit-slider-thumb {
box-shadow: 0 2px 10px 0 rgba(0,0,0,0.08);
border: 14px solid #F9F9FF;
height: 53px;
width: 53px;
border-radius: 30px;
background: #FF4C60;
cursor: pointer;
-webkit-appearance: none;
margin-top: -13.5px;
position: relative;
z-index: 1000;
}
input[type='range']::-webkit-slider-thumb::before {
position: absolute;
content: '';
height: 10px; /* equal to height of runnable track */
width: 500px; /* make this bigger than the widest range input element */
left: -502px; /* this should be -2px - width */
top: 8px; /* don't change this */
background: #777;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 12.8px;
cursor: pointer;
animate: 0.2s;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: #353353;
border-radius: 25px;
border: 0px solid #000101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 20px;
width: 39px;
border-radius: 7px;
background: #000000;
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 12.8px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 39px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #000;
border: 0px solid #000101;
border-radius: 50px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: #000;
border: 0px solid #000101;
border-radius: 50px;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
border: 0px solid #000000;
height: 20px;
width: 39px;
border-radius: 7px;
background: #000;
cursor: pointer;
}
/*
#range-value {
content:"0";
background: rgba(233, 239, 244, 0.1);;
position: absolute;
z-index: 10000;
height: 25px;
top: -65px;
margin: 0;
border-radius: 5px;
left: 50%;
transform0: translateX(-50%);
font-size: 20px;
padding: 12px;
color: #41576B;
box-shadow: 0 2px 10px 0 rgba(0,0,0,0.08);
text-align: center;
opacity: 0;
}*/
/*=================================================================*/
/* BUTTONS
/*=================================================================*/
.btn {
border-radius: 30px;
font-family: "Rubik", sans-serif;
font-size: 16px;
font-weight: 700;
overflow: hidden;
line-height: 1;
padding: 12px 32px;
position: relative;
}
.btn:focus {
box-shadow: none;
}
.btn:focus {
outline: 0;
}
#-webkit-keyframes button-push {
50% {
-webkit-transform: scale(0.8);
transform: scale(0.8);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
#keyframes hvr-push {
50% {
-webkit-transform: scale(0.8);
transform: scale(0.8);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
.btn-default {
color: #FFF;
background: #FF4C60;
display: inline-block;
vertical-align: middle;
position: relative;
-webkit-transform: perspective(1px) translateZ(0);
transform: perspective(1px) translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
}
.btn-default:hover {
color: #FFF;
-webkit-animation-name: button-push;
animation-name: button-push;
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="loan bg-shadow">
<div class="container">
<form id="loanFormSubmit" method="get" action="{{ route('request.index') }}">
#csrf
<div class="container">
<div class="lc-wrapper shadow-main02s">
<div class="lc-ranger-content">
<div class="lc-ranger-box">
<div class="lc-ranger-box-top">
<span class="lc-ranger-text lc-text">Choose your loan amount</span>
<span id="lc-amount" class="lc-amount">6000</span>
</div>
<div class="lc-ranger-box-sliding">
<div class="lc-ranger-container slider-value">
<input id="lc-range-amount" type="range" class="slider lc-range-slider-amount" min="500" max="6000" step="100" value="1000">
<span id="lc-range-value-bar-amount"></span>
<span id="lc-range-value-amount" data-value="loan" class="value" style="display:none!important;">0</span>
</div>
</div>
<div class="lc-ranger-box-bottom">
<span class="lc-ranger-text lc-text">500€</span>
<span class="lc-ranger-text lc-text">6000€</span>
</div>
</div>
<div class="lc-ranger-box">
<div class="lc-ranger-box-top">
<span class="lc-ranger-text lc-text">Choose a maturity period</span>
<span id="lc-month" class="lc-month">60</span>
</div>
<div class="lc-ranger-box-sliding">
<div class="lc-ranger-container slider-value">
<input id="lc-range-month" type="range" class="slider lc-range-slider-month" min="6" max="60" step="1" value="24">
<span id="lc-range-value-bar-month"></span>
<span id="lc-range-value-month" data-value="months" class="value" style="display:none!important;">0</span>
</div>
</div>
<div class="lc-ranger-box-bottom">
<span class="lc-ranger-text lc-text">6 months</span>
<span class="lc-ranger-text lc-text">60 months</span>
</div>
</div>
</div>
<div class="lc-pyment-content">
<div class="lc-payment-head lc-text">
<h3>Your monthly payment</h3>
</div>
<div class="lc-payment-show">
<span id="lc-payment-show" class="lc-payment value " data-value="fee">
0,00
</span>
</div>
<div class="lc-payment-btn">
<button type="submit" class="btn btn-default" id="accept-loan">
I want a loan
</button>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
My attempt
added in body onload="setData()"
added in loan calculator form in button onclick="submitForm()"
and added in JS
$(document).ready(function() {
$("#accept-loan").click(function(e) {
var loan = $("#lc-range-amount").val();
var month = $("#lc-range-month").val();
var pay = $("[data-value='fee']").html().replace(' ', '');
var url = $("#loanFormSubmit")[0].setAttribute('action', '/request'+"?loan="+loan+"&months="+month+"&pay="+pay);
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: url,
method: 'post',
type: 'post',
data: {
_token: '{{csrf_token()}}',
loan: $("#loan").html(),
month: $("#month").html(),
pay: $("#pay").text(),
},
contentType: false,
processData: false,
success: function( data ) {
console.log(data);
}
});
});
});
function submitForm(){
if(typeof(localStorage) != "undefined"){
localStorage.loan = $('[data-value="loan"]').html();
localStorage.months = $('[data-value="months"]').html();
localStorage.payment = $('[data-value="fee"]').html();
}
document.getElementById("loanFormSubmit").submit();
}
function setData(){
if(typeof(localStorage) != "undefined"){
document.getElementById("loan").innerHTML = localStorage.loan;
document.getElementById("month").innerHTML = localStorage.months;
document.getElementById("pay").innerHTML = localStorage.payment;
}
}
Everything seems to be working as I should not know whether it is right to send information like this or whether it can be done even better
Hi you can receive all the data submitted in the form by using request method.
request('title') //Title is the name of the field
I suggest you follow this link to solve your problem. It shows all steps one by one.
https://vegibit.com/how-to-set-up-form-submission-in-laravel/
I'm trying to create a simple metronome using the web audio oscillator, so that no external audio files are needed. I'm creating the sound of the metronome by ramping the volume of the oscillator up and down very quickly (since you can't use start() and stop() more than once), and then repeating that function at a set interval. It ends up sounding like a nice little wood block.
The code below works/sounds great in Chrome, Safari and Opera. But in Firefox, there's a nasty intermittent "click" when the volume ramps up. I've tried changing the attack/release times to get rid of the click, but they have to be really, really long before it consistently disappears. So long, in fact, that the oscillator just sounds like a sustained note.
var audio = new (window.AudioContext || window.webkitAudioContext)();
var tick = audio.createOscillator();
var tickVol = audio.createGain();
tick.type = 'sine';
tick.frequency.value = 1000;
tickVol.gain.value = 0; //setting the volume to 0 before I connect everything
tick.connect(tickVol);
tickVol.connect(audio.destination);
tick.start(0);
var metronome = {
start: function repeat() {
now = audio.currentTime;
//Make sure volume is 0 and that no events are changing it
tickVol.gain.cancelScheduledValues(now);
tickVol.gain.setValueAtTime(0, now);
//Play the osc with a super fast attack and release so it sounds like a click
tickVol.gain.linearRampToValueAtTime(1, now + .001);
tickVol.gain.linearRampToValueAtTime(0, now + .001 + .01);
//Repeat this function every half second
click = setTimeout(repeat, 500);
},
stop: function() {
if(typeof click !== 'undefined') {
clearTimeout(click);
tickVol.gain.value = 0;
}
}
}
$("#start").click(function(){
metronome.start();
});
$("#stop").click(function(){
metronome.stop();
});
Codepen
Is there any way to get FF to sound like the other 3 browsers?
I was getting the exact same problem in latest Opera and found the problem to be the individual sounds 'decimal time length'.
I wrote a morse code translator, and like yours, it's just a series of simple short sounds/beeps created via createOscillator.
With morse code you have a speed count (words per minute) based on a 5 letter long word like codex or paris.
To get 20 or 30 paris' per minute to finish exactly on the minute, I had to use a sound time length of, for example, 0.61. In Opera, this caused the 'end of sound click'. On changing this to 0.6 and the click disappeared across all browsers - except Firefox.
I've tried freq = 0 and gain = 0 between sounds but still get the click at the end in FF and I don't know enough about Web Audio to try anything else.
On another note, I noticed you're using a loop and timeout to get to the next tick. Have you tried an 'Oscillator onended function' instead? I've used it with a simple counter increment and variable length blank sound/note. Go to the very end of my JS if you want to have a look.
**UPDATE - I've been fiddling about with setValueAtTime() and linearRampToValueAtTime() and appeared to have cracked the click problem. Scroll to bottom of script to see example. **
(function(){
/* Morse Code Generator & Translator - Kurt Grigg 2003 (Updated for sound and CSS3) */
var d = document;
d.write('<div class="Mcontainer">'
+'<div class="Mtitle">Morse Code Generator Translator</div>'
+'<textarea id="txt_in" class="Mtxtarea"></textarea>'
+'<div class="Mtxtareatitle">Input</div>'
+'<textarea id="txt_out" class="Mtxtarea" style="top: 131px;"></textarea>'
+'<div class="Mtxtareatitle" style="top: 172px;">Output</div>'
+'<div class="Mbuttonwrap">'
+'<input type="button" class="Mbuttons" id="how" value="!">'
+'<input type="button" class="Mbuttons" id="tra" value="translate">'
+'<input type="button" class="Mbuttons" id="ply" value="play">'
+'<input type="button" class="Mbuttons" id="pau" value="pause">'
+'<input type="button" class="Mbuttons" id="res" value="reset"></div>'
+'<select id="select" class="Mselect">'
+'<option value=0.07 selected="selected">15 wpm</option>'
+'<option value=0.05>20 wpm</option>'
+'<option value=0.03>30 wpm</option>'
+'</select>'
+'<div class="sliderWrap">volume <input id="volume" type="range" min="0" max="1" step="0.01" value="0.05"/></div>'
+'<div class="Mchckboxwrap">'
+'<span style="text-align: right;">separator <input type="checkbox" id="slash" class="Mchckbox"></span>'
+'</div>'
+'<div id="about" class="Minfo">'
+'<b>Input morse</b><br>'
+'<ul><li>Enter morse into input box using full stop (period) and minus sign (hyphen)</li>'
+'<li>Morse letters must be separated by 1 space</li>'
+'<li>Morse words must be separated by 3 or more spaces</li>'
+'<li>You can use / to separate morse words. There must be at least 1 space before and after each separator used</li>'
+'</ul>'
+'<b>Input text</b><br>'
+'<ul class="Mul"><li>Enter text into input box</li>'
+'<li>Characters that cannot be translated will be ignored</li>'
+'<li>If morse and text is entered, the converter will assume morse mode</li></ul>'
+'<input type="button" value="close" id="clo" class="Mbuttons">'
+'</div><div id="mdl" class="modal"><div id="bdy"><div id="modalMsg">A MSG</div><input type="button" value="close" id="cls" class="Mbuttons"></div></div></div>');
var ftmp = d.getElementById('mdl');
var del;
d.getElementById('tra').addEventListener("click", function(){convertToAndFromMorse(txtIn.value);},false);
d.getElementById('ply').addEventListener("click", function(){CancelIfPlaying();},false);
d.getElementById('pau').addEventListener("click", function(){stp();},false);
d.getElementById('res').addEventListener("click", function(){Rst();txtIn.value = '';txtOt.value = '';},false);
d.getElementById('how').addEventListener("click", function(){msgSelect();},false);
d.getElementById('clo').addEventListener("click", function(){fadeOut();},false);
d.getElementById('cls').addEventListener("click", function(){fadeOut();},false);
d.getElementById('bdy').addEventListener("click", function(){errorSelect();},false);
var wpm = d.getElementById('select');
wpm.addEventListener("click", function(){wpMin()},false);
var inc = 0;
var playing = false;
var txtIn = d.getElementById('txt_in');
var txtOt = d.getElementById('txt_out');
var paused = false;
var allowed = ['-','.',' '];
var aud;
var tmp = (window.AudioContext || window.webkitAudioContext)?true:false;
if (tmp) {
aud = new (window.AudioContext || window.webkitAudioContext)();
}
var incr = 0;
var speed = parseFloat(wpm.options[wpm.selectedIndex].value);
var char = [];
var alphabet = [["A",".-"],["B","-..."],["C","-.-."],["D","-.."],["E","."],["F","..-."],["G","--."],["H","...."],["I",".."],["J",".---"],
["K","-.-"],["L",".-.."],["M","--"],["N","-."],["O","---"],["P",".--."],["Q","--.-"],["R",".-."],["S","..."],["T","-"],["U","..-"],
["V","...-"],["W",".--"],["X","-..-"],["Y","-.--"],["Z","--.."],["1",".----"],["2","..---"],["3","...--"],["4","....-"],["5","....."],
["6","-...."],["7","--..."],["8","---.."],["9","----."],["0","-----"],[".",".-.-.-"],[",","--..--"],["?","..--.."],["'",".----."],["!","-.-.--"],
["/","-..-."],[":","---..."],[";","-.-.-."],["=","-...-"],["-","-....-"],["_","..--.-"],["\"",".-..-."],["#",".--.-."],["(","-.--.-"],[" ",""]];
function errorSelect() {
txtIn.focus();
}
function modalSwap(msg) {
d.getElementById('modalMsg').innerHTML = msg;
}
function msgSelect() {
ftmp = d.getElementById('about');
fadeIn();
}
function fadeIn() {
ftmp.removeEventListener("transitionend", freset);
ftmp.style.display = "block";
del = setTimeout(doFadeIn,100);
}
function doFadeIn() {
clearTimeout(del);
ftmp.style.transition = "opacity 0.5s linear";
ftmp.style.opacity = "1";
}
function fadeOut() {
ftmp.style.transition = "opacity 0.8s linear";
ftmp.style.opacity = "0";
ftmp.addEventListener("transitionend",freset , false);
}
function freset() {
ftmp.style.display = "none";
ftmp.style.transition = "";
ftmp = d.getElementById('mdl');
}
function stp() {
paused = true;
}
function wpMin() {
speed = parseFloat(wpm.options[wpm.selectedIndex].value);
}
function Rst(){
char = [];
inc = 0;
playing = false;
paused = false;
}
function CancelIfPlaying(){
if (window.AudioContext || window.webkitAudioContext) {paused = false;
if (!playing) {
IsReadyToHear();
}
else {
return false;
}
}
else {
modalSwap("<p>Your browser doesn't support Web Audio API</p>");
fadeIn();
return false;
}
}
function IsReadyToHear(x){
if (txtIn.value == "" || /^\s+$/.test(txtIn.value)) {
modalSwap('<p>Nothing to play, enter morse or text first</p>');
fadeIn();
txtIn.value = '';
return false;
}
else if (char.length < 1 && (x != "" || !/^\s+$/.test(txtIn.value)) && txtIn.value.length > 0) {
modalSwap('<p>Click Translate button first . . .</p>');
fadeIn();
return false;
}
else{
playMorse();
}
}
function convertToAndFromMorse(x){
var swap = [];
var outPut = "";
x = x.toUpperCase();
/* Is input empty or all whitespace? */
if (x == '' || /^\s+$/.test(x)) {
modalSwap("<p>Nothing to translate, enter morse or text</p>");
fadeIn();
txtIn.value = '';
return false;
}
/* Remove front & end whitespace */
x = x.replace(/\s+$|^\s*/gi, '');
txtIn.value = x;
txtOt.value = "";
var isMorse = (/(\.|\-)\.|(\.|\-)\-/i.test(x));// Good enough.
if (!isMorse){
for (var i = 0; i < alphabet.length; i++){
swap[i] = [];
for (var j = 0; j < 2; j++){
swap[i][j] = alphabet[i][j].replace(/\-/gi, '\\-');
}
}
}
var swtch1 = (isMorse) ? allowed : swap;
var tst = new RegExp( '[^' + swtch1.join('') + ']', 'g' );
var swtch2 = (isMorse)?' ':'';
x = x.replace( tst, swtch2); //remove unwanted chars.
x = x.split(swtch2);
if (isMorse) {
var tidy = [];
for (var i = 0; i < x.length; i++){
if ((x[i] != '') || x[i+1] == '' && x[i+2] != '') {
tidy.push(x[i]);
}
}
}
var swtch3 = (isMorse) ? tidy : x;
for (var j = 0; j < swtch3.length; j++) {
for (var i = 0; i < alphabet.length; i++){
if (isMorse) {
if (tidy[j] == alphabet[i][1]) {
outPut += alphabet[i][0];
}
}
else {
if (x[j] == alphabet[i][0]) {
outPut += alphabet[i][1] + ((j < x.length-1)?" ":"");
}
}
}
}
if (!isMorse) {
var wordDivide = (d.getElementById('slash').checked)?" / ":" ";
outPut = outPut.replace(/\s{3,}/gi, wordDivide);
}
if (outPut.length < 1) {
alert('Enter valid text or morse...');
txtIn.value = '';
}
else {
txtOt.value = outPut;
}
var justMorse = (!isMorse) ? outPut : tidy;
FormatForSound(justMorse);
}
function FormatForSound(s){
var n = [];
var b = '';
if (typeof s == 'object') {
for (var i = 0; i < s.length; ++i) {
var f = (i == s.length-1)?'':' ';
var t = b += (s[i] + f);
}
}
var c = (typeof s == 'object')? t : s;
c = c.replace(/\//gi, '');
c = c.replace(/\s{1,3}/gi, '4');
c = c.replace(/\./gi, '03');
c = c.replace(/\-/gi, '13');
c = c.split('');
for (var i = 0; i < c.length; i++) {
n.push(c[i]);
}
char = n;
}
function vlm() {
return document.getElementById('volume').value;
}
function playMorse() {
if (paused){
playing = false;
return false;
}
playing = true;
if (incr >= char.length) {
incr = 0;
playing = false;
paused = false;
return false;
}
var c = char[incr];
var freq = 550;
var volume = (c < 2) ? vlm() : 0 ;
var flen = (c == 0 || c == 3) ? speed : speed * 3;
var osc = aud.createOscillator();
osc.type = 'sine';
osc.frequency.value = freq;
var oscGain = aud.createGain();
oscGain.gain.value = volume;
osc.connect(oscGain);
oscGain.connect(aud.destination);
var now = aud.currentTime;
osc.start(now);
/*
Sharp volume fade to stop harsh clicks if wave is stopped
at a point other than the (natural zero crossing point)
*/
oscGain.gain.setValueAtTime(volume, now + (flen*0.8));
oscGain.gain.linearRampToValueAtTime(0.0, now + (flen*0.9999));
osc.stop(now + flen);
osc.onended = function() {
incr++;
playMorse();
}
}
})();
body {
text-align: center;
}
.Mcontainer {
display: inline-block;
position: relative;
width: 382px;
height: 302px;
border: 1px solid #000;
border-radius: 6px;
text-align: center;
font: bold 11px sans-serif;
background-color: rgb(203,243,65);
box-shadow: 0px 4px 2px rgba(0,0,0,0.3);
}
.Mtitle {
-webkit-user-select: none;
-moz-user-select: none;
display: inline-block;
position: absolute;
width: 380px;
height: 20px;
margin: auto;
left: 0; right: 0;
font-size: 16px;
line-height: 20px;
color: #666;
}
.Mtxtareatitle {
-webkit-user-select: none;
-moz-user-select: none;
display: block;
position: absolute;
top: 60px;
left: -36px;
height: 22px;
width: 106px;
font-size: 18px;
line-height: 22px;
text-align: center;
color: #555;
transform: rotate(-90deg);
}
.Mtxtarea {
display: block;
position: absolute;
top: 18px;
margin: auto;
left: 0; right: 0;
height: 98px;
width: 344px;
border: 0.5px solid #000;
border-radius: 6px;
padding-top: 6px;
padding-left: 24px;
resize: none;
background-color: #fffff0;
font: bold 10px courier;
color: #555;
text-transform: uppercase;
overflow: auto;
outline: 0; box-shadow: inset 0px 2px 5px rgba(0,0,0,0.5);
}
.Minfo {
display: none;
position: absolute;
top: -6px; left:-6px;
padding: 6px;
height: auto;
width: 370px;
text-align: left;
border: 0.5px solid #000;
border-radius: 6px;
box-shadow: 0px 4px 2px rgba(0,0,0,0.3);
background-color: rgb(203,243,65);
font: 11px sans-serif;
color: #555;
opacity: 0;
}
.Mbuttonwrap {
display: block;
position: absolute;
top: 245px;
margin: auto;
left: 0; right: 0;
height: 26px;
width: 100%;
}
.Mbuttons {
display: inline-block;
width: 69px;
height: 22px;
border: none;
margin: 0px 3.1px 0px 3.1px;
background-color: transparent;
font: bold 11px sans-serif;
color: #555;
border-radius: 20px;
cursor: pointer;
box-shadow: 0px 2px 2px rgba(0,0,0,0.5);
outline: 0;
}
.Mbuttons:hover {
background-color: rgb(213,253,75);
}
.Mbuttons:active {
position: relative;
top: 1px;
box-shadow: 0px 1px 2px rgba(0,0,0,0.8);
}
.Mchckboxwrap {
display: block;
position: absolute;
top: 274px;
left: 289px;
width: 87px;
height: 21px;
line-height: 22px;
border: 0.5px solid #000;
color: #555;
background: #fff;
-webkit-user-select: none;
-moz-user-select: none;
}
.Mselect {
display: block;
position: absolute;
top: 274px;
left: 6px;
width: 88px;
height: 22px;
border: 0.5px solid #000;
padding-left: 5%;
background: #fff;
font: bold 11px sans-serif;
color: #555;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
}
::selection {
color: #fff;
background: #555;
}
.Mchckbox {
margin-top: 1px;
vertical-align: middle;
cursor: pointer;
outline: 0;
}
.modal {
display: none;
position: absolute;
margin: auto;
top: 0;right: 0;bottom: 0;left: 0;
background: rgba(0,0,0,0.5);
-webkit-user-select: none;
-moz-user-select: none;
opacity: 0;
text-align: center;
}
.modal > div {
display: inline-block;
position: relative;
width: 250px;
height: 70px;
margin: 10% auto;
padding: 10px;
border: 0.5px solid #000;
border-radius:6px;
background-color: rgb(203,243,65);
font: bold 11px sans-serif;
color: #555;
box-shadow: 4px 4px 2px rgba(0,0,0,0.3);
text-align: center;
}
.sliderWrap {
display: block;
position: absolute;
top: 274px;
margin:auto;padding: 0;
left: 0; right: 0;
width: 184px;
height: 21px;
border: 0.5px solid #000;
background: #fff;
font: bold 11px sans-serif;
color: #555;
line-height: 21px;
text-align: center;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
}
input[type=range] {
-webkit-appearance: none;
width: 50%;
margin: 0;padding: 0;
vertical-align: middle;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: #666;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 1px 1px 0.5px rgba(0, 0, 0, 0.5);
border: none;
height: 10px;
width: 20px;
border-radius: 5px;
background: #ffffff;
cursor: pointer;
-webkit-appearance: none;
margin-top: -3px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #666;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 4px;
cursor: pointer;
background: #666;
}
input[type=range]::-moz-range-thumb {
box-shadow: 1px 1px 0.5px rgba(0, 0, 0, 0.5);
height: 10px;
width: 20px;
border: none;
border-radius: 5px;
background: #ffffff;
cursor: pointer;
}
input[type=range]::-ms-thumb {
height: 10px;
width: 20px;
border: none;
border-radius: 5px;
background: #ffffff;
box-shadow: 1px 1px 0.5px rgba(0, 0, 0, 0.5);
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 4px;
cursor: pointer;
background: transparent;
border: 5px solid transparent;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #666;
}
input[type=range]::-ms-fill-upper {
background: #666;
}
::-ms-tooltip {
display: none;
}
select::-ms-expand {
display: none;
}
It would be best to get Firefox to fix the issue (if indeed it is a Firefox bug with automations). Having said that, you could probably make all the browsers be consistent by using an AudioBufferSource node that has a precomputed click waveform that you want. Just generate a sine wave, ramp it up and down as you want (manually) and play that back at regular intervals.
Not great, but it should be cross-platform.
AFAIK this issue is not specific to Firefox, although looking at your code, I'm unsure why it doesn't happen in other browsers.
The problem is that the moment you schedule a *rampToValueAtTime to an audible source when that source is not currently interpolating between two ramp points, the "clicking" sound occurrs, possibly due to how the underlying implementation will immediately start taking the new ramp point into consideration, even if it's scheduled to happen the future.
The clicking sound will also be heard if you schedule a new ramp point between two points between which interpolation is occurring.
What I came up with as a workaround solution is either using an alternative approach to gradually changing AudioParam values, setTargetAtTime, or setting the value property of the AudioParam to the first ramp point value. Not setValueAtTime, but assigning to the value property itself, before anything audible happens on the given branch.
setTargetAtTime
You'll be needing neither cancelScheduledValues nor setValueAtTime, just two calls to setTargetAtTime, which is just a setValueAtTime with an exponential interpolation with a specified length.
var metronome = {
start: function repeat() {
now = audio.currentTime;
//Play the osc with a super fast attack and release so it sounds like a click
tickVol.gain.setTargetAtTime(1, now, 0.01);
tickVol.gain.setTargetAtTime(0, now + 0.01, 0.01);
//Repeat this function every half second
click = setTimeout(repeat, 500);
}
}
Live demo on JSFiddle