Make div keyboard-scrollable in jQuery Mobile? - css

From what I can tell, although jQuery-Mobile-powered pages can contain divs with overflow set to scroll or auto, and these divs can be scrolled with the one-screen bar or the mouse wheel, they cannot be scrolled using the arrow keys, page-up/page-down, or home/end.
Instead, the official "page" div (with data-role="page") absorbs all this input. Perhaps other divs can't even acquire focus, I'm not sure.
Is there any way around this?
EDIT: JSfiddle of simple example: https://jsfiddle.net/qogz0shx/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js">
</script>
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css"/>
<style>
#outer {
overflow:scroll;
height: 50vh;
width: 50vw;
}
#inner {
height: 500vh;
width: 500vw;
}
</style>
<div data-role="page">
<div id="outer">
<div id="inner"></div>
</div>
</div>
Same example without the external files: https://jsfiddle.net/xr0hjjjc/
<style>
#outer {
overflow:scroll;
height: 50vh;
width: 50vw;
}
#inner {
height: 500vh;
width: 500vw;
}
</style>
<div data-role="page">
<div id="outer">
<div id="inner"></div>
</div>
</div>
In Chrome, if you click on the div in the second example and press the arrow keys, you should see the scroll bars move. If you do the same with the first one, they won't.

You're right, internal <div>s cannot be scrolled using keyboard. My approach to this limitation is simple:
create new handler for up/down/PageUp/PageDown keys
when those keys are pressed, get element under mouse
if the element contains the keyboardScroll class, scroll it accordingly
So, mouse position sets which element has to be scrolled.
Updated JSFiddle (click to focus the "run" quadrant before scrolling)
JavaScript
var currentMousePos = { x: -1, y: -1 };
$(document).on("pageinit", "#page", function(event)
{
$(document).mousemove(function(event)
{
currentMousePos.x = event.pageX;
currentMousePos.y = event.pageY;
});
// keyboard handler
$(document).on("keydown", function(e)
{
// get element under mouse
var element = document.elementFromPoint(currentMousePos.x, currentMousePos.y);
// search for scrollable element in parents
while (!$(element).hasClass("keyboardScroll") && $(element).parents().length !== 0)
element = element.parentElement;
if (!$(element).hasClass("keyboardScroll"))
return; // no scrollable element found
// set scroll "speed"
var delta = 10;
if (e.keyCode === 38) // up
delta *= -1;
else if (e.keyCode === 40) // down
delta *= 1;
else if (e.keyCode === 33) // pageup
delta *= -10;
else if (e.keyCode === 34) // pagedown
delta *= 10;
else
return;
// scroll element
$(element).scrollTop($(element).scrollTop() + delta);
// stop event from propagating to jQuery Mobile handlers
e.preventDefault();
e.stopPropagation();
});
});

On revisiting this with new searches ("focus" is a better keyword here than "scroll"), I discovered a much simpler solution.
Just give the div in question a tabindex attribute, to make it focus-able. Make the value -1 so it won't interfere with the tabindex of anything else. (This means that if the user keeps pressing tab, the div in question will never be focused. Change the index to a positive number if you want it to be focus-able that way).
<div id="outer" tabindex="-1"> </div>
<!-- Containing element with overflow:scroll or whatever -->
and that's it. Once the div is clicked it should override whatever jQuery Mobile does to prohibit focus. New JSFiddle here.

Related

Lay a .png image partially over (on top of) menu

