Gmail like listview item removing - jquerymobile - jquery-ui

I'm building a phonegap mobile app with jqm 1.3.
I have a listview element, each list item have 2 actions, rename when swipe right, and delete when swipe left. What I want to achieve is a behavior like in gmail mobile application. When some list item is dragged aside (more than some threshold), another "layer" is shown with related buttons. currently I'm using code from jquery mobile swipe list demo, with popup on swipe event, but it is not fulfill my needs.
How this stuff can be implemented ?
Is there any plugin to achieve that functionality?

I tried to make something like this. The working demo is here - http://jsfiddle.net/Q9htn/19/
First HTML:
<ul id="list" data-role="listview"></ul>
Then some CSS. I am not very happy with having to define row height this way and I am sure there must be better ways how to do this fully dynamically, but hopefully it should be OK for this purpose. It makes sure that the row stays as it is during the animations which happen.
.row {
height: 1em;
}
.item {
position: absolute;
display: inline-block;
width: 100%;
right: -1em; /* This makes the item to fly out to the right */
}
.menu {
width: 100%;
display: inline-block;
text-align: center;
}
JavaScript:
var items = ["Audi", "Mercedes", "Skoda", "Rover", "Nisan", "Mazda", "Toyota"];
$.each(items, function(index, item) {
var li = $("<li class='row'>");
var contents = $("<span class='item'>" + item + "</span>");
contents.attr("data-customid", index); // Set some id
li.append(contents);
$("#list").append(li);
});
$("#list").listview("refresh");
// Attach swiperight handler on the list
$("#list").on("swiperight",">li",function(e){
var li = $(this);
var contents = $(li.children()[0]);
var item = contents.text(); // Get the item value
var itemId = contents.attr("data-customid");
var delButton = $("<a>").text("Yes").click(function(e){
// Delete handler, fade out menu and remove the row
menu.fadeOut(function(){
li.remove();
alert("Deleted " + item + " with ID = " + itemId);
});
});
var cancelButton = $("<a>").text("No").click(function(e){
// Cancel Handler, remove menu and show the item
menu.fadeOut(function(){
contents.animate({width: 'toggle'}, function(){
menu.remove();
});
});
});
// Create the menu
var menu = $("<span />").append("Sure? - ").append(delButton).append(" | ").append(cancelButton)
.css("display", "none")
.addClass("menu");
// Insert the menu
contents.after(menu);
// Slide the item
contents.animate({width: 'toggle'}, function(){
// And fade in the menu
menu.fadeIn();
});
});

Related

Openlayers 3 popover putting each word on one line

Working on an OL3 map, and am getting stuck on popover style. I haven't added any CSS to change it at all and it is currently being handled by default Bootstrap settings.
Okay so the problem: each word is being displayed on it's own line. How can I change this? Or, a better question, how do I control the style of the popovers?
This is was it looks like now: http://i.imgur.com/lrLYbag.png
The code handling popups:
//popups
var element = document.getElementById('popup');
var popup = new ol.Overlay({
element: element,
positioning: 'bottom-center',
stopEvent: false
});
map.addOverlay(popup);
// display popup on hover
map.on('pointermove', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
if (feature) {
var geometry = feature.getGeometry();
var coord = geometry.getCoordinates();
popup.setPosition(coord);
$(element).popover({
'placement': 'top',
'html': true,
'content': feature.get('name')
});
$(element).popover('show');
} else {
$(element).popover('destroy');
}
});
Thanks!
I think you just need to add some css to the #popup element you're using for the popup.
Something like:
#popup {
min-width: 280px;
}
Take a look at this example http://openlayers.org/en/master/examples/popup.html for styling ideas.

How to change jquery ui datepicker position?

