I want to remove a newsletter element for 10 minutes after closing it. The panel should remain removed if the page is reloaded within that timespan. I was thinking of using localstorage but as far I know localstorage does not have expiration. I'm thinking of using setTimeout but not sure how to use it in this context. Also, this should be done purely with Javascript without any library. JSFiddle.
<section class="newsletter">
<div id="newsletter_container" class="newsletter_class">
<h1>
Panel Title
<button id="close_btn">
close
</button>
</h1>
<h3>Panel content
</h3>
</div>
</section>
.newsletter {
position: fixed;
bottom: 0;
}
#keyframes Slide_down {
0% {
transform: translateY(0);
}
100% {
transform: translateY(250px);
}
}
#newsletter_container {
display: block;
background-color: rgb(0, 122, 193,0.7);
width: 500px;
}
.slide_down {
animation: Slide_down 1.4s ease;
}
.newsletter_class {
display: none;
}
#close_btn {
float: right;
background-color: rgb(0, 122, 193,0.7);
border: none;
cursor: pointer;
}
#media only screen and (max-width:500px) {
#newsletter_container {
width: auto;
}
.newsletter_button {
width: 75%;
padding: 5px 5px;
margin-left: 10px;
margin-bottom: 10px;
}
}
#newsletter_container h1, h3 {
font-family: Arial, Helvetica, sans-serif;
color: white;
padding: 5px 10px;
}
#newsletter_container h1 {
font-size: 16px;
}
#newsletter_container i {
color: white;
}
#newsletter_container h3 {
font-size: 12px;
}
const newsletter = document.getElementById("newsletter_container");
const closeBtn = document.getElementById("close_btn");
closeBtn.addEventListener("click",()=>{
newsletter.classList.add("slide_down");
newsletter.addEventListener("webkitAnimationEnd",function(){
newsletter.remove();
});
});
Edit:
I've used localStorage to remove the elements after reloading, but it's not permanently removed after reloading. JSFiddle.
let removeNewsletter = localStorage.getItem('removeNewsletter');
const closeNewsLetter = () => {
newsletter.classList.add("close");
localStorage.setItem('removeNewsletter','enabled');
}
if(removeNewsletter === 'enabled'){
newsletter.style.display = "none"
newsletter.addEventListener("animationend",function(){
newsletter.remove();
});
}
closeBtn.addEventListener("click",()=>{
removeNewsletter = localStorage.getItem('removeNewsletter');
if(removeNewsletter !== 'enabled'){
newsletter.addEventListener("animationend",function(){
newsletter.remove();
});
closeNewsLetter();
}
});
var storeddate = Number(localStorage.getItem("storedate"));
if(storeddate){
let diff = (Date.now() - storeddate / 60000);
if(diff < 10){
newsletter.remove();
}
}
//localStorage.setItem('removeNewsletter',null);
Use the javascript Date.now() method to get the start time and save it in the local storage. Get another Date.now() when the page loads to compare with the stored time (if any) when the page refreshes and check if the difference is longer than 10 mins.
You can compare both like this:
var storeddate = Number(localStorage.getItem("storeddate"));
if (storeddate){
var diff = (Date.now() - storeddate) / 60000;
if (diff < 10){
newsletter.style.display = "none";
}
}
ps: the Date.now() time is in milliseconds so to get it in minutes you need to divide it by 60000
Related
I've just started a couple of days in web development.
I need help for - I have two texts in the HTML (p tag) on the same line, one linked to JS with an "ID" and the other to CSS with "Class" and by using keyframes, and I've been trying to add a static text on the same line that displays after the animated text.
I'm trying to output - Where the First text animates by default, and when JS actions are triggered, that is by clicking on the button, the second text should display a static text on the same line as the first text.
My code:
JavaScript
CSS
HTML
let secondText = document.getElementById("second-text");
let a = 1;
let b = 5;
let c = a + b;
let result = "";
function startAction() {
if (c <= 12) {
result = "December";
} else {
result = "Not-Exists";
}
secondText.textContent = result;
console.log(result);
}
#second-text {
margin: 30px;
font-size: 20px;
font-weight: 700;
}
.first-text {
margin: 30px;
font-size: 20px;
font-weight: 700;
animation: typing 10s steps(19) infinite;
overflow: hidden;
white-space: nowrap;
border-right: 2px solid #111;
width: 19ch;
}
#keyframes typing {
0% {
width: 0ch;
}
50% {
width: 19ch;
}
100% {
width: 0ch;
}
}
<p class="first-text" id="second-text">Welcome To My Page</p>
<button onclick="startAction()">Action</button>
Please, Help me figure out what went wrong in my code?
Is that what you are looking for ?
let secondText = document.getElementById("second-text");
let a = 1;
let b = 5;
let c = a + b;
let result = "";
function startAction() {
document.getElementById("second-text").classList.remove("first-text");
document.getElementById("second-text").classList.add("newClass");
if (c <= 12) {
result = "December";
} else {
result = "Not-Exists";
}
secondText.textContent = result;
console.log(result);
}
.first-text {
margin: 30px;
font-size: 20px;
font-weight: 700;
animation: typing 10s steps(19) infinite;
overflow: hidden;
white-space: nowrap;
border-right: 2px solid #111;
width: 19ch;
}
.newClass{
margin: 30px;
font-size: 20px;
font-weight: 700;
overflow: hidden;
white-space: nowrap;
width: 19ch;
}
#keyframes typing {
0% {
width: 0ch;
}
50% {
width: 19ch;
}
100% {
width: 0ch;
}
}
<p class="first-text" id="second-text">Welcome To My Page</p>
<button onclick="startAction()">Action</button>
I've tried to look for a solution for this but have failed miserably. It's my first ever time using JS (I'm trying to learn) so the possibility of my just not understanding the answers in the search results properly is quite high - sorry about that.
I am wanting a JS carousel, generated from an array, with Prev/Next buttons (ideally responsive etc but that'll come at a later stage), preferably with captions underneath. I can get the carousel to work but I end up getting a text link when I click on either Prev or Next. And I've no idea how to add the caption array underneath (I've taken out the JS for the captions for now because it was messing everything else up even further).
Relevant HTML:
<body onload="changePilt()">
<span id="prev" class="arrow">❮</span>
<div class="karussell" id="karussell">
<img class="karu" name="esislaid">
</div>
<span id="next" class="arrow">❯</span>
<div class="caption">
<h3 name="esikiri"></h3>
</div>
</body>
CSS, just in case:
.karussell {
position: relative;
width: 100%;
max-height: 600px;
overflow: hidden;
}
.arrow {
cursor: pointer;
position: absolute;
top: 40%;
width: auto;
color: #00A7E0;
margin-top: -22px;
padding: 16px;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
}
#next {
right: 0;
border-radius: 3px 0 0 3px;
}
#prev {
left: 0;
}
.arrow:hover {
background-color: rgba(0,0,0,0.8);
}
.caption {
text-align: center;
color: #00A7E0;
padding: 2px 16px;
}
.karu {
max-width: 75%;
}
#media (max-width:767px){.karu{max-width: 95%;}}
And finally, the dreaded JS:
var i = 0;
var s = 0;
var esileht = [];
var aeg = 5000;
//Image List
esileht[0] = 'img/tooted/raamat/graafvanalinn2016.jpg';
esileht[1] = 'img/tooted/kaart/kaart_taskus_esipool.jpg';
esileht[2] = 'img/tooted/kaart/graafkaart_esikylg.jpg';
//Change Image
function changePilt (){
document.esislaid.src = esileht[i];
if(i < esileht.length -1){
i++;
} else {
i = 0;
}
setTimeout("changePilt()", aeg);
}
document.onload = function() {
}
// Left and Right arrows
//J2rgmine
function jargmine(){
s = s + 1;
s = s % esileht.length;
return esileht [s];
}
//Eelmine
function eelmine(){
if (s === 0) {
s = esileht.length;
}
s = s -1;
return esileht[s];
}
document.getElementById('prev').addEventListener('click', function (e){
document.getElementById('karussell').innerHTML = eelmine();
}
);
document.getElementById('next').addEventListener('click', function (e) {
document.getElementById('karussell').innerHTML = jargmine();
}
);
I'm sure the solution is dreadfully obvious, I just cannot seem to be able to figure it out...
instead of innerHTML change src attribute of image
document.querySelector('#karussell img').src = eelmine();
And
document.querySelector('#karussell img').src = jargmine();
I was doing an exercise involving a typing speed test. I added a color palette that makes the whole text green if the character matches the test text and red if it does not match.
If I wanted individual characters to change though, all the ways I can think of going about this seem quite tedious. I've tried creating individual span tags every time a character is entered and assigning them to the array value of the text string but haven't been able to get it to work. Is there a more efficient way to do this or is my current method the "best" way to go about it?
I would much more prefer a general path to solve this as opposed to someone just writing out a complete solution so I can write it out on my own please.
const testWrapper = document.querySelector(".test-wrapper");
const testArea = document.querySelector("#test-area");
const originText = document.querySelector("#origin-text p").innerHTML;
const resetButton = document.querySelector("#reset");
const theTimer = document.querySelector(".timer");
var interval;
var timer = [0,0,0,0];
var timerRunning = false;
// Add leading zero to numbers 9 or below (purely for aesthetics):
function leadingZero(time) {
if (time <= 9) {
time = "0" + time;
}
return time;
}
// Run a standard minute/second/hundredths timer:
function runTimer() {
let currentTime = leadingZero(timer[0]) + ":" + leadingZero(timer[1]) + ":" + leadingZero(timer[2]);
theTimer.innerHTML = currentTime;
timer[3]++;
timer[0] = Math.floor((timer[3]/100)/60);
timer[1] = Math.floor((timer[3]/100) - (timer[0] * 60));
timer[2] = Math.floor(timer[3] - (timer[1] * 100) - (timer[0] * 6000));
}
// Match the text entered with the provided text on the page:
function spellCheck() {
let textEntered = testArea.value;
let originTextMatch = originText.substring(0,textEntered.length);
if (textEntered == originText) {
testWrapper.style.borderColor = "#429890";
clearInterval(interval);
} else {
if (textEntered == originTextMatch) {
testWrapper.style.borderColor = "#65ccf3";
testArea.style.color = "#00B400";
} else {
testWrapper.style.borderColor = "#e95d0f";
testArea.style.color = "#FF0000"
}
}
}
// Start the timer:
function start() {
let textEnteredLength = testArea.value.length;
if(textEnteredLength === 0 && !timerRunning) {
timerRunning = true;
interval = setInterval(runTimer, 10);
}
}
// Reset everything:
function reset(){
timer = [0,0,0,0];
theTimer.innerHTML = "00:00:00";
clearInterval(interval);
testArea.value = "";
timerRunning = false;
console.log("The reset button has been pressed.");
}
// Event listeners for keyboard input and the reset button:
testArea.addEventListener("keypress", start, false);
testArea.addEventListener("keyup", spellCheck, false);
resetButton.addEventListener("click", reset, false);
/*--------------------------------------------------------------
Typography
--------------------------------------------------------------*/
body,
button,
input,
select,
textarea {
font-family: 'Source Sans Pro', 'Helvetica', Arial, sans-serif;
font-size: 18px;
line-height: 1.5;
}
h1,
h2,
h3,
h4,
h5,
h6 {
clear: both;
}
p {
margin-bottom: 1.5em;
}
b,
strong {
font-weight: bold;
}
dfn,
cite,
em,
i {
font-style: italic;
}
blockquote {
margin: 0 1.5em;
}
address {
margin: 0 0 1.5em;
}
pre {
background: #eee;
font-family: "Courier 10 Pitch", Courier, monospace;
font-size: 15px;
font-size: 1.5rem;
line-height: 1.6;
margin-bottom: 1.6em;
max-width: 100%;
overflow: auto;
padding: 1.6em;
}
code,
kbd,
tt,
var {
font: 15px Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
}
abbr,
acronym {
border-bottom: 1px dotted #666;
cursor: help;
}
mark,
ins {
background: #fff9c0;
text-decoration: none;
}
sup,
sub {
font-size: 75%;
height: 0;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
bottom: 1ex;
}
sub {
top: .5ex;
}
small {
font-size: 75%;
}
big {
font-size: 125%;
}
/*--------------------------------------------------------------
Layout
--------------------------------------------------------------*/
body {
margin: 0;
padding: 0;
}
.masthead {
padding: 1em 2em;
background-color: #0D1B2E;
color: white;
}
.masthead h1 {
text-align: center;
}
.intro {
padding: 2em 2em;
color: #ffffff;
background: #429890;
}
.intro p,
.test-area {
margin: 0 auto;
max-width: 550px;
}
.test-area {
margin-bottom: 4em;
padding: 0 2em;
}
.test-wrapper {
border: 10px solid grey;
border-radius: 10px;
}
#origin-text {
margin: 1em 0;
padding: 1em 1em 0;
background-color: #ededed;
}
#origin-text p {
margin: 0;
padding-bottom: 1em;
}
.test-wrapper {
display: flex;
}
.test-wrapper textarea {
flex: 1;
}
.meta {
margin-top: 1em;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.timer {
font-size: 3em;
font-weight: bold;
}
#reset {
padding: .5em 1em;
font-size: 1.2em;
font-weight: bold;
color: #E95D0F;
background: white ;
border: 10px solid #E95D0F;
}
#reset:hover {
color: white;
background-color: #E95D0F;
}
<header class="masthead">
<h1>Test Your Typing Speed</h1>
</header>
<main class="main">
<article class="intro">
<p>This is a typing test. Your goal is to duplicate the provided text, EXACTLY, in the field below. The timer starts when you start typing, and only stops when you match this text exactly. Good Luck!</p>
</article><!-- .intro -->
<section class="test-area">
<div id="origin-text">
<p>The text to test.</p>
</div><!-- #origin-text -->
<div class="test-wrapper">
<textarea id="test-area" name="textarea" rows="6" placeholder="The clock starts when you start typing."></textarea>
</div><!-- .test-wrapper -->
<div class="meta">
<section id="clock">
<div class="timer">00:00:00</div>
</section>
<button id="reset">Start over</button>
</div><!-- .meta -->
</section><!-- .test-area -->
</main>
If efficiency is your question, I would say to use an MVVM framework such as KnockoutJS or Angular, then it's really easy to determine differences and keeps the code real clean.
I'd split the text to copy into two, side by side:
1. Text typed | 2. Text to copy
With a separate box to type into.
You would subtract what you type upon key press, probably bassed on string length, from 2.text to copy, and put it into 1.text typed.
Use a calculated method to determine if it matched, and set the class on 1.text typed accordingly.
I am trying to create a time tracker in the following format; 0:00:00. The first zero represents the hour, then minutes, then seconds. Currently, I have a working function that increments the number every second. I know there is a proper way to do this with getDate() and then modifying the hours, minutes and seconds using getHours(), getMinutes() and so on. I just can't seem to get it all to work together. I've attached a working jsFiddle to show how far I've gotten.
The goal is to have it look something like ... 0:00:59 then turn into 0:01:00 and so on. Thank you.
Full example # http://jsfiddle.net/London804/628xz9x7/2/
$('#submit').click(function(){
var start = setInterval(updateDisplay, 1000), // every millisecond call updateDisplay
timer = $('#timer'),
value = parseInt($(timer).find('.value').text(), 10);
function updateDisplay(){
value++;
$(timer).find('.value').text(value);
if (value >= 60) {
$('#sec').replaceWith("min");
}
if (value >= 3600) {
$('#sec').replaceWith("hrs");
}
if (value >= 86400) {
value = 0;
console.log('stop and take a break, you have been working over 24hrs!');
}
}
$('#stop').click(function(){
clearInterval(start);
});
$('#reset').click(function(){
clearInterval(start);
value = parseInt($(timer).find('.value').text('0'));
});
});
Here is a solution that doesn't involve all the slicing and dicing of html elements. I'm using Date objects to track elapsed time in milliseconds and updating the display by extracting a substring of a standard format string provided by the Date object.
The end result will be more accurate as you are not relying on the timer to tick off seconds but are using an actual elapsed time between calls.
You still have to mess with the final output formatting but the Date object has nice functions that allow you to pull all the components you many need in terms our hours, minutes, seconds etc...
var starting_ms ;
var elapsed ;
var $timer = $('#timer .value');
var $hrs = $('#elapsedtime #hrs');
var $min = $('#elapsedtime #min');
var $sec = $('#elapsedtime #sec');
var start;
function updateDisplay() {
elapsed.setTime(Date.now() - starting_ms);
$timer.text(elapsed.toUTCString().substr(20, 5));
$hrs.text(elapsed.getUTCHours() );
$min.text(elapsed.getUTCMinutes() );
$sec.text(elapsed.getUTCSeconds() );
}
$('#submit').click(function() {
if( start )
clearInterval(start);
starting_ms = Date.now();
elapsed = new Date(0);
start = setInterval(updateDisplay, 1000); // every millisecond call updateDisplay
});
$('#stop').click(function() {
clearInterval(start);
});
$('#reset').click(function() {
clearInterval(start);
starting_ms = Date.now();
updateDisplay();
});
* {
-webkit-tap-highlight-color: transparent
}
body {
-webkit-touch-callout: none;
-webkit-text-size-adjust: none;
-webkit-user-select: none;
background-color: #E4E4E4;
background-image: linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image: -webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image: -ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #A7A7A7), color-stop(0.51, #E4E4E4));
background-attachment: fixed;
font-family: 'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
font-size: 12px;
height: 100%;
margin: 0px;
padding: 0px;
text-transform: uppercase;
width: 100%
}
.app {
background: transparent url(../../img/logo.png) no-repeat center top;
position: absolute;
left: 50%;
top: 50%;
height: 50px;
width: 225px;
text-align: center;
padding: 180px 0px 0px 0px;
margin: -115px 0px 0px -112px
}
.app #login {
margin-top: 20px;
position: relative;
font-size: 18px;
text-transform: uppercase
}
.app #login:active {
color: #cbcbcb
}
#welcome {
width: 90%;
margin: 20px auto
}
#media screen and (min-aspect-ratio: 1 / 1) and (min-width: 400px) {
.app {
background-position: left center;
padding: 75px 0px 75px 170px;
margin: -90px 0px 0px -198px
}
}
h1 {
font-size: 24px;
font-weight: normal;
margin: 0px;
overflow: visible;
padding: 0px;
text-align: center
}
.event {
border-radius: 4px;
-webkit-border-radius: 4px;
color: #FFFFFF;
font-size: 12px;
margin: 0px 30px;
padding: 2px 0px
}
.event.listening {
background-color: #333333;
display: block
}
.event.received {
background-color: #4B946A;
display: none
}
#keyframes fade {
from {
opacity: 1.0
}
50% {
opacity: 0.4
}
to {
opacity: 1.0
}
}
#-webkit-keyframes fade {
from {
opacity: 1.0
}
50% {
opacity: 0.4
}
to {
opacity: 1.0
}
}
.blink {
animation: fade 3000ms infinite;
-webkit-animation: fade 3000ms infinite
}
#timer-container {
min-width: 300px;
max-width: 50%;
margin: 0 auto
}
#timer-container #timer {
text-align: center;
font-size: 20px;
color: #4887da;
font-weight: bold
}
#timer-container label {
display: block
}
#timer-container label input {
width: 98%
}
#timer-container #button-container {
text-align: center
}
#timer-container #button-container button {
-webkit-box-shadow: 0px 1px 5px 3px #9c899c;
-moz-box-shadow: 0px 1px 5px 3px #9c899c;
box-shadow: 0px 1px 5px 3px #9c899c;
width: 35%;
margin: 10px auto;
position: relative
}
#timer-container #button-container button:nth-child(2) {
width: 20%
}
/*# sourceMappingURL=styles.css.map */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="welcome">
<h2>Welcome please log in</h2>
<p>Stuff ...</p>
</div>
<div>
<fieldset id="timer-container">
<div id="timer"><span class="value">0:00</span> <span id="sec">sec</span>
</div>
<div id="button-container">
<button id="submit" type="submit">Start</button>
<button id='reset' type="reset">Reset</button>
<button id="stop" type="stop">Stop</button>
</div>
</fieldset>
<table id="elapsedtime">
<caption>Just for fun</caption>
<tr>
<td>Hrs</td><td>Min</td><td>Sec</td>
</tr>
<tr>
<td><span id="hrs"></span></td><td><span id="min"></td><td><span id="sec"></td>
</tr>
</table>
</div>
When you start the timer, save the current date-time.
var start_dt = Date.now();
When you want to update the display, start by using the following:
var current_dt = Date.now();
var elapsed_ms = current_dt - start_dt;
That gives an accurate count of the elapsed time. Repeatedly incrementing a variable as you are doing will drift.
Now, it's time to format as H:MM:SS
function format_timer(ms) {
var s = ("0" + Math.floor((ms / ( 1000)) % 60)).substr(-2);
var m = ("0" + Math.floor((ms / ( 60*1000)) % 60)).substr(-2);
var h = Math.floor((ms / (60*60*1000)) );
return h + ":" + m + ":" + s;
}
You can accomplish it with converting your seconds to dateTime format and then with simple regex:
var myDate = new Date(null, null, null, null, null, value).toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
Here is working fiddle: http://jsfiddle.net/628xz9x7/6/
if you are certain on implementing this logic by yourself, you can make some use of some basic mathematics.
function updateDisplay(){
value++;
// Example for minutes
if (value >= 60) {
secs = value % 60;
mins = (value - secs) / 60;
$(timer).find('.value').text("00:"+min+":"+secs);
//$('#sec').replaceWith("hrs");
}
}
You can add the implementation for the other fields, but what we simply do here is find how many seconds are over the minute, by using modulus and then subtract the seconds from the minutes and divide by 60 to get the amount of minutes elapsed, we can then set the labels with these new values.
One thing you may want to do is provide a formatNumber method:
function formatNumber(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
What this will do is provide the formatted string for the number to update label for values under 10, a test fiddle is here, I have not implemented all functionality but its a start for you : https://jsfiddle.net/628xz9x7/14/
JS Fiddle Demo
Note that I do an iteration every millisecond instead of a second, for faster testing.
var start, value, timer = $('#timer');
$('#submit').click(function(){
value = readTime(timer.text());
start = setInterval(updateDisplay, 1); // replace 1 with 1000
});
$('#stop').click(function(){ clearInterval(start); });
$('#reset').click(function(){
clearInterval(start);
value = parseInt(timer.text(formatTime(0)));
});
function updateDisplay(){
value++;
timer.text(formatTime(value));
if (value >= 86400) {
value = 0;
console.log('stop and take a break, you have been working over 24hrs!');
}
}
function formatTime(t){
var h = ('0' + parseInt( t / 3600 ) % 24).slice(-2),
m = ('0' + parseInt( t / 60 ) % 60).slice(-2),
s = ('0' + t % 60).slice(-2);
return h+':'+m+':'+s;
}
function readTime(s){
var r = s.split(':');
return parseInt(r[0])*3600 + parseInt(r[1])*60 + parseInt(r[2]);
}
I have a simple animation on my page that cycles through quotes (from a javascript array, currently). Before a new quote is loaded, jQuery moves the div to the right a bit and hides it. Then it loads the new text and moves the div back to the left while fading it in.
Here is the
JavaScript:
var lastIndex;
$(document).ready(function () {
cycleTestimonial(); // set first testimonial
setInterval(cycleTestimonial, 9000); // cycle through testimonials every x seconds after that
});
function cycleTestimonial() {
var testi = getTestimonial(); // retrieve testimonial
if (!testi) return; // usually means duplicate of last quote, so skip setting HTML
$('#testimonial').hide(0, function () { // erase current quote
$('#testimonial > #quote').html(testi['quote'].replace(/'/g, "’"));
$('#testimonial > #author').html(testi['auth']);
$('#testimonial > #tagline').html(testi['tag']);
$(this).velocity({ // set opacity to 0 and move right instantaneously to prepare to fade new quote in
right: '-=60',
opacity: 0.0
}, 0, function () {
var testiH = $(this).height();
var headH = $('#home-header').height() / 2;
$(this).offset({ 'top': (headH-(testiH/2)) });
$(this).show().velocity({ // fade in new quote and slide left
right: '+=60',
opacity: 1.0
}, 600);
});
});
}
function getTestimonial(index) {
var t = [ { "quote" : "I love this product.",
"auth" : "John Doe",
"tag" : "Preferred Client"
},
...
];
if (!index) { // no specific testimonial asked for, get a random one
index = Math.floor(Math.random() * t.length);
if (index == lastIndex) { // retrieved same testimonial as last time
cycleTestimonial(); // re-run until we get a new testimonial from last time
return;
}
else lastIndex = index; // set to ensure no repeats back-to-back
}
return t[index];
}
For thoroughness, here is the corresponding
HTML:
<div id="home-header">
<div class="boundary">
<div id="testimonial">
<div id="quote">
quote
</div>
<div id="author">
author
</div>
<div id="tagline">
tagline
</div>
</div>
</div>
</div>
And, finally, relevant
CSS:
.boundary {
display: block;
position: relative;
margin: 0 auto;
max-width: 1080px;
min-width: 720px;
height: inherit;
}
#home-header {
display: block;
position: relative;
height: 420px;
width: inherit;
}
#home-header #testimonial {
position: absolute;
display: block;
top: 40px;
right: 0px;
min-width: 350px;
max-width: 470px;
}
#home-header #testimonial #quote {
display: block;
width: inherit;
text-align: left;
font-size: 26pt;
font-style: italic;
line-height: 1.2;
color: #0085df;
font-weight: 300;
}
#home-header #testimonial #author {
display: block;
width: inherit;
text-align: right;
font-size: 14pt;
font-weight: 700;
color: #999;
}
#home-header #testimonial #tagline {
display: block;
width: inherit;
text-align: right;
text-transform: uppercase;
font-weight: 400;
font-size: 8pt;
color: #999;
}
Now, this code works great most of the time. However, when I switch away from the page to a different tab or window, and then come back to it, the alignment is all screwy until a new quote is loaded.
Also, when I load the page, occasionally the alignment gets screwed up then too, like it was placed before the page was fully loaded or loaded enough for it to place properly.
Is there a better way to do what I'm doing that won't come with these issues on placement?