Set draggable bars to custom start position with javascript in Qualtrics - javascript

In Qualtrics, it is possible to set the starting position of draggable bars (i.e., their width) with a "Custom Start Position". This is done by dragging the bars to the desired width while editing the survey. However, I am looking for a way to set the width of the bars to a start position with JavaScript (or Prototype JavaScript).
Here are my attempts, first (successfully) trying to change the color of the bars (in qualtrics and on jsfiddle), then (successfully) trying to adapt these attempts to change the bar widths on jsfiddle; and then getting stuck because what works on jsfiddle does not work on Qualtrics.
In Qualtrics, I can change the color of draggable sliders with the following Prototype JavaScript (adapted from this answer):
Qualtrics.SurveyEngine.addOnload(function()
{
//change the color of all bars to red for testing
$(this.questionId).select('.bar').each(function(name, index) {
name.style.backgroundColor = "red";
});
});
The result can be seen (and inspected) here. Inspecting the survey in the link indeed shows that the background-color was set to red:
<div id="QID2~2~bar" class="bar" style="width: 103px; background-color: red;"></div>. A width argument is also present, meaning I should be able to modify the width with the following code (which indeed does work on jsfiddle when setting the library to prototype):
$("test").select('.bar').each(function(name, index) {
name.setStyle({ width: '40px'});
});
However, this code does not work on Qualtrics (when replacing $("test") with $(this.questionId) and including the code in Qualtrics addOnload function).
The following javascript also works on Qualtrics for changing bar colors (adapted from this answer):
Qualtrics.SurveyEngine.addOnload(function()
{
//change the color of all bars to red for testing
var bar = document.querySelectorAll('.bar');
for (var i=0; i < bar.length; i++) {
bar[i].setAttribute("style", "background-color:red");
}
});
With this code, I can also adjust the div width on jsfiddle:
var bar = document.querySelectorAll('.bar');
for (var i=0; i < bar.length; i++) {
bar[i].setAttribute("style", "width:40px");
}
However, again this has no effect in Qualtrics.
So, long story short: Is there a way to programmatically give the bars in Qualtrics a start position, e.g., by setting their width to 50% of the parent div?
Update:
After digging deeper into the Qualtrics Question API, I found setChoiceValue with which I can programmatically select multiple choice items. E.g.,
Qualtrics.SurveyEngine.addOnload(function()
{
this.setChoiceValue(2,true);
});
will select the 2nd radio-button by setting its value to true:
However, so far I was unable to either apply setChoiceValue to draggable bars or find a similar equivalent.
Update 2:
Qualtrics Support (who are very friendly and approachable) has suggested that setChoiceAnswerValue might be what I am looking for. However they also explained that they cannot provide customer support for JavaScript. I took a look at a more recent version of the API documentation which also lists setChoiceAnswerValue, but so far without success.

I must have made a typo in my original code, as it turns out that what I had started with actually works:
Qualtrics.SurveyEngine.addOnload(function()
{
$(this.questionId).select('.bar').each(function(name, index) {
name.setStyle({ width: '50px'});
});
});

Here is a solution for setting the custom start positions for draggable bars using the setChoiceValue method as documented in the Qualtrics Question API.
Below is an example code for a question with 10 bars using embedded data from previous questions.
var embedded = ["${e://Field/r1}", "${e://Field/r2}",
"${e://Field/r3}", "${e://Field/r4}", "${e://Field/r5}",
"${e://Field/r6}", "${e://Field/r7}", "${e://Field/r8}",
"${e://Field/r9}", "${e://Field/r10}"];
for (var i = 0; i < 11; i++) {
var index = i + 1;
var choiceInput = embedded[i];
this.setChoiceValue(index, choiceInput);
}
For setting the custom value of one bar:
Qualtrics.SurveyEngine.addOnload(function()
{
this.setChoiceValue(2, "80");
});

Related

jQuery UI sortable - overlapping by 50% doesn't seem to work