Is it possible to change top and left positions (get current values and change them) of jQuery UI datepicker. Please note that i need to change position, not set margin as it is in other examples.
Sure it is. As there's always only one datepicker active, you can select active datepicker with:
var $datepicker = $('#ui-datepicker-div');
and change its position:
$datepicker.css({
top: 10,
left: 10
});
EDIT
Whoah, tricky one. If you set top or left position in beforeShow, it gets overriden again by datepicker plugin. You have to put css changes in a setTimeout:
$("#datepicker").datepicker({
beforeShow: function (input, inst) {
setTimeout(function () {
inst.dpDiv.css({
top: 100,
left: 200
});
}, 0);
}
});
DEMO: http://jsfiddle.net/BWfwf/4/
Explanation about setTimeout(function () {}, 0): Why is setTimeout(fn, 0) sometimes useful?
If you get really stuck you can edit your jquery-ui-[version].custom.js. The function that controls the position where the calender will appear is:
_findPos: function(obj) {
var position,
inst = this._getInst(obj),
isRTL = this._get(inst, "isRTL");
while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
obj = obj[isRTL ? "previousSibling" : "nextSibling"];
}
position = $(obj).offset();
return [position.left, position.top];
},
I have some custom code that uses a CSS3 transformation to zoom the page in or out based on its width. This throws out the screen coordinates that the calendar widget relies on. I added some custom code to the _findPos to detect and handle the zoom level. Modified code looks like this:
_findPos: function(obj) {
var position,
inst = this._getInst(obj),
isRTL = this._get(inst, "isRTL");
while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
obj = obj[isRTL ? "previousSibling" : "nextSibling"];
}
position = $(obj).offset();
/* Custom Code for Zoom */
var zoomLevel = 1;
var minW = 1024;
if ($(window).width() > minW)
{ zoomLevel = $(window).width() / minW;}
return [position.left, position.top/zoomLevel];
},
May be an old question, but ran into the problem myself just today and could not get other suggestions to work. Fixed it alternatively (using .click(function(){}) and wanted to add my two cents.
I have an input field with the id sDate which, when clicked, displays the datepicker.
What I did to solve the problem was add a click routine to the #sDate field.
$('#sDate').click(function(){ //CHANGE sDate TO THE ID OF YOUR INPUT FIELD
var pTop = '10px'; //CHANGE TO WHATEVER VALUE YOU WANT FOR TOP POSITIONING
var pLeft = '10px'; //CHANGE TO WHATEVER VALUE YOU WANT FOR LEFT POSITIONING
$('#ui-datepicker-div').css({'left':pLeft, 'top':pTop});
});
your solution works provided you run it after calling the datepicker in the code, I tried calling it before but it didn't work, so I tried to understand how it worked for you.
I have adapted the datepicker in the context of an input field which is fixed at the top of the page to scroll. The datepicker was lost ...
Here is my example code for adaptation in a context of datepicker which becomes dynamically fixed:
Example found on w3schools.com: https://www.w3schools.com/howto/howto_js_sticky_header.asp
HTML:
<div class="padding-16 center" id="resa_nav">
<div style="margin: 24px 0 0;">
<label for="date_selector"
class="text-gray">Choose a date</label>
<input type="text" id="date_selector" name="date_selector" class="padding-small">
</div>
</div>
CSS:
.sticky {
position: fixed;
top: 0;
width: inherit;
background: white;
box-shadow: 0px 0px 7px 4px #69696969;
}
JS:
// init datepicker
$('#date_selector').datepicker();
// When the user scrolls the page, execute myFunction
window.onscroll = function() { myFunction() };
// Get the header
var header = document.getElementById('resa_nav');
// Get the offset position of the navbar
var sticky = header.offsetTop;
// Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
function myFunction() {
if (window.pageYOffset > sticky) {
// set block sticky
header.classList.add('sticky');
// adjust datepicker position
// attach a namespace for unbind click later in "non-sticky" context
$('#date_selector').on('click.sticked', function(){
var top = '10px';
var left = '10px';
$('#ui-datepicker-div').css({'left': left, 'top': top});
});
}
else {
// remove sticky
header.classList.remove('sticky');
// unbind the second event 'click' for retrieve the
// default of settings in "non-sticky" context
$('#date_selector').off('click.sticked');
}
}
// END FUNCTION
hope to help!
just add css as below for datepicker
.datepicker {
top: -150px;
/* adjust value as per requirement. if not work try with addin !important*/
}

How do I stop my fixed navigation from moving like this when the virtual keyboard opens in Mobile Safari?

I understand that mobile safari has a lot of bugs around fixed elements, but for the most part I've managed to get my layout working correctly until I added a much needed text input to the fixed navigation at the bottom. Now when the user focuses on the text input element and the virtual keyboard appears, my navigation, which is otherwise always fixed at the bottom of the page, jumps up to a really strange spot in the middle of the page.
I'd add some of my code to this post, but I wouldn't be sure where to start. That navigation is fixed at the bottom and positioned to the left and bottom 0, and 100% width. From there, I don't know what's going on, I can only assume it's a mobile safari bug.
It also appears to lose it's position fixed and become relative, only while the text input element is focused on and the virtual keyboard is open.
http://dansajin.com/2012/12/07/fix-position-fixed/ this is one of the solutions proposed. Seems worth a shot.
In short: set fixed elements to position:absolute when any input is focused and reset them when that element is blurred
.header {
position: fixed;
}
.footer {
position: fixed;
}
.fixfixed .header,
.fixfixed .footer {
position: absolute;
}
and
if ('ontouchstart' in window) {
/* cache dom references */
var $body = $('body');
/* bind events */
$(document)
.on('focus', 'input', function() {
$body.addClass('fixfixed');
})
.on('blur', 'input', function() {
$body.removeClass('fixfixed');
});
}
The solutions on the top are some ways to go and fix the problem, but I think adding extra css class or using moderniz we are complicating things.If you want a more simple solution, here is a non-modernizr non-extra-css but pure jquery solution and work on every device and browsers I use this fix on all my projects
if ('ontouchstart' in window) {
$(document).on('focus', 'textarea,input,select', function() {
$('.navbar.navbar-fixed-top').css('position', 'absolute');
}).on('blur', 'textarea,input,select', function() {
$('.navbar.navbar-fixed-top').css('position', '');
});
}
I had a similar problem, but I found a workaround by adding the following css class to the body element on input focus and then removing it again on unfocus:
.u-oh {
overflow: hidden;
height: 100%;
width: 100%;
position: fixed;
}
Taking from what sylowgreen did, the key is to fix the body on entering the input. Thus:
$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});
$("#myInput").on("blur", function () {
$("body").css("position", "static");
});
Add javascript like this:
$(function() {
var $body;
if ('ontouchstart' in window) {
$body = $("body");
document.addEventListener('focusin', function() {
return $body.addClass("fixfixed");
});
return document.addEventListener('focusout', function() {
$body.removeClass("fixfixed");
return setTimeout(function() {
return $(window).scrollLeft(0);
}, 20);
});
}
});
and add class like this:
.fixfixed header{
position: absolute;
}
you can reference this article: http://dansajin.com/2012/12/07/fix-position-fixed/
I really like the solution above. I packaged it up into a little jQuery plugin so I could:
Set which parent gets the class
Set which elements this applies to (don't forget "textarea" and "select").
Set what the parent class name is
Allow it to be chained
Allow it to be used multiple times
Code example:
$.fn.mobileFix = function (options) {
var $parent = $(this),
$fixedElements = $(options.fixedElements);
$(document)
.on('focus', options.inputElements, function(e) {
$parent.addClass(options.addClass);
})
.on('blur', options.inputElements, function(e) {
$parent.removeClass(options.addClass);
// Fix for some scenarios where you need to start scrolling
setTimeout(function() {
$(document).scrollTop($(document).scrollTop())
}, 1);
});
return this; // Allowing chaining
};
// Only on touch devices
if (Modernizr.touch) {
$("body").mobileFix({ // Pass parent to apply to
inputElements: "input,textarea,select", // Pass activation child elements
addClass: "fixfixed" // Pass class name
});
}
I use this jQuery script:
var focus = 0;
var yourInput = $(".yourInputClass");
yourInput.focusin(function(){
if(!focus) {
yourInput.blur();
$("html, body").scrollTop($(document).height());
focus = 1;
}
if(focus) {
yourInput.focus();
focus = 0;
}
});
Works perfectly for me.
The focusin and focusout events seem to be better suited to this problem than the focus and blur events since the former bubble up to the root element. See this answer on SO.
Personally I use AngularJS, so I implemented it like this:
$window.document.body.addEventListener('focusin', function(event) {
var element = event.target;
var tagName = element.tagName.toLowerCase();
if(!$rootScope.inputOverlay && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {
$rootScope.$apply(function() {
$rootScope.inputOverlay = true;
});
}
});
$window.document.body.addEventListener('focusout', function() {
if($rootScope.inputOverlay) {
$rootScope.$apply(function() {
$rootScope.inputOverlay = false;
});
}
});
Note: I am conditionally running this script if this is mobile Safari.
I put an ng-class attribute on my navbar:
<div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">
using the following CSS:
.navbar-absolute {
position: absolute !important;
}
You can read more about focusin here and focusout here.
Test this one. It works. I just test it.
$(document).on('focus','input', function() {
setTimeout(function() {
$('#footer1').css('position', 'absolute');
$('#header1').css('position', 'absolute');
}, 0);
});
$(document).on('blur','input', function() {
setTimeout(function() {
$('#footer1').css('position', 'fixed');
$('#header1').css('position', 'fixed');
}, 800);
});
None of these solutions worked for me because my DOM is complicated and I have dynamic infinite scroll pages, so I had to create my own.
Background: I am using a fixed header and an element further down that sticks below it once the user scrolls that far down. This element has a search input field. In addition, I have dynamic pages added during forward and backwards scroll.
Problem: In iOS, anytime the user clicked on the input in the fixed element, the browser would scroll all the way to the top of the page. This not only caused undesired behavior, it also triggered my dynamic page add at the top of the page.
Expected Solution: No scroll in iOS (none at all) when the user clicks on the input in the sticky element.
Solution:
/*Returns a function, that, as long as it continues to be invoked, will not
be triggered. The function will be called after it stops being called for
N milliseconds. If `immediate` is passed, trigger the function on the
leading edge, instead of the trailing.*/
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function is_iOS() {
var iDevices = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
];
while (iDevices.length) {
if (navigator.platform === iDevices.pop()) { return true; }
}
return false;
}
$(document).on("scrollstop", debounce(function () {
//console.log("Stopped scrolling!");
if (is_iOS()) {
var yScrollPos = $(document).scrollTop();
if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
$('#searchBarDiv').css('position', 'absolute');
$('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header
}
else {
$('#searchBarDiv').css('position', 'inherit');
}
}
},250,true));
$(document).on("scrollstart", debounce(function () {
//console.log("Started scrolling!");
if (is_iOS()) {
var yScrollPos = $(document).scrollTop();
if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
$('#searchBarDiv').css('position', 'fixed');
$('#searchBarDiv').css('width', '100%');
$('#searchBarDiv').css('top', '50px'); //50 for fixed header
}
}
},250,true));
Requirements: JQuery mobile is required for the startsroll and stopscroll functions to work.
Debounce is included to smooth out any lag created by the sticky element.
Tested in iOS10.
I wasn't having any luck with the solution proposed by Dan Sajin. Perhaps the bug has changed since he wrote that blog post, but on iOS 7.1, the bug will always surface when the position is changed back to fixed after the input is blurred, even if you delay until the software keyboard is hidden completely. The solution I came to involves waiting for a touchstart event rather than the blur event since the fixed element always snaps back into proper position when the page is scrolled.
if (Modernizr.touch) {
var $el, focused;
$el = $('body');
focused = false;
$(document).on('focus', 'input, textarea, select', function() {
focused = true;
$el.addClass('u-fixedFix');
}).on('touchstart', 'input, textarea, select', function() {
// always execute this function after the `focus` handler:
setTimeout(function() {
if (focused) {
return $el.removeClass('u-fixedFix');
}
}, 1);
});
}
HTH