I have an accordion menu that I have tweaked to suit my needs. My last stumbling block is that I have an image (see attached image) of a FedEx Courier that I need to lay on top of the menu and yet still allow users to click through it to activate (access) the accordion menu. The image is a separate image that is set to the desired alpha as created in Photoshop. The file is merely a snapshot of how it would look if it was the way I wanted it.
If this is even possible, what code would I use and exactly where would I place it? If in the CSS file, where does it go and between which lines?
Original full size Image file
You can apply the css:
pointer-events: none;
to the image above the links.
See fiddle https://jsfiddle.net/4zgcrkyz/
pointer-events: none; is a suitable solution if you do not need to care about IE < 11. More info on compatibility here.
Alternatively you can use elementFromPoint() which has compatibility IE > 5.5
The following trick allow you to select under your cover image without using pointer-events: none;
https://jsbin.com/tuhotagize/edit?html,output
Explanation:
At click on cover image.
Hide cover image temporary.
Get mouse coordinates.
Get HTML element under that mouse coordinates (so you know what under the cover).
Trigger click event on that HTML element.
Show cover image again.
Another alternative solution to your problem, which does not include any JS is:
Trim your image in PhotoShop as should appear inside the menu. Use CSS background-image property on it
Use the courier FedEx image only as CSS background-image the body of your page.
You can achieve the same visual effect using only CSS.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
<style>
img {
position: absolute;
top: 0;
left: 0;
opacity: 0.4;
}
a {
display: block;
width: 300px;
height: 20px;
background-color: greenyellow;
}
a:hover {
background-color: #FF0000;
}
</style>
<script>
window.app = {
show: function () {
document.getElementById('cover').style.display = '';
},
hide: function () {
document.getElementById('cover').style.display = 'none';
},
event: null,
start: function () {
document.getElementById('cover').addEventListener('click', function (event) {
this.hide();
this.event = event;
var target = document.elementFromPoint(event.pageX, event.pageY);
this.show();
target.click();
}.bind(this));
var links = document.querySelectorAll('a');
for (var i = 0, len = links.length; i < len; i++) {
links[i].addEventListener('click', function (event) {
alert('click on ' + event.target.id);
}.bind(this));
}
}
};
</script>
</head>
<body onload="window.app.start();">
<img id="cover" src="http://placehold.it/200x200" />
<a id="a1">link</a>
<a id="a2">link</a>
<a id="a3">link</a>
<a id="a4">link</a>
<a id="a4">link</a>
<a id="a6">link</a>
</body>
</html>

infinite scrolling in both ways within div

i'm making a website with 3 div columns that have overflow: scroll. (see screensho there: https://dl.dropboxusercontent.com/u/13769038/Schermafbeelding%202015-05-04%20om%2017.37.40kopie.jpg)
I want to make the image scrolling divs infinite as in: they should loop. The end of the div should be connected with the beginning of the div seamless.
I found this fiddle: http://jsfiddle.net/2L23c/
this is exactly what i want to do, but it wont work in my html. I think it is using the body to scroll and not a individual div, and since my body is height: 100% it will not scroll properly.
any way to make this work? here's the JS from the fiddle:
(function($){
$(document).ready(function(){
var html = $(".what").html();
var what = '<div class="what">'+html+'</div>';
$(window).scrollTop(1);
$(window).scroll(function() {
if ( $(window).scrollTop() >= ($('body').height() - $(window).height()) ) {
$(".what").last().after(what);
if ($(".what").length > 2) {
$(".what").last().prev().remove();
$(window).scrollTop($(window).scrollTop() - $(".what").first().height());
}
}
else if ( $(window).scrollTop() == 0 ) {
$(".what").first().before(what);
$(window).scrollTop($(".what").first().height());
if ($(".what").length > 2) {
$(".what").last().remove();
}
}
});
});
})( jQuery );
html
<div class="what">
<img src="http://1.bp.blogspot.com/_27Ai9FzK4gE/SQzMV9lH2jI/AAAAAAAAAYU/zY9yp_HpCx8/s400/brick_wall.jpg"/>
<img src="http://4.bp.blogspot.com/-5Olo8-EgrZI/TZBqclcfPqI/AAAAAAAAC5c/920EyWecwiU/s640/background_brick_wall.jpg"/>
<img src="http://www.macrobusiness.com.au/wp-content/uploads/2012/12/Brick-Wall-With-Lights-stock4221-large.png"/>
<img src="http://parktownprawn.com/wp-content/uploads/2013/04/brick-stone-wall-grey.jpg"/>
CSS
div.what{
width:400px;
margin: 0 auto;
}
IMG{
max-width:400px;
}
Mathieu

How to make popup slide down from under the header in Jquery Mobile

