Why is IOS 7.0.3 picker goofing up my LiveCode webform? - iphone

I don't know where the best place to ask about this is. My problem seems to be with IOS 7.0.3 and how Safari is handling the picker in a web form. I've created a web form with LiveCode that works just fine in every browser I've tried. But on the iPhone, the picker malfunctions. If you choose one item and press Done, it reverts to 0 items chosen. If you choose two items and press done, it shows one item chosen. The same goes for three, four, and so on. Has anyone else had this experience? Here is a snippet of one of the multiple choice buttons.
<label for="authors[]">
Select Author(s)
<select name="authors[]" id="authors" multiple="yes" size="7" >
<?lc
put the number of lines in tAuthorList into tTotalAuthors
repeat with x = 1 to tTotalAuthors
put "<option value=" & q(line x of tAuthorList)
put lineOffset(line x of tAuthorList,tPrevAuthors) into tLineHit
if bDataSubmitted and line x of tAuthorList is line tLineHit of tPrevAuthors then
put " selected"
end if
put ">" & line x of tAuthorList & "</option>" & return
end repeat
?>
</select>
</label>
This is the URL:
http://lc.scs.earlham.edu/soul_therapy3.lc
Incidentally, I use it with an iframe in my Drupal 7 site:
http://soulshare.org/soul_therapy/tool

There is an issue (design choice?) in iOS7 where you need to not only scroll to the correct value but also tap your selected value. I don't know if this is your problem though...
In some forms you only needs to scroll to the correct value but in many, you need to scroll and THEN select. As you probably have guessed this has nothing to do with LiveCode...

This is a bug in IOS and has been reported to apple. Currently the best solution I've found uses jQuery to fix the selected items upon closing the picker. Simply paste this into your JS file and away you go.
// hack for iPhone 7.0.3 multiselects bug
if(navigator.userAgent.match(/iPhone/i)) {
$('select[multiple]').each(function(){
var select = $(this).on({
"focusout": function(){
var values = select.val() || [];
setTimeout(function(){
select.val(values.length ? values : ['']).change();
}, 1000);
}
});
var firstOption = '<option value="" disabled="disabled"';
firstOption += (select.val() || []).length > 0 ? '' : ' selected="selected"';
firstOption += '>« Select ' + (select.attr('title') || 'Options') + ' »';
firstOption += '</option>';
select.prepend(firstOption);
});
}
Multiple select in Safari iOS 7

Related

How to get contents on BindPopup

I am trying to get marker's .bindPopup content on click event so I can save it to localStorage. But it is not working properly for each marker.
L.marker([76.920614, -60.117188])
.addTo(map)
.bindPopup('<div><span class="claimed">DATA 1</span></div>')
.on('click', groupClick);
L.marker([77.841848, -31.289063])
.addTo(map)
.bindPopup('<div><span class="claimed">DATA 2/span></div>')
.on('click', groupClick)
function groupClick(event) {
var a = document.querySelector('.claimed').innerHTML;
console.log(a);
}
it would work on first click but on the second click on different marker, it will take the data from the first marker that i clicked instead of the second marker. In this case i have to click somewhere else on the map or click the popup close button first before i can click on the next marker to properly get the data. is there any fix on this?
PROBLEM:
you are selecting in your function only the first appearance of the class (not the clicked ones child) at
var a = document.querySelector('.claimed').innerHTML;
SOLUTION 1 (NOT RECOMMENDED):
You should use the this keyword, and the getPopup() and getContent() methods instead, your function should look something like:
function groupClick(event) {
var a = this.getPopup().getContent();
console.log(a);
}
This way you'll get the escaped html, so a much better and proper way is...
SOLUTION 2 (RECOMMENDED): if you store the necessary data in the markers options (instead of storing and getting html from popup), like this:
L.marker([40, 12], {data: 1, datastring: 'first'})
.addTo(map)
.bindPopup('ONE')
.on('click', groupClick);
Then you can access this options in your function this way:
function groupClick(event) {
var a = this.options.data + ' ' + this.options.datastring;
alert(a);
}
A working fiddle again.
EDIT: I have found a workaround for the desired logic. But still, you need to link the marker and its popup content, because:
Popup content is not a node in the DOM, so you cannot access it before it is opened with a user click.
So in my solution i store a simple integer in the marker options (divId: int), which is the unique id of the marker. In the popup content, the radio inputs have the same id concatenated with the desired string (<input type="radio" id="Item-10-0" name="Item-10" value="0" checked="">).
L.marker([40, 32], {
divId: 10
})
.addTo(map)
.bindPopup('<div id="2div" class="popup-todo"><input type="radio" id="Item-10-0" name="Item-10" value="0" checked=""><label for="Item-10-0">Claimed</label><input type="radio" id="Item-10-1" name="Item-10" value="1"><label for="Item-10-1">Unclaimed</label></div>')
.on('click', groupClick);
If the user clicks, the new node is already accessible, so you can select it and use its id and value.
function groupClick(event) {
var a = document.querySelector('input[name=Item-'+this.options.divId+']');
document.querySelector('#demo').innerHTML = a.id + ' ' + a.value;
}
The fiddle.