How to create two footer rows in jqgrid

I am working on jqgrid with ASP.NET WEB API.
I want to add two rows in the footer of jqgrid.
So a little search on the net brought me to this link (2010) which says "It is not possible", I am thinking as the answer is of 2010, may be by now some thing / some workaround may have been made possible for this.
What do I want to show in footer ?
I want to show two rows
Total for data preset in current page
Grand total for data present in all of the pages
I am able to pass the data and read the data, the question is how to use this data and create two footer rows in jqgrid.
Any thoughts ?
I found the question interesting, so I created the demo which demonstrates one from the possible implementation of two-rows footer:
The main idea is to add the second row in the table where the standard footer already exist. To eliminate possible problems with other parts of jqGrid code I replaced footrow class name in the custom row to myfootrow. To have the same CSS settings for the second footer as the original tooter has I included the copy of .ui-jqgrid tr.footrow td from ui.jqgrid.css with the same definitions for .ui-jqgrid tr.myfootrow td:
.ui-jqgrid tr.myfootrow td {
font-weight: bold;
overflow: hidden;
white-space:nowrap;
height: 21px;
padding: 0 2px 0 2px;
border-top-width: 1px;
border-top-color: inherit;
border-top-style: solid;
}
The full code you will find below
footerrow: true,
loadComplete: function () {
var $this = $(this),
sum = $this.jqGrid("getCol", "amount", false, "sum"),
$footerRow = $(this.grid.sDiv).find("tr.footrow"),
localData = $this.jqGrid("getGridParam", "data"),
totalRows = localData.length,
totalSum = 0,
$newFooterRow,
i;
$newFooterRow = $(this.grid.sDiv).find("tr.myfootrow");
if ($newFooterRow.length === 0) {
// add second row of the footer if it's not exist
$newFooterRow = $footerRow.clone();
$newFooterRow.removeClass("footrow")
.addClass("myfootrow ui-widget-content");
$newFooterRow.children("td").each(function () {
this.style.width = ""; // remove width from inline CSS
});
$newFooterRow.insertAfter($footerRow);
}
$this.jqGrid("footerData", "set", {invdate: "Total (page):", amount: sum});
// calculate the value for the second footer row
for (i = 0; i < totalRows; i++) {
totalSum += parseInt(localData[i].amount, 10);
}
$newFooterRow.find(">td[aria-describedby=" + this.id + "_invdate]")
.text("Grand Total:");
$newFooterRow.find(">td[aria-describedby=" + this.id + "_amount]")
.text($.fmatter.util.NumberFormat(totalSum, $.jgrid.formatter.number));
}
In the code I set additional information in columns invdate and amount of the footer.

