Hey guys I'm new to programming, I need to make a website for school.
I want to open the next page when pressing the arrow keys. So I thougt,
I can put the URLs into an array an increment the index, when the button is pressed.
Unfortunately I get some random numbers from 1 to 3 when I press the down key.
const url = ['/#t1', '/#t2', '/#t3', './contact.html', './404.html'];
var index = 0;
$(document).keydown(function(e) {
switch(e.which) {
case 38: // up
up();
break;
case 40: // down
down();
break;
default: return;
}
e.preventDefault();
});
function up() {
index = index - 1;
alert(index);
window.location.href = url[index];
}
function down() {
index = index + 1;
alert(index);
window.location.href = url[index];
}
A quick way to solve this without using storage is to find the index in the array rather than keeping track of it. You can do that like so:
const url = ['/list', '/of', '/urls'];
//find index of current url in array
let index = url.indexOf(window.location.pathname)
if(index == -1){
//url is not in the array
windows.alert("invalid url")
}
Edit: I agree with Michael Geary that is is a bad idea for a real world website
Don't do this!
What you're doing is a fun exercise, but it breaks the normal page scrolling that any visitor to your site may expect to work.
When I view a web page, I scroll through it using the up and down arrow keys. For example, open the Stack Overflow home page or Hacker News and hit the down arrow a few times, then the up arrow. That scrolling is how web pages are supposed to work.
There are some exceptions. The Google home page opens with the the text cursor in the main input field, and the down arrow opens a list of recent searches. That's perfectly reasonable.
But having the down arrow jump to a whole new section of the page - or another page entirely! - is not what visitors expect. Don't do it unless you have a really good reason.
If you do have a good reason, I will be curious to hear it! :-)
Related
I have a ruby on rails application where the user can go to a previous or next question using their keyboard. One page is loaded at a time, which contains the link to a previous page, and the next page.
What I want to do is that if the user is at the very first page, pressing the left keyboard arrow key should not work at all, since it will be undefined. Additionally, if the user is at the very last page, pressing the right keyboard arrow key should not work either, since the next page will be undefined. Right now, if the user is at the first or last page and presses the left or right arrow key respectively, it throws an error in my application saying that "undefined" url can not be found.
I got the prev/next functionality working, but now am confused on how to proceed.
$(function() {
$(document).keyup(function(e) {
switch(e.keyCode) {
case 37 :
var a_href = $(this).find('a.previous_page').attr('href');
window.location=a_href;
break;
case 39 :
//window.location="/page-link-next";
var a_href = $(this).find('a.next_page').attr('href');
window.location=a_href;
break;
}
});
});
Use .length on a jQuery collection (such as .find) to figure out how many elements are in the collection.
Another thing to keep in mind is that var gets hoisted; having two vars declaring the same variable name inside a function isn't exactly valid. Better to declare the variable name elsewhere (such as at the top) and reassign, or use something other than a switch statement so you can use const, which has block scope and is a lot easier to deal with:
$(function() {
$(document).keyup(function(e) {
const keyCode = e.keyCode;
if (keyCode === 37) {
const a = $(this).find('a.previous_page');
if (a.length === 0) return;
window.location= a.attr('href');
} else if (keyCode === 39) {
const a = $(this).find('a.next_page');
if (a.length === 0) return;
window.location= a.attr('href');
}
});
});
It's better not to use switch if you can avoid it - it's unnecessarily wordy and error-prone.
While this issue has been addressed a few times here and here, subsequent Qualtrics updates have made it difficult to continue to apply these solutions.
My objective: count up the number of text boxes containing responses from 2 questions and use that number to determine what gets displayed in a third. The following javascript code used in a text question type on a page separating the second and third questions works fine:
Qualtrics.SurveyEngine.addOnload(function()
{
//Count up the number of text boxes with anything in them
var count = 0;
if('${q://QID1/ChoiceTextEntryValue/1}') count++;
if('${q://QID1/ChoiceTextEntryValue/2}') count++;
//etc...
if('${q://QID2/ChoiceTextEntryValue/1}') count++;
if('${q://QID2/ChoiceTextEntryValue/2}') count++;
//etc...
//Set count as embedded data (added to survey flow earlier)
Qualtrics.SurveyEngine.setEmbeddedData('count', count);
};
The problem is that I have a useless page between my second and third questions. If I use display logic to hide my intervening question with this code, the code doesn't execute. If I use javascript to hide the question and automatically move to the next page as described here, it works, but then the user can't move back in the survey because jQuery('#NextButton').click(); returns them to the third question. I've tried wrapping the above code in a substitute NextButton code and moving it to the same page with QID2 as shown here with at least one update that I could figure out:
this.hideNextButton ();
$('NextButton').insert({
before: "<input id=\"checkButton\" type=\"button\" value=\" -> \" title=\" -> \">"
});
$('checkButton').onclick = function() {
//Previous count and set code here
$('NextButton').click();
};
This works for counting up everything from QID1 (located on the previous page), but doesn't catch those from QID2 (same page).
I've also tinkered with placing code in addOnReady and addOnUnload to no avail.
What I need is either 1) an update to the solution that hides the question on an intervening page that modifies the Back button on the page with my third question to kick the participant two pages back, or 2) an update to the substitute button solution that will grab counts from the question on the same page.
With the hint given by #T.Gibbons, I was able to get things working.
Code for the first question, after including count1 as embedded data in the Survey Flow:
//Count up the number of text boxes with anything in them
var qid = this.questionId; //Pull question id
//Focus on a text box to force listener to fire; ensures downstream logic will work regardless of participant behavior
document.getElementById('QR~'+qid+'~1').focus();
var quest = document.getElementById(qid); //Set up listener
quest.addEventListener('blur', function() {
var count1 = 0;
if(document.getElementById('QR~'+qid+'~1').value) count1++;
if(document.getElementById('QR~'+qid+'~2').value) count1++;
//and so on...
//Set count1 as embedded data
Qualtrics.SurveyEngine.setEmbeddedData('count1', count1);
}, {capture: true});
Code for the second question, after including count in the Survey Flow:
//Count up the number of text boxes with anything in them, add to prior question
var qid = this.questionId; //Pull question id
var count1 = Qualtrics.SurveyEngine.getEmbeddedData('count1'); //Pull count1 from previous question
document.getElementById('QR~'+qid+'~1').focus(); //Focus on a text box, force listener to fire
//Set up listener
var quest = document.getElementById(qid);
quest.addEventListener('blur', function() {
var count2 = 0;
if(document.getElementById('QR~'+qid+'~1').value) count2++;
if(document.getElementById('QR~'+qid+'~2').value) count2++;
// and so on...
var count = count1 + count2;
//Set count as embedded data
Qualtrics.SurveyEngine.setEmbeddedData('count', count);
}, {capture: true});
Set the survey logic to depend on count and it's good to go.
Solved! - didn't update my random number generation after changing from switch statement to array... ups. - Thanks!
Problem
Building a web comic and wanted to have one of those "random" buttons, where you jump to any of the strips. I'm assuming the best way to do this would be something on the back end (PHP or such), but I want to do it with JavaScript.
I got as far as picking a random page, but had the problem that it would sometimes redirect to the page it's already on (or rather often until I have more pages). I tried to make it take the page out of the array if the current page is the same as the target page, but instead I end up getting redirected to "http://bcitcomp.ca/students/hsloman/Comp1850/final/undefined"
I even made sure to use splice instead of delete. Doesn't that re-index the list?
Code
var pickRandomPage = function () {
// random Pages available
var links = [
"construction.html",
"placeholder.html",
"noplaymobil.html"];
// current Page
var currentURL = window.location.href;
var currentPage = currentURL.substr(currentURL.lastIndexOf('/')+1);
// get rid of current page from array of options
for(var i = 0; i < links.length; i++){
if(links[i] == currentPage){
links.splice(i,1);
}
}
// get a random number, rounded number between 0 and number of links
var randomPage = Math.floor((Math.random() * 3) + 1);
var link = 'http://bcitcomp.ca/students/hsloman/Comp1850/final/' + links[randomPage];
// open it
window.open(link,"_self");
};
Resources used sofar
Get current URL in web browser
window.open() should open the link in same tab
but instead I end up getting redirected to "http://bcitcomp.ca/students/hsloman/Comp1850/final/undefined"
The undefined is because your randomPage variable will contain a number between 1 and 3, but the actual valid indices in your links array are only either 0 or 1 because it will only have two elements after you remove the current page URL.
Change:
var randomPage = Math.floor((Math.random() * 3) + 1);
to:
var randomPage = Math.floor(Math.random() * links.length);
put this right before the window.open(...) line:
if(link === window.location+"") return pickRandomPage();
This is saying, "if the chosen link is the page we're already on, run the function again" ..so it will keep trying until a new page is given. This is easier than trying to splice the array.
See: recursion for more info.
Right now I have a few issues I need to tweak out with my Quiz Application.
When the user answers the first question, he can skip the proceeding questions.
var usersGuess = -1; //this is the starting value of the userGuess variable
This is because the userGuess variable is updated by the id of the radio button clicked when the user makes a guess, and the default starting variable is what prevents the user from skipping the first question only. I have a few ideas on how to fix it, but not sure how to implement it. One would be to detect IF none of the radio inputs are checked then don't load the next question, else load it.
When a user goes back to the question, the previous checked radio button disappears. I haven't thought of how to fix this yet. Right now I have saved the previous answers into an empty array, but I don't believe it's working properly.
Here is the code that deals with userGuess and how it interacts with the Event Listener for my next button.
nextButton.addEventListener('click', function() {
//prevent user from skipping questions
if (usersGuess === -1) {
console.log(usersGuess);
alert('You must choose an answer!');
} else {
//if users guess is the id of the correct answer, add one
if (usersGuess == questions[index].correctAnswer) {
userScore += 1;
console.log('Users Score: ' + userScore);
}
//store previous user answers into an array
usersAnswers.push(usersGuess);
if (index + 1 < questions.length) {
index++;
addQuizQuestion(questions[index].question);
addQuizAnswers(questions[index].choices);
} else {
alert('You scored a ' + getPercent() + '%!');
}
}
}, false);
Here is a link to the codepen as well for testing: http://codepen.io/laere/pen/KVwBME
Appreciate the help!
Don't complicate things too much. All you need here is the index of the current question and, say, an array of boolean (or integers, for points) for each question.
All you need to do is to check whether the current question has been answered, and if so, allow the user to move on.
Of course, since this is Javascript, all this serves for a better user experience and nothing more - if someone WANTS to move on to the next question, they WILL (unless you implement some server-side checking/question loading).
reset usersGuess to -1 before loading next question.
if (index + 1 < questions.length) {
index++;
usersGuess = -1; // reset usersGuess
addQuizQuestion(questions[index].question);
addQuizAnswers(questions[index].choices);
}
Okay so I'm here trying to get myself acquainted with Adobe Acrobat's Javascript API -- I feel like I may be missing some easy ways of doing certain things, but let's find that out together.
The Question:
How would I go about finding the amount of pages that belong to a bookmark?
For example, I have the following Bookmark layout:
Intro [3 pages]
Factions [2 pages]
Character [3 pages]
End [1 page]
(would have posted a picture, but I don't have the permission to do so :/)
Essentially I would like to be able to automate the extraction of the # of pages each bookmark has, for a little project I'm working on to speed stuff up at work.
My code thus far:
/* Count Bookmark Children
TODO: Count Pages of each Bookmark */
function CountBm(bm) {
var count = 0;
console.println("Bookmark name: " + bm.name);
bm.execute(); // goto bm -- not necessary, just for personal reasons
console.println("Bookmark Start Page: " + (this.pageNum+1));
/* This would only work if each page in the bookmark was a child
of the bookmark being checked */
if (bm.children != null) {
for (var i = 0; i < bm.children.length; i++)
count++;
}
console.println("Pages in Bookmark: " + count);
}
var bkmk = bookmarkRoot.children[2]; // Character Bookmark
CountBm(bkmk);
Also, for the last two lines of that code, is there a better way to reference specific bookmarks? By name, perhaps?
I have done this by using the current bookmark's execute() destination relative to the next bookmark's execute() destination. So assuming the bookmarks follow the flow of the document, just run execute() on the next bookmark, and use this.pageNum to figure out how many pages you have jumped forward.
Something like:
this.pageNum = 0;
for (var i = 1; i < this.bookmarkRoot.children.length; i++) {
page = this.pageNum;
this.bookmarkRoot.children[i].execute();
console.println("This bookmark is " + (this.pageNum-page) + " pages long");
}
You can add handling for grandchildren bookmarks as well, depending on your application. The right solution is dependent upon the structure of your bookmarks. The print to console line above could be replaced with this.extractPages(...) for your application.
Unfortunately that's the only way to reference bookmarks. If you wanted to find a bookmark by it's name, you could store all the bookmark names in an object with their child indexes. It's a hack, but it can be helpful when you have a document with a large number of bookmarks.