How can I write some javascript to click this "continue" button?

<span id="continue" class="a-button a-button-span12 a-button-primary"><span class="a-button-inner"><input id="continue" tabindex="5" class="a-button-input" type="submit" aria-labelledby="continue-announce"><span id="continue-announce" class="a-button-text" aria-hidden="true">
Continue
</span></span></span>
Above the the HTML from part of a page, which has a 'Continue' button that i'm trying to click, using my script.
So, writing in Javascript, i'm trying to click this button. But nothing I have tried works.
My attempted answer is:
function() {
var goButton = document.getElementById("continue");
goButton.click();},
Why doesn't it work? Help me, please !
You have set the ID of both the span and the input field to "continue". ID's should be unique for a single element. When I enter your code in the browser's console it returns the following:
> var goButton = document.getElementById("continue");
< undefined
> goButton.valueOf()
< <span id="continue" class="a-button a-button-span12 a-button-primary">
You can see the span is the element being selected instead of the input submit button. You should rename either of the 2 elements so both have a unique ID and use that in your script.
Edit: OP mentioned the HTML can not be changed so instead of fixing the use of a not-unique ID this Javascript can be used:
function() {
var continueSpan = document.getElementById("continue");
var goButton = continueSpan.firstElementChild.firstElementChild;
goButton.click();}

Angular -- data-binding for a form that grows

I'm trying to create a form with data-binding that the user can add items to; they can click a button to add another text field (in this example it's the "plus" button). Here's a screenshot:
I've got things working now so more list items appear when the user clicks the button, but I can't find a clean and simple solution for how to let each form-element bind to a separate instruction in the model (theoretically in some sort of array in $scope.form). So right now, every instruction text area always contains the same text (as expected, which is the problem).
Here's my view code (in jade, but should be readable):
ol
li( ng-repeat='instruction in form.instructions' )
input( name='instruction[]' type='text' ng-model='form.instructions.text' )
| <br>
input( type='button' value='+' ng-click='addInstr()' )
Here's my controller code.
formControllers.controller('new-instruction-set-ctrl', function ($scope, $http) {
$scope.form = $scope.form || {};
$scope.form.instructions = [{}];
$scope.addInstr = function() {
$scope.form.instructions.push({});
};
});
This finally worked for me. See live demo in Plunker.
View:
li( ng-repeat='instruction in form.instructions' )
input( name='instruction[]' type='text' ng-model='form.instructions[$index].text')
I didn't have to change my controller at all.
$index is automatically provided by ng-repeat.

Google's autocomplete not activated by pasting with mouse

