I use the following iScroll 5 code (generally, not so important: just a common scrolling page-by-page):
var myScroll = new IScroll('.scroller', {
mouseWheel: true,
scrollbars: true,
keyBindings: {
// doesn't matter
},
preventDefault: false,
fadeScrollbars: true,
snap: 'section', // <-- that's the key
wheelAction: 'scroll',
});
myScroll.on('beforeScrollStart', function (e) {
myScroll.preventDisabling = true;
});
myScroll.on('scrollMove', function (e) {
});
myScroll.on('scrollStart', function (e) {
// !!! I need the detection somewhere here !!!
if (!myScroll.preventDisabling) {
myScroll.disable();
disabledWasCalledInMeanwhile = true;
}
myScroll.preventDisabling = false;
});
var disabledWasCalledInMeanwhile = false;
// that's just to prevent jumping to another page before scrolling is finished
myScroll.on('scrollEnd', function (e) {
disabledWasCalledInMeanwhile = false;
window.setTimeout(function () {
if (!disabledWasCalledInMeanwhile)
myScroll.enable();
}, 250);
$('.labels>*').toggleClass('active', false)
.eq(this.currentPage.pageY).toggleClass('active', true);
});
myScroll.on('scrollCancel', function (e) {
myScroll.enable();
});
So, is there any chance to detect in beforeScrollStart or scrollStart the page I am going to scroll to? That's important to know for triggering that page items animation. Thanks!
I've used iScroll for a number of years (it is a excellent library), and I don't know of a built-in method of doing it. All the scroll events (except scrollEnd) before the iScroll snap is determined. However, with a slight modification of the library, I believe it is possible.
First, go into iScroll.js source and find the _nearestSnap method. At the bottom of the method, you will find the object you seek returned. Before the return, grab that data and pass it to a custom event. Unfortunately, iScroll's event system doesn't permit you to pass custom variables to events, so you'll have to do a work-around. In addition, you'll need to track the "flick" event because it won't trigger the _nearestSnap method.
iScroll modification in _nearestSnap method
this.customSnap({
x: x,
y: y,
pageX: i,
pageY: m
});
Update to class instance. Note the addition of "customSnap" method and the flick event.
myScroll = new IScroll('#wrapper', {snap: "p"});
myScroll.customSnap = function(data) {
console.log(data);
};
myScroll.on('flick', function() {
console.log(data.currentPage);
});
That should do it. Not necessarily the cleanest update, but in my testing, it does work.
http://jsfiddle.net/9pa4th4y/
Related
I need to add gestures in my Meteor app. I don't understand how.
Now I have put my code in Template.XX.rendered and than I call the gesture inside the events scope:
Session.setDefault('deletable', false);
Template.xx.rendered = function(){
$('body').hammer();
};
Template.xx.events({
'swipeleft #hammerDiv': function(e, t) {
Session.set('deletable', true);
},
'swiperight #hammerDiv': function(e, t) {
Session.set('deletable', false);
}
});
Template.territories.helpers({
deleteButton : function(){
return Session.get('deletable');
}
});
this simple code make possible to appear a delete button in the swiped item. All seems to work with chrome and mouse swipe, but when I emulate the app in my android device (meteor run android-device), swipe gesture don't works. If I test in my device with Chrome browser all works done.
Is there any compatibility problem? Is my code wrong? Any suggestions?
Thanks a lot!
I found the definitive solution that works for me:
I changed hammer() properties set to a fast swipe and touch;
I've added preventDefault() in each swipe events;
Set is now set to pass this._id to the helper to check if the swiped
item has the same object id and then, if true, it shows delete
button.
The code:
Session.setDefault('deletable', null);
Template.xx.rendered = function(){
$('body').hammer({
drag_min_distance:1,
swipe_velocity:0.1
});
};
Template.xx.events({
'swipeleft #hammerDiv': function(e, t) {
e.preventDefault();
Session.set('deletable', null);
},
'swiperight #hammerDiv': function(e, t) {
e.preventDefault();
Session.set('deletable', this._id);
}
});
Template.xx.helpers({
deleteButton : function(){
var thisItem = Session.get('deletable');
if (thisItem == this._id){
return true
}else{
return false;
}
}
});
Alternatively, instead of apply preventDefault() within events, it's possible to change the hammer() target and add a new property like this:
$('#hammerDiv').hammer({
drag_min_distance:1,
swipe_velocity:0.1
prevent_default:true
});
We have multiple animations against the same object. We need to take different actions when each of these animations end.
Right now, we bind to the webkitAnimationEnd event, and use a gnarly if/then statement to handle each animation differently.
Is there a way to essentially create custom webkitAnimationEnd events, allowing us to fire a specific event handler when a specific animation ends? For instance, fire handler1 when animation1 ends and fire handler2 when animation2 ends.
We're building for Webkit browsers, specifically Mobile Safari.
Thanks!
For a simple event-trigger, you can pass a function to jQuery's trigger() method and use the returned value of that function to call a trigger a specific event (which can then be listened-for:
function animEndTrigger(e) {
if (!e) {
return false;
}
else {
var animName = e.originalEvent.animationName;
return animName + 'FunctionTrigger';
}
}
$('body').on('bgAnimFunctionTrigger fontSizeFunctionTrigger', function(e){
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
$(this).trigger(animEndTrigger(e));
});
JS Fiddle demo.
You can, of course, also use the called function to either trigger the event itself or assess the passed parameters to determine whether or not to return an event at all:
One method to assess for a particular event to trigger is to use an object:
var animations = {
'bgAnim': 'aParticularEvent'
};
function animEndTrigger(e) {
if (!e) {
return false;
}
else {
var animName = e.originalEvent.animationName;
return animations[animName] ? animations[animName] : false;
}
}
$('body').on('aParticularEvent', function(e) {
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
$(this).trigger(animEndTrigger(e));
});
JS Fiddle demo.
Though, in this case, the return false should be altered so as not to provide the error Uncaught TypeError: Object false has no method 'indexOf' (which I've not bothered, as yet, to account for).
The following causes the called-function (animEndTrigger()) to directly trigger() the custom event (which requires an element on which to bind the trigger() method) and also avoids the Uncaught TypeError above:
var animations = {
'bgAnim': 'aParticularEvent'
};
function animEndTrigger(e, el) {
if (!e || !el) {
return false;
}
else {
var animName = e.originalEvent.animationName;
if (animations[animName]) {
$(el).trigger(animations[animName]);
}
}
}
$('body').on('aParticularEvent', function(e) {
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
animEndTrigger(e, this);
});
JS Fiddle demo.
Of course you're still, effectively, using an if to perform an assessment, so I can't be particularly sure that this is any tidier than your own already-implemented solution.
I'm using mootools sortable to handle a simple image gallery function. If you move the image from the left column to the right column, the photo is added into the user's "photos" table by a storeImage call in the onComplete event.
Here's a simple fiddle of it: http://jsfiddle.net/JQja3/1/
My question is, if the storeImage call from the onComplete event fails, how can I revert the image back to the "available" left stack?
you need to store the groups and parents in a var and then revert, this will totally restore the old group and order.
this pattern will create a restore function that can undo it - every time.
http://jsfiddle.net/JQja3/6/
new Sortables('#example2 UL', {
clone: true,
revert: true,
opacity: 0.7,
onStart: function(el, clone) {
this.restore = (function() {
var oldParent = el.getParent(),
oldList = oldParent.getChildren();
return function() {
oldParent.adopt(oldList);
}
})();
},
onComplete: function(el, clone){
var storeImage = false; // this is false to simulate a bad return from the DB store call
if (!storeImage){
this.restore();
}
}
});
I'm trying to revert a draggable if a condition returns false. So for instance, I'd like to do the following:
new Draggable('myelement', {
onStart: function() {
// do something
},
onEnd: function() {
var condition = getConditionVal();
if (!condition) revert to original position
else {
// do something else
}
}
});
Would this be possible? Not sure if "droppables" would work in this case since the droppable area changes dynamically.
Scriptaculous drag/drop is designed to have all kinds of fancy stuff easily added.
Of course you can edit the revert option any time.
To change the value of the revert-option of an draggable, just reset the revert-option:
var myDraggable = new Draggable('myelement', {
onStart: function() {
// do something
},
onEnd: function() {
var condition = getConditionVal();
if (!condition){
myDraggable.options.revert = true;
}
else {
myDraggable.options.revert = false;
// do something else
}
};
});
Scriptaculous does the revert right after the onEnd event call,
which gives us the possibility of changing it before it will be executed.
Scriptaculous's drag/drop code wasn't designed to have conditional revert. You can have revert or no revert. That's all, sadly.
This feature has been requested many times but scripty/prototype has waned in popularity over the years, so it's doubtful this feature will ever be added.
I have registered a trigger on window resize. I want to know how I can trigger the event to be called. For example, when hide a div, I want my trigger function to be called.
I found window.resizeTo() can trigger the function, but is there any other solution?
window.dispatchEvent(new Event('resize'));
Where possible, I prefer to call the function rather than dispatch an event. This works well if you have control over the code you want to run, but see below for cases where you don't own the code.
window.onresize = doALoadOfStuff;
function doALoadOfStuff() {
//do a load of stuff
}
In this example, you can call the doALoadOfStuff function without dispatching an event.
In your modern browsers, you can trigger the event using:
window.dispatchEvent(new Event('resize'));
This doesn't work in Internet Explorer, where you'll have to do the longhand:
var resizeEvent = window.document.createEvent('UIEvents');
resizeEvent.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(resizeEvent);
jQuery has the trigger method, which works like this:
$(window).trigger('resize');
And has the caveat:
Although .trigger() simulates an event activation, complete with a synthesized event object, it does not perfectly replicate a naturally-occurring event.
You can also simulate events on a specific element...
function simulateClick(id) {
var event = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
var elem = document.getElementById(id);
return elem.dispatchEvent(event);
}
With jQuery, you can try to call trigger:
$(window).trigger('resize');
Combining pomber's and avetisk's answers to cover all browsers and not causing warnings:
if (typeof(Event) === 'function') {
// modern browsers
window.dispatchEvent(new Event('resize'));
} else {
// for IE and other old browsers
// causes deprecation warning on modern browsers
var evt = window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(evt);
}
A pure JS that also works on IE (from #Manfred comment)
var evt = window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(evt);
Or for angular:
$timeout(function() {
var evt = $window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, $window, 0);
$window.dispatchEvent(evt);
});
I wasn't actually able to get this to work with any of the above solutions. Once I bound the event with jQuery then it worked fine as below:
$(window).bind('resize', function () {
resizeElements();
}).trigger('resize');
just
$(window).resize();
is what I use... unless I misunderstand what you're asking for.
I believe this should work for all browsers:
var event;
if (typeof (Event) === 'function') {
event = new Event('resize');
} else { /*IE*/
event = document.createEvent('Event');
event.initEvent('resize', true, true);
}
window.dispatchEvent(event);
Response with RxJS
Say Like something in Angular
size$: Observable<number> = fromEvent(window, 'resize').pipe(
debounceTime(250),
throttleTime(300),
mergeMap(() => of(document.body.clientHeight)),
distinctUntilChanged(),
startWith(document.body.clientHeight),
);
If manual subscription desired (Or Not Angular)
this.size$.subscribe((g) => {
console.log('clientHeight', g);
})
Since my intial startWith Value might be incorrect (dispatch for correction)
window.dispatchEvent(new Event('resize'));
In say Angular (I could..)
<div class="iframe-container" [style.height.px]="size$ | async" >..
window.resizeBy() will trigger window's onresize event. This works in both Javascript or VBScript.
window.resizeBy(xDelta, yDelta) called like window.resizeBy(-200, -200) to shrink page 200px by 200px.