Maintain Scroll Position When Panel Swipes Open - jquery-mobile

I have a page with a side panel that swipes open. I would like the scroll position to remain in the same place, when this panel is swiped open. Currently, it snaps to the top. My below code is not working. Any advice?
var storePosition = {
topCoordinate : null
}
$(document).ready(function(){
/////////////////////// JQUERY MOBILE SWIPING (Scroll position) //////////////////////
$( "#B" ).panel({
beforeopen: function( event ) {
storePosition.topCoordinate = $(this).offset().top;
$( "body [data-role=page]" ).css("position","fixed");
}
});
$( "#B" ).panel({
beforeclose: function( event ) {
$( "body [data-role=page]" ).css("position","");
if($.mobile.activePage.attr("id") == "page" && storePosition.topCoordinate !== 0){
$('html, body').animate({
scrollTop: $("#A").position().top += storePosition.topCoordinate - 60}, 10);
}
}
});
////////////////////// SIDE PANEL //////////////////////
$('#open').click(function(){
if($('#B').width() > 0){
$('#B').animate({width: '0px'}),
$( ".container" ).removeClass( "no-scroll" ).animate({right: '200px'});
}
else{
$('#B').animate({width: '200px'}),
$( ".container" ).addClass( "no-scroll" ).animate({right: '200px'});
}
});
$('#close').click(function(){
$('#B').animate({width:"0px"}),
$( ".container" ).removeClass( "no-scroll" ).animate({right: '0px'});
});
$("body").on("swipeleft",function(){
$('#B').animate({width:"200px"}),
$( ".container" ).addClass( "no-scroll" ).animate({right: '200px'});
});
$("#B").on("swiperight",function(){
$(this).animate({width:"0px"}),
$( ".container" ).removeClass( "no-scroll" ).animate({right: '0px'});
});
Here's the fiddle.
Note: The function of the panel is to push the content of the page to the left, when opened. It should be scrollable, but the content of the page should not be. This panel can also be opened/closed with a toggle button on the page.

It turns out, the answer was pretty simple.
Adding height:100vh to the wrapper is what made the page jump, upon opening the panel. I added that to prevent to content from being scrollable. But, I discovered that if I put overflow:hidden on the body instead of the wrapper, it would prevent scrolling. So, I could eliminate height:100vh and all that "scroll position" jargon all together.
Here is the fix.
/////////////////////// SEARCH TOGGLE //////////////////////
$('#open').click(function(){
if($('#B').width() > 0){
$('#B').animate({width: '0px'}),
$( ".container" ).animate({right: '200px'});
$( "body" ).removeClass( "no-scroll" );
}
else{
$('#B').animate({width: '200px'}),
$( ".container" ).animate({right: '200px'});
$( "body" ).addClass( "no-scroll" );
}
});
$('#close').click(function(){
$('#B').animate({width:"0px"}),
$( ".container" ).animate({right: '0px'});
$( "body" ).removeClass( "no-scroll" );
});
$("body").on("swipeleft",function(){
$('#B').animate({width:"200px"}),
$( ".container" ).animate({right: '200px'});
$( "body" ).addClass( "no-scroll" );
});
$("#B").on("swiperight",function(){
$(this).animate({width:"0px"}),
$( ".container" ).animate({right: '0px'});
$( "body" ).removeClass( "no-scroll" );
});

Related

Remove initial selection of Select2

I am working with Select2 and jQuery UI Tooltip. I made a jsfiddle in this regard. I am describing issue below.
$( function() {
$(document).ready(function () {
$('.js-example-basic-single').select2();
$( document ).tooltip({
position: {
my: "center bottom-20",
at: "center top",
using: function( position, feedback ) {
$( this ).css( position );
$( "<div>" )
.addClass( "arrow" )
.addClass( feedback.vertical )
.addClass( feedback.horizontal )
.appendTo( this );
}
}
});
});
});
If I click on dropdwon of Select2, the drop down opens with first value selected. I would like to remove this initial selection.

jquery-UI Drag + clone div inside other div and make it sortable

I'm trying to create a situation where it is possible to drag and clone a div inside another div multiple times, this div in the specific container has tot be sortable with the other ones.
$(function() {
$( ".drag" ).each(function(){
$(this).draggable({
helper: "clone"
});
});
$( ".day " ).droppable({
drop: function( event, ui ) {
var targetElem = $(this).attr("id");
$( this ).addClass( "" );
if($(ui.draggable).hasClass('draggable-source'))
$( ui.draggable ).clone().appendTo( this ).removeClass('draggable-source');
else
$( ui.draggable ).appendTo( this );
console.log(this.id)
}
}).sortable({
items: "div",
sort: function() {
$( this ).removeClass( "ui-state-default" );
}
});
});
This is working in this fiddle:
http://jsfiddle.net/mfUCe/
This is where i got stuck:
I want to be able to drag the 2 divs in to the divs that are already inside of the droppable containers.
it would be great if anybody could help me

How to use tilesloaded event for google maps v3

Here I have a code:
<script>
$(function() {
$( "#photo" ).resizable();
$( "#photo" ).draggable({revert: 'invalid'});
$( "#left" ).droppable({
accept: '#photo',
drop: function( event, ui ) {
$( this )
.find( "p" )
.html( "Dropped!" );
}
});
});
</script>
and this code I must run after full loading google maps, so I need to "hook up" tilesloaded event for this code.
http://jsbin.com/ayugun/7/edit
But how to do that?
Here is the code
google.maps.event.addListener(map, 'tilesloaded', function() {
doWhatYouWant();
});

jQuery UI Multiple Droppable - drag whole div element & clone

I've just started using jQuery UI to drag divs into a columns in a table. I have a couple different draggable divs with different background-colors and text inside them, and I need them to be able to dragged up to the drop area as a clone. This worked fine by using jQuery UI's example shopping cart code, but I've edited it so the whole object is dragged instead of just the text, but this then eliminates the clone functionality for some reason, even though I have helper:clone.
Here is my code:
<script>
$(function() {
$( "ul li" ).draggable({
appendTo: "body",
helper: "clone"});
$( ".day #drag" ).draggable({
appendTo: "body"});
$( ".day" ).droppable({
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
accept: ":not(.ui-sortable-helper)",
drop: function( event, ui ) {
var targetElem = $(this).attr("id");
$( this ).addClass( "ui-state-highlight" );
$( ui.draggable ).appendTo( this );
}
}).sortable({
items: "li:not(.placeholder)",
sort: function() {
$( this ).removeClass( "ui-state-default" );
}
});
});
</script>
Example column:
<td>
<div id="monday" class="day monday ui-widget-content"></div>
</td>
Draggable element:
<li><div style="background-color:#<?=$bgColor?>;color:<?=$textColor?>;" id="drag" class="<?=$subject?>"><?=$row['name']?></div></li>
It's essentially a timetable setup tool. Thank you for the help
Here is a jsFiddle for reference: http://jsfiddle.net/x5T4h/
Not sure that it is exactly what you want, but here is a good start for your : http://jsfiddle.net/x5T4h/2/
Basically, I removed the second draggable object declaration, and I added clone function to duplicate your element inside drop event $( ui.draggable ).clone().appendTo( this );
$(function() {
$( "ul li" ).each(function(){
$(this).draggable({
helper: "clone"
});
});
$( ".day" ).droppable({
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
accept: ":not(.ui-sortable-helper)",
drop: function( event, ui ) {
var targetElem = $(this).attr("id");
$( ui.draggable ).clone().appendTo( this );
}
}).sortable({
items: "li:not(.placeholder)",
sort: function() {
$( this ).removeClass( "ui-state-default" );
}
});
});​

jQueryUI droppable, stop propagation to overlapped sibling

As you can see here: http://jsfiddle.net/rA4CB/6/
When I make the drop in the overlapped area it is received in both droppables, greedy doesn't work when the items are siblings. Is there any way to block the reception on droppables lower in the zIndex?
BTW, mouseOver won't fire for the droppable element as the mouse is actually over the draggable element.
relevant JS:
$(function() {
$( "#draggable" ).draggable();
$( "#droppable" ).droppable({
tolerance:'pointer',
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
}
});
$( "#droppable2" ).droppable({
tolerance:'pointer',
greedy:true,
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
}
});
});
Okay, so I spend an hour trying to figure it out, then as soon as I ask I then find my answer
http://jsfiddle.net/rA4CB/7/
Modified the JS to the following:
$(function() {
$( "#draggable" ).draggable();
$( "#droppable" ).droppable({
tolerance:'pointer',
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
}
});
$( "#droppable2" ).droppable({
tolerance:'pointer',
greedy:true,
drop: function( event, ui ) {
$( this )
.addClass( "ui-state-highlight" )
.find( "p" )
.html( "Dropped!" );
},
over: function(event, ui){
$( "#droppable" ).droppable( "disable" )
},
out: function(event, ui){
$( "#droppable" ).droppable( "enable" )
}
});
});
$( "#droppable" ).droppable({
greedy: true,
drop: function( event, ui ) {
if(ui.helper.is(".dropped")) {
return false;
}
ui.helper.addClass(".dropped");
}
});
Just set a css class on ui.helper of draggable. If the draggable has been accepted once, it will be refused by all other droppables (Could be done with the droppable "accept" parameter,too , like accept : ":not(.dropped)" and the class added to ui.draggable).
If you have a number of droppable in a container area then what????
You must re think for that problem. Greedy works for only parent to child relationship not in siblings. So you must edit droppable js or put your own logic for it.
So if you have a numbers of droppable then you must write some extra code to handle dropping on perfect droppable as it is in this example A number of siblings droppables
For making perfect siblings droppable modify your droppbale as below
var topElement = undefined;
var topElementArray = Array();
$( "#draggable" ).draggable();
$( ".droppableBox" ).droppable({
activeClass: "active-droppable",
tolerance:'pointer',
over: function( event, ui ) {
// This is for only show a message that z-index must be required for proppable
// you can remove it after testing or after development
if ($(this).css("z-index") == 'auto') {
alert("Please provide z-index for every droppable.");
return;
}
//
topElement = undefined;
topElementArray = Array();
// Change it as you want to write in your code
// For Container id or for your specific class for droppable or for both
$('#demo > .droppableBox').each(function(){
_left = $(this).offset().left, _right = $(this).offset().left + $(this).width();
_top = $(this).offset().top, _bottom = $(this).offset().top + $(this).height();
if (event.pageX >= _left && event.pageX <= _right && event.pageY >= _top && event.pageY <= _bottom) {
topElementArray.push($(this).attr('id'));
}
});
},
drop: function( event, ui ) {
if (!topElement) {
topElement = determineTopElement(topElementArray);
}
if ($(this).attr('id') == $(topElement).attr('id')) {
$( this ).addClass( "ui-state-highlight" ).find( "p" ).html( "Dropped!" );
// Your code after successful dropped element on specific siblings
// Start writing code for dropped element & perfect droppable
}
}
});
determineTopElement = function(_array) {
var topElement;
var zIndexHighest = 0;
for (i = 0; i < _array.length; i++){
var element = $("#"+ _array[i]);
var z_index = $(element).css("z-index");
if( z_index > zIndexHighest){
zIndexHighest = z_index;
topElement = element;
}
}
return topElement;
}
In certain circonstances :
myjQuery.droppable({
over:function(evt,ui){
ui.draggable.attr('drg_time', this.drg_time = evt.timeStamp)
},
accept:function(draggeds){
if(draggeds.attr('drg_time'))
{
return draggeds.attr('drg_time') == this.drg_time
}
return draggeds.hasClass('acceptable_classes_here')
},
out:function(evt,ui){
// useless but cleaner
ui.draggable.removeAttr('drg_time')
}
drop:...,
})
I had the same problem and made a small plugin :)
check it out:
https://stackoverflow.com/a/16720944/1308461
I find that using #invertedSpear's method will cause UI state change which is not desirable in some cases. Here is the code.
var lastOpertion = new Date().getTime();
drop: function (event, ui) {
if (new Date().getTime() - lastOpertion < 100) return;
lastOpertion = new Date().getTime();
....
}
So, when trying to find simple solution I came up with this (and it works for me):
window.overNowOnThis = "";
window.olderOnes = [];
$obj.droppable({
accept: ".draggable_imgs",
drop: function(e, ui) {
if(window.overNowOnThis == this){
// Do whatever
}
},
over: function(event, ui){
window.olderOnes.push(window.overNowOnThis);
window.overNowOnThis = this;
},
out: function(){
var lastElem = window.olderOnes.pop();
window.overNowOnThis = lastElem;
}
});
Top element would be selected because on it "over" fires the last one. Also - if there is more than two siblings - then when moving out of element we set the last one as current. Using global "window" was for example. Better option would be using classes as it can safely keep data.
It's very similar to invertedSpear answer. I had to change it a little bit because enabling/disabling inside "over"/"out" didn't work for me .I had to do below instead
$("#droppable2").droppable({
greedy: true,
drop: function (event, ui) {
$("droppable").droppable("disable");
}
}
I had to explicitly enable"droppable" div when I needed it. For instance, enable it when starting the drag event. Eg
$("#drageMe").draggable({
start:function(event,ui){
$("droppable").droppable("enable");
}
})
try greedy option in ui dropable. see the fiddle link below for demo:
http://jsfiddle.net/creators_guru/3vT5C/embedded/result/
$( ".circles" ).droppable({
greedy: true,
drop: function( event, ui ) {
$_data = ('drgged class = ' + ui.draggable.attr('class'));
$_data1 = ('droped id = #' + $(this).attr('id'));
$('#data').html($_data + '<br/>'+$_data1);
return false;
}
});

Resources