The Google autocomplete API doesn't seem to be activating by pasting content into a text input with the mouse. It works fine if involving the keyboard at all, but not with just mouse.
I did notice, however, that after you paste your content into the text input it will activate from almost any keypress (tested right arrow key, end key, space).
You can repro it here on their autocomplete demo site.
Is this a bug? or as designed? If it's as designed, how to apply workaround?
I've got this as a workaround so far, but no simulated keypress events seem to work.
$('.txtLocation').bind("paste", function (e)
{
$('.txtLocation').focus();
var e = jQuery.Event("keydown");
e.keyCode = 39; //39=Arrow Right
$('.txtLocation').trigger(e);
});
It seems this impacts not only the context-menu Paste, but also that of Edit|Paste from the browser menu bar as well as the iOS paste functionality. I've opened a bug with Google. You may wish to "Star" that bug report to catch updates.
I found a workaround that, while a bit of a hack, seems to fix the problem. If you store the pasted value, switch focus on a different field, set the value in the Autocomplete field, and finally focus back on the Autocomplete field things work more or less as expected. Also, you have to do this in a setTimeout() callback - the delay time doesn't seem to matter at all, but if you just do this inline you won't see the expected results.
Here's a code sample of what I'm describing above:
$("#address_field").on("paste", googleMapsAutocompletePasteBugFix);
googleMapsAutocompletePasteBugFix = function() {
return setTimeout(function() {
var field, val;
field = $("#address_field");
val = field.val();
$("#price").focus();
field.val(val);
return field.focus();
}, 1);
};
The last focus() is optional, but the UI is a little less surprising than if you just skipped automatically to the next field.
Following solution seems to work for me (existence of field ending with "address_2" is assumed). Tested on IE8, IE9, IE10, Chrome, FF and Safari
if document.addEventListener
$(document).on("paste", "[name*=address_1]", #googleMapsAutocompletePasteBugFix)
$(document).on("onpaste", "[name*=address_1]", #googleMapsAutocompletePasteBugFix)
else
for element in $("input[name*=address_1]")
document.getElementById($(element).attr('id')).onpaste = #googleMapsAutocompletePasteBugFix
googleMapsAutocompletePasteBugFix: (e) ->
unless e
e = window.event
if e.srcElement
target = e.srcElement
else
target = e.target
field = $(target)
fieldId = field.attr('id')
focusSwitchFieldId = fieldId.replace(/(\d)$/, '2')
setTimeout(->
if window.chrome || /Safari/.test(navigator.userAgent)
val = field.val()
$("##{focusSwitchFieldId}").focus()
field.val(val)
field.focus()
else
field = document.getElementById(fieldId)
val = field.value
document.getElementById(focusSwitchFieldId).focus()
setTimeout(->
field.value = val
field.focus()
field.focus()
, 50)
, 10)

In JQuery, How can I avoid two $(this) selectors from causing conflict to each other as part of an each() method?

everybody.
I'm sort of newbie in JQuery and I'm trying to do the following: I've got both select and checkbox elements and I want certain changes to occur each time the document is loaded or refreshed. What I mean is, the background of the selects should be different depending on whether an empty option (or prompt) is currently selected or not. Also, depending on the former, an (accompanying) checkbox should be enabled or disabled as well (empty option selected => checkbox disabled OR the other way around).
Now, I won't be inputting any ids (from selects or checkboxes) manually. Instead, I want to get them all dinamically by using an each method on the correct selector. And that's where the problem arises.
So, lets say we've got this:
<select id="select_01">
<option value="">Whatever as prompt...</option>
<option value="first">First option</option>
</select>
<input id="check_box_01" type="checkbox" />
<select id="select_02">
<option value="first" selected="selected">First option</option>
<option value="">Whatever as prompt...</option>
</select>
<input id="check_box_02" type="checkbox" />
and in a script I put this:
$(document).ready(function() {
$("select,:checkbox").each(function() {
mySelectId = $("#" + $(this).attr("id"));
myCheckboxId = $("#" + $(this).attr("id"));
if (mySelectId.attr("value") === "") {
mySelectId.css({
"background": "grey"
});
myCheckboxId.attr("disabled", "disabled");
}
});
});
The problem, as you can see, is the $("select,:checkbox").each method not being able to discern which $(this) represents what (well, that and my own obvious lack of knowledge to solve this problem).
If I leave one of the selectors out, everything works well but (obviously) it only affects selects or checkboxes, but not both. Something like this works (the background changes as it should but checkboxes are left unaffected):
$(document).ready(function() {
$("select").each(function() {
mySelectId = $("#" + $(this).attr("id"));
if (mySelectId.attr("value") === "") {
mySelectId.css({
"background": "grey"
});
}
});
});
¿Can I make mySelectId and myCheckboxId two different, easily recognizable variables within the scope of the method? Any help will be greatly appreciated. Thanks in advance!
Carlos Pardilla.
PD: (I wanted to say "Hi everybody" on top, but the edits keep on cutting the whole greeting - dont' know why)
In your loop, the each() function, you do not get the elements as pairs.
You get them one-by-one.
I would do it in two steps (two loops), one for the selects, one for the checkboxes.
if ( $(this).is("select") ) {
mySelectId = $("#" + $(this).attr("id"));
}else if (( $(this).is(":checkbox") ) {
myCheckboxId = $("#" + $(this).attr("id"));
}
Well, I finally managed to get it working thanks to the both of you:
$(document).ready(function() {
$("select, :checkbox").each(function() {
if ($(this).is("select")) {
mySelectId = $("#" + $(this).attr("id"));
if (mySelectId.attr("value") === "") {
mySelectId.css({
"background": "grey"
});
}
} else if ($(this).is(":checkbox")) {
myCheckboxId = $("#" + $(this).attr("id"));
if (mySelectId.attr("value") === "") {
myCheckboxId.attr("disabled", "disabled");
}
}
});
});
The only thing I do not find myself entirely confortable with is with having to repeat if (mySelectId.attr("value") === "") {, (I try to apply Rails's DRY philosophy when possible), but I'm sure I'll find a workaround.
I find the is() method (wich I wasn't previously too familiar with) to be of much help in situations such as these.
Feel free to tinker with this as you'll please: http://jsfiddle.net/CarlosPF/DsHUp/
Many thanks to you both! Your help has been invaluable.
Carlos Pardilla.