Right now when i summon a popup it appears over the header and then slides down beneath it. Check out what it looks like now.
I would like the popup to slide down from underneath the header. I've tried setting the z index of the popup lower than the header but it didnt do anything. Apparently you need to explicitly set the positioning of elements to use z index but when I did that it totally messed up the UI.
Here's the relevant code
HTML:
<div data-role="popup" id="alertPopup" class="ui-content" data-shadow="false" data-transition="slidedown" data-dismissible="false" data-corners="false" data-position-to="origin">
<p id="popupText"></p>
</div>
JS:
var horizontal = Math.floor(window.innerWidth/2);
var vertical = 80;
var popupOptions = {
x: horizontal,
y: vertical
};
if (status == google.maps.DirectionsStatus.ZERO_RESULTS) {
$("#popupText").text("No transit options could be found.");//using popups instead of alerts because these will go away by themselves instead of forcing user to tap.
$("#alertPopup").popup("open",popupOptions);
setTimeout(function() {
$("#alertPopup").popup("close");
}, 3000);
}
http://jsfiddle.net/guanzo/gvsqenvf/
I think that using a jQM popup widget will not work for this because jQM creates a transparent overlay that covers the page, then a popup container above the overlay and then it places the popup within the container. So there is no way to have the popup be under the header.
Instead, you could use an absolutely positioned DIV for your popup and use the jQuery slideToggle() method to display it.
Add the notification div to the content:
<div data-role="content" id="content">
<div id="notify" class="ui-body-inherit ui-content">
<p id="notifyText">hello</p>
</div>
I am Content
</div>
Setup the CSS to absolutely position the div and hide it until needed:
#notify {
border-width: 1px;
border-style: solid;
display: none;
position: absolute;
}
#notify p {
margin: 0;
}
In the script, set the text, calculate position and show it with slide toggle (I added a timeout on the show just so the fiddle can finish drawing the page before the notification is shown).
$("#notifyText").text("No transit options could be found.");
var $notify = $("#notify");
var vertical = $(".ui-header").outerHeight() -1; //height of header
var w = $notify.width();
var left = (Math.floor((window.innerWidth - w) / 2));
$notify.css({ left: w + "px", top: vertical + "px"});
setTimeout(function() {
$notify.slideToggle(500); //delay showing for the fiddle
}, 500);
setTimeout(function() {
$notify.slideToggle(500);
}, 5000);
Your updated FIDDLE

fixed position menu with changing background colors

I have inherited a project, and have some questions on how to resolve a particular issue.
There is a fixed left sub-nav, seen below. As the user scrolls, there are 6-10 different "sections" that are stacked vertically. The top section has a background-image (seen below), while the remaining sections alternate between white & various colors, such as:
section 1: background-image
section 2: background-color: white
section 3: background-color: blue
section 4: background-color: white
section 5: background-color: green
... etc
The customer wants the menu items to change colors based on what background each item is over at a given time (so as you scroll, it's changing item by item). As you can see in the image, when I scroll from the header to the first content section, I'm moving to a white background, so my menu is white text on a white background (the 5th menu item is moving into the white background).
The guys that worked on this initially used jquery waypoint to trigger wholesale changes to the menu item color when a particular div scrolled to a certain location. This basically works - but only when the entire section is scrolled to the top of the menu (meaning the menu items are white-on-white until the last menu item is scrolled into the section).
Any thoughts on how to handle this?
[EDIT TO ADD]
I thought I made this pretty clear above. We're already using jquery waypoints. The problem is, waypoint cannot trigger on each menu item (primarily since the menu items are not part of the ancestral tree of the content nodes, which prohibits me from passing in a context to the waypoint handler), unless I create a handler for the section div at each offset of every menu item (which are different for each page). This would result in a crazy amount of waypoint handlers being bound, which I don't think is ideal.
Here is an example of what I'm describing. As you scroll, the menu items change all at once. You can see where this is a problem when you're scrolling down from the header into the first content section. The menu items are white. So is the background of the first content section. So until the waypoint is hit, the menu is effectively hidden. What I am looking to do is change the color of each menu item as it "enters" or "exits" a particular content div. I suppose I could do this on window.scroll, but that seems pretty expensive. Was hoping there's something I'm either missing with waypoints, or a better way to do this.
Alright, so I did solve this by creating an event handler at every offset. Given that I have 6-10 menu items per page (so 6-10 sections), I don't really like a solution where I create 36-100 event handlers, so I'm hopeful somebody has a better one (although I'm starting to doubt it).
SO is telling me I need to post code, so here goes:
HTML
<div class="menu">
<ul>
<li>
<a href='#header'>Header</a>
</li>
<li>
<a href='#getting-started'>Getting Started</a>
</li>
<li>
<a href='#zomglaserguns'>Laser Guns</a>
</li>
<li>
<a href='#pewpew'>Pew Pew</a>
</li>
</ul>
</div>
<div id="header" data-menu-color-down='#fff' data-menu-color-up='#000'>
Some header content
</div>
<div class="content">
<div id="getting-started" data-menu-color-down='#000' data-menu-color-up='#fff'>
some content
</div>
<div id="zomglaserguns" data-menu-color-down='#fff' data-menu-color-up='#000'>
laser guns!
</div>
<div id="pewpew" data-menu-color-down='#000' data-menu-color-up='#fff'>
pew pew!!!!
</div>
</div>
JS:
var myObj = {
menuOffsets: {},
pageSections: [],
init: function() {
myObj.initMenuOffsets();
myObj.initSections();
myObj.initWaypoints();
},
initMenuOffsets: function() {
$('.menu a').each(function() {
var self = $(this),
href = self.attr('href'),
menuItemHeight = self.height();
myObj.menuOffsets[href.substring(1, href.length)] = self.offset().top + self.height();
});
console.log(myObj.menuOffsets);
},
initSections: function() {
var header = $('#header'),
sections = $('.content > div');
if(header.length) {
myObj.pageSections.push('header');
}
sections.each(function() {
var self = $(this);
myObj.pageSections.push(self.attr('id'));
});
console.log(myObj.pageSections);
},
initWaypoints: function() {
var menuItemColor,
key,
i = 0,
len = myObj.pageSections.length;
for ( i; i < len; i++ ) {
for ( key in myObj.menuOffsets ) {
if( myObj.menuOffsets.hasOwnProperty( key ) ) {
(function ( key, i ) {
$('#' + myObj.pageSections[i]).waypoint(function(direction) {
var self = $(this);
menuItemColor = self.data('menuColor' + (direction === 'up' ? 'Up' : 'Down'));
$('.menu a[href="#' + key + '"]').css('color', menuItemColor);
}, { offset: myObj.menuOffsets[key] });
})(key, i);
}
}
}
}
};
myObj.init();
SEE-ESS-ESS:
.menu {
position: fixed;
top: 40px;
left: 10px;
color: white;
}
.menu li {
list-style-type: none;
}
.menu a {
color: inherit;
text-decoration: none;
}
.content {
}
#header {
background: black;
color: white;
height: 200px;
padding: 0 120px;
}
#zomglaserguns {
background: green;
color: #777;
}
.content div {
min-height: 300px;
padding: 0 120px;
}
Well, it's not too difficult to set up some ID's on the page, and use those as anchors for when to trigger the background change.
Say you had an HTML structure like this:
<header>
...
</header>
<div id="getting-started" data-background-color="lightBlue">
...
</div>
<div id="afford" data-background-color="red">
...
</div>
<div id="down-payment" data-background-color="green">
...
</div>
<div id="financing" data-background-color="blue">
...
</div>
And now you include jQuery Waypoints
<script type="text/javascript">
(function($) {
$('#getting-started').waypoint(function() {
var $this = $(this);
$('header').css('background-color', $this.data('background-color'));
});
})(jQuery)
</script>
Keep in mind this isn't a complete solution, just something to help poke you in the right direction.

