JavaScript: Set Variable - javascript

I'm using http://fakeapp.com to run some browser automation tasks and am running into a bit of a roadblock with parsing in a variable to the URL string. This question is more about JavaScript loops than FakeApp (but just so question has some context). Here's what I have so far:
var idx = fake.loop.index;
fake.set('idx', idx);
console.log('idx: ' + idx)
What I need to do is just set the starting variable at let's say 500. Right now the repeatable action (this part is done in FakeApp) starts at 0 -- I need to start the index at a specific number and increment by one. Thanks!

Related

getcomputedstyle only the changes from default

The code I currently have gets the whole CSS, even the default one. What I want is to get only the CSS changed from default.
function baba() {
addEventListener("mouseover", function() {
var elem = document.getElementById("ex");
cssObj = window.getComputedStyle(elem, null)
var txt = "";
for (i = 0; i < cssObj.length; i++) {
cssObjProp = cssObj.item(i)
txt += cssObjProp + " = " + cssObj.getPropertyValue(cssObjProp) + "<br>";
document.getElementById("empty").innerHTML = txt;
}
})
}
<p id="ex" onclick="baba()">Hello World</p>
<h1>Hello World</h1>
<p id="empty"></p>
Okay, so here's how I'd tackle it. Note: I just slammed this out in the console in 5 minutes; I'm sure there are more efficient ways to handle it, but for PoC this should get you going.
Requirements Analysis
Really (barring a more specific edge-case application, anyway), what you're asking for is "How does Element <XXX>'s current computed style differ from a vanilla object of the same type in the same context?" It's nonsensical to ask how it differs from "default" because "default", perforce, is going to be influenced by said context (don't agree? Wait for it; I'll 'splain).
Because of this, really what we need to be examining is a <XXX> that lacks the effects applied to your target object (consequences of its DOM position, class, id, attributes, predecessors, etc.). The good news is: we can totally fake it! Check it out:
The Setup
First thing's first, let's get hold of our object. This would be better executed as a function, I know, but for illustrative purposes, work with me here. Let's pick an object you can see the results on right away. Let's see... how about the Search bar at the top of this very page? Hit f12 to pop your console, and you'll see it's name is 'q'. That'll work.
// Get the StackOverflow Search field from the top of this page.
var targetDOMElement = document.querySelector('[name="q"]');
// Now, let's get its current style snapshot.
var targetObjsStyles = window.getComputedStyle(targetDOMElement);
// ... and vomit it out to our console, just so we know what we're dealing with.
console.log('ORIGINAL SET (' + Object.keys(targetObjsStyles).length + ' rules):',targetObjsStyles);
Capital! Now we have our source object (our "<XXX>", if you will).
The Control
Next, we need something to compare it against. Now, being the obedient little boy who was raised Orthodox Scientist that I am, in my mind that's a control. Fortunately, we know plenty about our source object, so let's manufacture one:
// Create a new element of the same type (e.g. tagName) as our target
var tempCopyOfTarget = document.createElement(targetDOMElement.tagName);
// Insert it into the context AT THE BEGINNING of the page. Both bits here are important:
// if we create it within a documentFragment (try it) literally every property will
// be flagged as unique. I suspect this has to do with the client's default
// renderer, vs. the purity of a abstracted prototype, but I won't lie: I'm guessing.
// It MUST be at the start of the body to avoid silliness like
// body > .first-element ~ xxx { display:none; }
// CSS still won't let us target predecessors/ancestors, alas.
document.body.insertAdjacentElement('afterBegin', tempCopyOfTarget);
// Now our new object shares our target's context, get ITS snapshot.
var basicElementsCSS = window.getComputedStyle(tempCopyOfTarget);
console.log('BASELINE (DUMMY OBJECT) SET (' + Object.keys(basicElementsCSS).length + ' rules):',basicElementsCSS);
The Grunt Work
While I'm certain most folks see where I'm going at this point, let's finish her off. Given a testable quantity, and a control, check for deltas.
// Create an empty object to store any changes in.
var cleanSetOfStyles = {};
// Objectify our target's style snapshot, and iterate.
Object.entries(targetObjsStyles).forEach(p=>{
// If a key-value pair exists that matches our control, ignore it. Otherwise,
// tack it onto our clean object for later perusal.
if(basicElementsCSS[p[0]] !== p[1]){
cleanSetOfStyles[p[0]] = p[1];
}
});
Awesome! Nice work!
Conclusion
Now, assuming my hypothesis is correct, we should see within our clean object a set of properties and their corresponding values. The length of this list should be both non-zero, and different than the count contained within the raw sets above (which, the more observant of you will have noticed, WERE the same, in that the browser assigns ALL possible styles' values to an object when a getComputedStyles collection is requested.
// Display our deltas
console.log('CLEAN SET (' + Object.keys(cleanSetOfStyles).length + ' rules):',cleanSetOfStyles);
// Oh, and always remember to clean up after you make a mess in the lab.
tempCopyOfTarget.remove()
What's this!? VICTORY! At least in my environment (which has to factor my browser make, version, active plug-ins, supported features, operating system, etc., etc.; your mileage may vary), I count 116 rules that remain and are acting on our target object. These are the rules that differ from our vanilla, first-line-of-code object we summoned into being for the picoseconds it took the browser to take a gander at it.
CAVEATS
There's always a catch, isn't there?
This is NOT a foolproof system. I can think of a half dozen ways this will fail off the top of my head (:empty modifiers, depending on the scope you're in... [name="q"] ~ [name="q"] rules, the insertion of our dummy object now making apply to our target... :first-of-type no longer being applicable... all kinds of 'whoopsies'). BUT, I'm prepared to assert all the ones I can think of are both edge cases, and themselves manageable, given proper forethought.
TLDR
Here's the whole code, copy+pasteable directly into console, if you're so inclined, and sans comments:
var targetDOMElement = document.querySelector('[name="q"]');
var targetObjsStyles = window.getComputedStyle(targetDOMElement);
console.log('ORIGINAL SET (' + Object.keys(targetObjsStyles).length + ' rules):',targetObjsStyles)
var tempCopyOfTarget = document.createElement(targetDOMElement.tagName);
document.body.insertAdjacentElement('afterBegin', tempCopyOfTarget);
var basicElementsCSS = window.getComputedStyle(tempCopyOfTarget);
console.log('BASELINE (DUMMY OBJECT) SET (' + Object.keys(basicElementsCSS).length + ' rules):',basicElementsCSS)
var cleanSetOfStyles = {};
Object.entries(targetObjsStyles).forEach(p=>{
if(basicElementsCSS[p[0]] !== p[1]){
cleanSetOfStyles[p[0]] = p[1];
}
});
console.log('CLEAN SET (' + Object.keys(cleanSetOfStyles).length + ' rules):',cleanSetOfStyles);
tempCopyOfTarget.remove()
Final note: I know this question is a couple months old, but nobody really answered it outside of "Nope! You're screwed!"
On the off chance #angels7 still needs the fix, here ya go. Otherwise, "Hi, all you far-out future folk!"

Counting TAB key strokes in Qualtrics

I'm trying to set as embedded data, the number of times participants in my Qualtrics survey hit the tab key, but only on a certain block. I added, early in the survey, a new embedded data variable, called "tabcounter" and set its value to 0.
I inserted this code to the relevant block's JS, but the counter keeps on counting keystrokes in the following questions and blocks as well. How do I make it stop counting once the next block appears?
Qualtrics.SurveyEngine.addOnload(function() {
//tab counter
var tabPressCount = 0;
var currentQuestionID = this.getQuestionInfo().QuestionID;
jQuery(document).on("keydown", function(counter){
var key = counter.keyCode;
if ((key==9) && (currentQuestionID=='QID82')) {
tabPressCount++;
Qualtrics.SurveyEngine.setEmbeddedData('tabcounter', tabPressCount); }
});
I found a rather improvisational solution: on survey flow, I create a new embedded value right after the block I'm interested in, and input into it the "tabcounter" embedded value I created earlier.
That is, the old embedded value keeps on counting tab strokes all throughout the survey, but I'm getting its value only at the one point I'm interested in.
Good enough for what I'm looking for right now, but there must be a more elegant way to do this.

For loop keeps breaking out after 1 instance - Apps Script

I have looked everywhere I can think of for anything that can provide an answer to this. First time posting a question here - I can usually find my answers. I have a for loop that is pulling information from a range of data that is formatted in one cell like this: 09/01/2016 - Status changed to active.
The loop is supposed to first see how many values are in that column then go one by one and split the data into a simple array, post it into two columns on a separate sheet, then move onto the next one. The problem is that it stops after the first entry.
var numEntries = dataSheet.getRange(1,i+1,1000).getValues();
var lastEntry = numEntries.filter(String).length;
if (lastEntry == 7) {
// no change data to date
sheet.getRange(18,3).setValue("No changes yet");
} else {
var changeData = dataSheet.getRange(8,i+1,lastEntry-7).getValues();
for (var y = 0; y < changeData.length; y++) {
var changeHistory = changeData[y][y].split(" - ");
sheet.getRange(nextRow+1,2).setValue(changeHistory[0]);
sheet.getRange(nextRow+1,3).setValue(changeHistory[1]);
nextRow++;
Logger.log(nextRow);
Logger.log(changeData.length);
Logger.log(y);
}
}
I know that it is executing properly because it is properly setting the "No changes yet" value when there are no entries. Variable nextRow starts at a value of 17, and the log properly shows changeData.length with the number of entries and y being equal to 0. But then it stops. It doesn't follow the loop that y is still less than changeData.length. Any help is very much appreciated!
[edit] - I also want to point out that it does properly split and populate the first value into the two cells I want it to, so the whole for statement does work, it just doesn't loop. [edit]
[16-09-29 15:37:48:514 CDT] 18.0 [16-09-29 15:37:48:515 CDT]
11.0 [16-09-29 15:37:48:515 CDT] 0.0
changeData is an n*1 Array.
You are increasing y and and you are also trying to get the y-th column from changeData.
After the first iteration this is undefined because there's only one column.
undefined does not have a split method throwing an exception and terminating the script. (You may not see this exception, these kinds of exceptions aren't always shown to the user for some reason)
Try
var changeHistory = changeData[y][0].split(" - ");
instead.

For loop index undefined in IE9 for initial pass

On this page: http://koncordia.marketingassociates.com/19892arc/
I have a slideshow that I created custom prev/next links for. Each selection you make on the page advances it one slide forward. The progress bar at the top allows you to click a previous slide, and jump more than one back if you want (you can go from step 4 or step 1 for example).
This multi-step jump works fine in all the current major browsers, but the client uses IE9, and this is where I do not understand the source of the issue.
The following are the relevant methods in this issue. To mimic a user jumping back one or more slides I have a for loop iterate over simulatePrevClick() as many times as necessary; it's not sexy but it works.
The issue arises on the initial pass in IE9. The console spits out "undefined" for the first pass, but it says 0 for all other browsers (including IE 10 and 11) which is correct. If I remove the method call within the loop the iteration works perfectly, so it has something to do with the .click() event or way the method is called, but I don't know what.
No matter what, IE9 will show the immediate previous slide no matter how many they click back; the progress bar be out of sync if they click back more than one in this instance. The undefined result is not showing as an error, either.
//Highlight the right number of progress buttons
highlightProgressBar: function( slideNumber ) {
$(".btn-progress").attr('disabled', 'disabled').removeClass('active'); //Disabled all
$("#progress-wrapper a:lt(" + slideNumber + ")").removeAttr('disabled'); //Disable select number
$("#progress-wrapper a:eq(" + (slideNumber - 1) + ")").addClass('active'); //Add active to the specified button clicked
},
simulateNextClick: function () {
//The value of this must match what the responsiveslides function creates for the prev/next buttons (seen when you inspect element)
$(".transparent-btns_nav.transparent-btns1_nav.next").click();
},
simulatePrevClick: function () {
//The value of this must match what the responsiveslides function creates for the prev/next buttons (seen when you inspect element)
$(".transparent-btns_nav.transparent-btns1_nav.prev").click();
},
toggleProgressBar: function( clickedSlideNumber, activeSlideNumber ) {
var numSlides = activeSlideNumber - clickedSlideNumber;
for (var i=0; i < numSlides; i++) { //Anticipate user may click more than one step back
this.simulatePrevClick();
console.log(i); // **shows "undefined" on first pass in IE9 only**
}
this.highlightProgressBar(clickedSlideNumber);
}
Try to move the var i = 0 declaration out of the loop.
var i = 0;
for (; i < numSlides; i++) {}
It's really strange that that should happen.
This is just a guess, but I looked through the rest of your source code, and its possible that the root of your problem could be due to whenever you actually implement your toggleProgressBar function, in this area:
$(".btn-progress").click(function() {
var currentSlideID = $("#progress-wrapper").find('a.active').attr('id').split("-");
var clickedSlideID = $(this).attr('id').split("-");
slideFn.toggleProgressBar( clickedSlideID[1], currentSlideID[1] );
});
If I see right, your toggleProgressBar wants to accepts two numbers. However, what you're passing in are string literals:
slideFn.toggleProgressBar( "2", "1" );
ID attributes are output as strings, not numbers. I just tested the following in Chrome, and it worked:
"2" - "1" === 1 //true
This is because I guess V8 (Chrome's JS engine) coerces the two string literals into numbers. However, (while I have not tested it), this tells me that it's possible that IE might not be coercing the two strings into numbers (like I said, I don't know this for a fact, but this is something you might try debugging). Try this and see if it has any effect:
//first option
slideFn.toggleProgressBar( +clickedSlideID[1], +currentSlideID[1] );
//the + sign will typecast your strings into numbers
//second option
slideFn.toggleProgressBar( parseInt(clickedSlideID[1]), parseInt(currentSlideID[1]) );
However, in my experience, parseInt runs a little bit slower than using + to typecast the strings into numbers.
IE uses the Chakra JS engine, which I believe follows the standards of ECMAScript 3, which is from 1999. I haven't read through the standard, but it's worth considering the possibility that it has something to do with the issue.
Edit
Here's your problem:
$("#progress-wrapper").find('a.active') ==> []
The first time, there are no a.active elements. Thus, whenever you try to call split on an empty array, it throws a TypeError.
You need to give your first .btn-progress the class active, because the first time around, your first .btn-progress looks like this:
1
There's no active class. Only subsequent .btn-progress elements receive the class active whenever you click the .btn-continue. Your first one never does. Therefore, clickedSlideID[1] and currentSlideID[1] are undefined the first go around. It probably breaks in IE9 because IE9 doesn't understand i < undefined, but it's possible that other more modern browsers go ahead and execute anyway.
Somewhere in the beginning of your code, then, you need to do something like this:
$('.btn-progress').eq(0).addClass('active');
I just tried this in the console on your page, and it worked just fine. After I added the class active to the fist .btn-progress, currentSlideID[1] was now 1, and not undefined.

How can we increment variables declared in scriptlet inside javascript

I want to display an element of the list, but I have a problem with the incrementation of list counter. it inrements only one time.
here is my function code in javascript
var element= document.getElementById("question");
timeTotal =timeTotal -1;
var nextQuestNumber = <%=k%>;
var nbQuestion = <%=iter%>;
if (timeTotal <= 0 && nextQuestNumber>0 && nextQuestNumber<nbQuestion)
{
timeTotal=<%=a%>;
element.innerHTML = '<c:out value="<%=listQuestions.get(k).getQuestion()%>"/>';
<%=k++%>;
}
setTimeout("listIter()", 1000);
k is the counter initialized to zero, iter is the list size, and timeTotal is the variable decrimenting the total time (one minute).
So each minute i want to get the next element of list and display it.
So to load this function I did this:
<body onload="listIter()">
And to repeate this function each second i did this inside the function:
setTimeout("listIter()", 1000);
But unfortunately, this not work for me.
Could you help me on that please and tell m
You can't do this directly.
Either pass the whole list to the client side code first then have k client side and read the proper item from the client side array, or use AJAX to read the proper item from the server.
In addition, you don't have any stop condition so your function will keep running endlessly which isn't a good practice. When you are finished, don't call the function again.
The jsp expressions like <% .. %> or <c:out .. /> are evaluated on server side while your javascript code runs on client side. You should check the javascript code in your browser to see what is rendered server side.
Following issues in the program:
setTimeout("listIter()", 1000);
to
setTimeout(listIter, 1000);
and
<%=k++%>;
to
nextQuestNumber++;
and
timeTotal=<%=a%>;
receive it in some other varible in the program as it is getting reset in every run.

Categories

Resources