jQuery UI sortable plugin is intended to enable a group of DOM elements to be sortable. A nice demo is at official website here
The API documentation provides tolerance option, and the description says:
Specifies which mode to use for testing whether the item being moved is hovering over another item. Possible values: intersect, pointer
Furthermore, the description of intersect (which is default) states:
intersect: The item overlaps the other item by at least 50%.
I expected, that if I drag one item, and move it over another item, it will detect that I'm reordering the items as soon as 50% of the height overlaps. But it doesn't seem to work this way :(. Even if you check the official demo, and you try to drag the 1st item over the 2nd item, you'll see that the 1st item has to be dragged for entire height, like 100% of its height, over the 2nd element, and only then the order of items is swapped.
Am I missing something? Is there any way for me as a programmer to force the plugin to work as I expect it to work? I wish the user to move the 1st item only 50% of its height down, in order for the plugin to detect overlapping and perform reordering.
The short answer is:
There's a bug ticket for this, so it seems like the only option is some form of workaround.
Here's a workaround example that uses a custom sort function, which seemed to answer your question better. I'll keep the below example as well for another approach to the problem.
...
That covers the case with a single direction, but what if you want to implement a grid?
Here's a workaround fiddle that I edited (Grid example w/ insert): fiddle
Note: This doesn't swap blocks, it inserts them and pushes the rest back.
Here's a snip of the javascript / jQuery code involved that mocks 50% coverage:
var height = $(".tab").height();
var height = $(".tab").width();
$('#pointer').sortable({
cursorAt: { top: height/2, left: width/2 },
containment: 'parent',
tolerance: 'pointer'
});
Looking at the widget's code you'll find:
if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
this._rearrange(event, item);
} else {
break;
}
So, due you specifie tolerance: "intersect", this._intersectsWithSides(item) is take it.
And function _intersectsWithSides(item) it's defined here:
_intersectsWithSides: function(item) {
var isOverBottomHalf = this._isOverAxis(this.positionAbs.top +
this.offset.click.top, item.top + (item.height/2), item.height),
isOverRightHalf = this._isOverAxis(this.positionAbs.left +
this.offset.click.left, item.left + (item.width/2), item.width),
verticalDirection = this._getDragVerticalDirection(),
horizontalDirection = this._getDragHorizontalDirection();
it take "item.height/2" and "item.width/2"
You can go with your on function and redefine this behaviour:
_myIntersectsWithSides: function(item) {
var isOverBottomHalf = this._isOverAxis(this.positionAbs.top +
this.offset.click.top, item.top + (item.height/5), item.height),
isOverRightHalf = this._isOverAxis(this.positionAbs.left +
this.offset.click.left, item.left + (item.width/5), item.width),
verticalDirection = this._getDragVerticalDirection(),
horizontalDirection = this._getDragHorizontalDirection();
And that give you 20% (100/5 instead of 100/2) of width and height.
The "50%" it's defined by code.-
Hope this help

HTML: show movement when tabbing between inputs?

I have a web app I would like to be controllable from the keyboard.
I recently saw a library that showed movement of the blue outline when tabbing between form fields. Eg, starting with the field 'one' highlighted:
[one]
another
Then when tab is hit:
one
[ ]
another
then finishing:
one
[another]
As you can see, it where the focus is moving to quite obvious for keyboard users.
The bad news: I can't find this library more, or anything like it. So my question:
Is there a tool to show movement during field focus changes like this? and, more to the point, where is it?
EDIT: Be a little more explicit: no, I really do not want make newly selected fields have an animated border.
The effect is called Focus Transition, and the library is called Flying Focus.
Actually it's not very hard effect (depends on conditions, of course), if i understand you correct.
Just create a 'dummy' hidden outline object in css and attach handler on focus event to all inputs you need and move your outline as you want in attached handler
For example with jQuery (written right here, may not work):
var $outline = $('#outline');
var padding = 6;
$('input').focus(function () {
var width = parseInt($(this).width()) + padding;
var height = parseInt($(this).height()) + padding;
var top = $(this).parent().offset()['top'] - padding/2;
var left = $(this).parent().offset()['left'] - padding/2;
$outline.stop().animate({
top: top,
top: top,
width: width,
left: left
});
});
You can try this fiddle (http://jsfiddle.net/C4Gde/) with something similar

change css on scroll event w/ requestAnimation Frame

I want to change the background color of in-viewport elements (using overflow: scroll)
So here was my first attempt:
http://jsfiddle.net/2YeZG/
As you see, there is a brief flicker of the previous color before the new color is painted. Others have had similar problems.
Following the HTML5 rocks instructions, I tried to introduce requestAnimationFrame to fix this problem to no avail:
http://jsfiddle.net/RETbF/
What am I doing wrong here?
Here is a simpler example showing the same problem: http://jsfiddle.net/HJ9ng/
Filed bug with Chromium here: http://code.google.com/p/chromium/issues/detail?id=151880
if it is only the background color, well why don't you just change the parent background color to red and once it scroll just change it to pink?
I change your CSS to that
#dad
{
overflow-y: scroll;
overflow-x: hidden;
width: 100px;
height: 600px;
background-color:red;
}​
I remove some of you Jquery and change it to this
dad.bind('scroll', function() {
dad.css('background-color', 'pink');
});
And I remove this line
iChild.css('backgroundColor', 'red');
But is the Red color it is important that won't work for sure http://jsfiddle.net/2YeZG/5/
I like Manuel's Solution.
But even though I don't get what you're exactly trying to do, I want to point out a few things.
In your fiddle code, I saw that you included Paul Irish's Shim for requestAnimationFrame.
But you never use it.
(It's basically a reliable setTimeOut, nothing else) it's from frame based animations.)
So since you just want to change some CSS properties, I don't see why you would need it. Even if you want transitions, you should rely on CSS transitions.
Other than that your code could look something like
dad.bind('scroll', function() {
dad.css('background-color', 'pink');
eachElemNameHere.css('background-color','randomColor');
});
Also you should ideally not use something like that if you can help it. You should just add and remove class names and add all these properties in your CSS. Makes it work faster.
Also, again I don't quite get it, but you could use the jQuery function to find out each elements' position from the top to have better control.
Your problem seems to be that you only change the background color of the elements which have already been scrolled into view. Your code expects that the browser waits for your code to handle the scroll event before the browser redraws its view. This is most probably not a guarantee given by the HTML spec. That's why it flickers.
What you should do instead is to change the elements which are going to be scrolled into view. This is related to off screen rendering or double buffering as it is called in computer games programming. You build your scene off screen and copy the finished scene to the visible frame buffer.
I modified your first JSFiddle to include a multiplier for the height of the scroll area: http://jsfiddle.net/2YeZG/13/.
dad.bind('scroll', function() {
// new: query multiplier from input field (for demonstration only) and print message
var multiplier = +($("#multiplier")[0].value);
$("#message")[0].innerHTML=(multiplier*100)-100 + "% of screen rendering";
// your original code
var newScrollY = newScrollY = dad.scrollTop();
var isForward = newScrollY > oldScrollY;
var minVal = bSearch(bots, newScrollY, true);
// new: expand covered height by the given multiplier
// multiplier = 1 is similar to your code
// multiplier = 2 would be complete off screen rendering
var newScrollYHt = newScrollY + multiplier * dadHeight;
// your original code (continued)
var maxVal;
for (maxVal = minVal; maxVal < botsLen; maxVal++) {
var nxtTopSide = tops[maxVal];
if (nxtTopSide >= newScrollYHt) {
break;
}
}
maxVal = Math.min(maxVal, botsLen);
$(dadKids.slice(minVal, maxVal)).css('background', 'pink');
});
Your code had a multiplier of 1, meaning that you update the elements which are currently visible (100% of scroll area height). If you set the multiplier to 2, you get complete off screen updates for all your elements. The browser updates enough elements to the new background color so that even a 100% scroll would show updated elements. Since the browser seldom scrolls 100% of the area in one step (depends of the operating system and the scroll method!), it may be sufficient to reduce the multiplier to e.g. 1.5 (meaning 50% off screen rendering). On my machine (Google Chrome, Mac OS X with touch pad) I cannot produce any flicker if the multiplier is 1.7 or above.
BTW: If you do something more complicated than just changing the background color, you should not do it again and again. Instead you should check whether the element has already been updated and perform the change only afterwards.

How do I limit the range of my draggable SVG shape?

I have an SVG slider that I've been working on ... please see it on jsFiddle here.
I would like to limit the range of my sliders.
My JS started out as found on this picker (thanks to #Phrogz), then I poked and prodded at it until I was able to strip it down to its current state.
The sliders are working great, but I can really use some guidance on adding the limitations.
For example, I'd like slider_1 (the slider on the left) to be limited to the area in front of the blue rectangle.
JS is still pretty unnatural for me, so I'd appreciate any and all feedback.
Thanks-a-bunch.
Try throwing something like this into your move functions:
var limitLower = 0;
var limitUpper = 20;
if ( x < limitLower || x > limitUpper ) {
return;
}
Here's a fiddle with the above code inserted for slider1: http://jsfiddle.net/ucnyz/4/

How to split html to full-screen height pages?

I need to split some html content to pages, so that each page would have height of the screen and some predefined width. Page split can happen in the middle of paragraph (or probably some other html element), so this situation should be handled somehow.
What I really want to achieve is the effect of reading the book, page by page. I assume there will be a need for some javascript, so I'd prefer to to this with jQuery, but if other framework is required, it's also okay.
I have to admit that I'm quite new to HTML and all, so sorry if my guess is stupid, but currently I'm considering the following approach: measure actual height of the visible area (need to figure out how yet), then take my html document and incrementally take tag after tag, put this into invisible div and calculate its resulting height. When I'll have its height more than page height, I'm done. However, this approach will not work in case of long tags, e.g. long paragraph.
Thanks in advance.
EDIT: thanks for your previous answers. I tried to use approach of manual calculating the size of the elements, and encountered one problem which I cannot solve in a good way. This is problem of collapsing margins. What I'm trying to do is to loop through all the paragraphs in my document and sum up results of .outerHeight(true) jQuery call. This should give me the full height of element, including padding, margin and border. And it actually does what it says, but the problem here is that it doesn't take collapsing margins into account. Because of that I end up with wrong overall size (bigger than real one), because browser throws away some of margins (of adjacent paragraphs in my case), but I take them into account.
Any ideas how to solve this other than introducing the algorithm deciding which margins are collapsed and which are not? I think it is ugly...
You could use CSS3 multi-column rules, example: http://www.quirksmode.org/css/multicolumn.html
Or for support in all browsers use a javascript plugin: http://welcome.totheinter.net/columnizer-jquery-plugin/
This plugin even has a multi-page multi-column example: http://welcome.totheinter.net/2009/06/18/dynamic-multi-page-multi-column-newsletter-layout-with-columnizer/
I can think of one framework which seems to do what you need (and a bit more): https://github.com/Treesaver/treesaver
jQuery will give you the height (in pixels) of an element with the height() function.
jQuery("BODY").height() will give you the maximum height of the view port (though only if your content height is >= the height of the BODY - otherwise it will give you the height of how much space the body is taking up in the view port.)
Counting the heights of the P tags (or other tags) seems like a good way to go. I suppose if you want to break up the content of a P tag for large paragraphs, you could define a maximum "breakage" height for the last P tag on a page. You can then break rest of the contents of the P tag by creating a new P tag with jQuery("#the-next-page-id).append(jQuery("<P>"+restOfTheParagraphContent+"</P>"))
Use your own logic to calculate the height of each element in the html body
using jQuery code
$('selector').height();
Using this, you can calculate the height of some html elements and decide how much
elements should be displayed on your device screen.
for more, please visit jQuery Height Documentation
In case anyone still looking for something like this I recently did it using JQuery. It also leaves the first page empty (for title and such):
https://jsfiddle.net/xs31xzvt/
It basically iterates over the movable items and insert them into a new div if the previous div is full.
(function($) {
$(document).ready(formatPages)
function formatPages() {
var container = $('.container');
var subPage = $('.subpage').get(0);
var subPageHeight = subPage.offsetHeight;
var subPageScrollHeight = subPage.scrollHeight;
// See how many pages we'll need
var pages = Math.floor(subPageScrollHeight / subPageHeight) + 1;
//add a new page
var pageCount = 2;
var pageDiv = createPageDiv(pageCount);
var subPageDiv = createSubPageDiv(pageCount);
var addPage = function (){
pageCount++;
pageDiv = createPageDiv(pageCount);
subPageDiv = createSubPageDiv(pageCount);
pageDiv.append(subPageDiv);
container.append(pageDiv);
pageContentHeight = 0;
}
addPage()
container.append(pageDiv);
$('.movable').each(function() {
var element = $(this);
//remove the element
element.detach();
//try to add the element to the current page
if (pageContentHeight + element.get(0).offsetHeight > subPageHeight) {
subPageDiv.append(getFooterDiv().show());
//add a new page
addPage();
}
subPageDiv.append(element);
pageContentHeight += element.get(0).offsetHeight;
});
}
function createPageDiv(pageNum) {
return $('<div/>', {
class: 'page',
id: 'page' + pageNum
});
}
function createSubPageDiv(pageNum) {
return $('<div/>', {
class: 'subpage',
id: 'subpage' + pageNum
});
}
function getFooterDiv() {
return $('.footer').first().clone();
}
}(jQuery));

Categories