jQueryUI slider: absolutely positioned element & parent container height

I have an example on http://jsfiddle.net/SsYwH/
In case it don't work
HTML:
<div class="container">
<div class="absolute">
Testing absolute<br />
Even more testing absolute<br />
</div>
A little test<br />
</div>
CSS:
.container {
background: green;
}
.absolute {
position: absolute;
background: red;
}
Problem
I use jQuery to create a slider-effect. To do that I need to set position absolute.
The red block in my code is the position absolute slider.
The green block is the container.
I still want the container to be set by it's childs height. Now it don't know it because of the position absolute. Solution?
Absolutely positioned elements do not count towards the container's contents in terms of flow and sizing. Once you position something absolutely, it will be as if it didn't exist as far as the container's concerned, so there's no way for the container to "get information" from the child through CSS.
If you must allow for your scroller to have a height determined by its child elements without Javascript, your only choice may be to use relative positioning.
Then you'll also need to use jQuery to fix the height of the container div. Like so:
http://jsfiddle.net/khalifah/SsYwH/24/
$( document ).ready(function() {
$( ".container" ).each(function() {
var newHeight = 0, $this = $( this );
$.each( $this.children(), function() {
newHeight += $( this ).height();
});
$this.height( newHeight );
});
});
This is wrong however, since an absolute positioned element can sit outside of it's container. What you really what is something that will find the bottom of the element that sits lowest in the containing div, with respect to the view.
jQuery('.container > .absolute').each(function() {
jQuery(this).parent().height('+=' + jQuery(this).height());
jQuery(this).css('position', 'absolute');
});
.container {
background: green;
position: relative;
}
.absolute {
position: absolute;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="absolute">Testing absolute<br />Even more testing absolute<br /></div>
Yo
</div>
This should do what you are wanting. Note that this assumes that the absolutely positioned element must be an immediate child.
Also note that you remove the '+=' + in the height function if you want the parent element to have 100% height of it's child element.
http://jsfiddle.net/SsYwH/21/
You can do something like this with jquery. Call ghoape(jqueryElement).
var ghoape = function getHeightOfAbsolutelyPositionedElement( element ){
var max_y = 0;
$.each( $(element).find('*'), function(idx, desc){
max_y = Math.max(max_y, $(desc).offset().top + $(desc).height() );
});
return max_y - $(element).offset().top;
}
This will go through all the descendants and find the max height and return the difference between the childs.offset() + its height and then subtract that from the elements offset.

Resources