jQuery UI draggable element always on top

I need to have elements that are dragged from left-hand side area to be always on top. And they are when I first drag them from left area, however if I drop them into Box 2 and then decide to drag to Box 1, the item I drag appears below Box 1.
Confused? Here's DEMO of what I'm talking about.
Yes, I have added zIndex -- did not help.
Looks like you are doing some editing. :)
The solution is set the two boxes to the same z-index, and then lower the z-index of the sibling (the box the card is NOT over) using the "start" event. The "stop" event should set them equal again. Of course the draggable itself needs a higher z-index.
You can also try the stack option.
EDIT: Working example. Note that its actually the draggable drop event that needs to set the z-indexs equal again.
You'll need to make these changes (omit asterisks in your code, of course):
In dragdrop-client.js
// make the new card draggable
newCard.draggable({
zIndex: 2500,
handle: ".card",
stack: ".card",
revert: "invalid",
start: function() {
$(this).effect("highlight", {}, 1000);
$(this).css( "cursor","move" );
**var $par = $(this).parents('.stack');
if ($par.length == 1) {
console.log('in stack');
$par.siblings().css('z-index', '400');
}**
},
stop: function() {
$(this).css("cursor","default");
$(".stack").css('z-index', '500');
}
});
// make the new stack droppable
newStack.droppable({
tolerance: "intersect",
accept: ".card",
greedy: true,
drop: function(event, ui) {
**$(".stack").css('z-index', '500');**
card = ui.draggable;
putCardIntoStack(card,stackId);
}
});
In dragdrop-client.css
.stack {
width: 300px;
border: 1px dashed #ccc;
background-color: #f5f5f5;
margin: 10px;
float:left;
**z-index:500;**
}
I do what two7s_clash recommends for my drag-drop when elements are inserted dynamically. We have some elements being inserted over a canvas and then we want to drag n drop over everything:
start: function(e) { $('element').css('z-index', -1)}
stop: function(e) { $('element').css('z-index', 0)}

Resources