Script.aculo.us Drag 'n' Drop - Revert onEnd condition - javascript

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.

Related

Firing multiple Events on JQuery Resize

I have been using the JQuery Code below to handle a little bit of responsiveness for a menu on a Drupal site. In the two commented lines in the resize function, I am essentially trying to enable and disable the opposite events dependent on the screen size. My first question would be since this handler triggering would be in the resize function, would it cause any kind of significant performance hit to attempt something like this? My second question would be how? I've been trying to use the on and off functions to enable/disable those handlers as needed, but I don't think I'm getting the overall syntax correct. I figure it would be best to break the existing event handlers into functions, but have left them as is for the code example.
jQuery(document).ready(function($) {
$('.nav-toggle').click(function() {
$('#main-menu div ul:first-child').slideToggle(250);
return false;
});
if( ($(window).width() > 600) || ($(document).width() > 600) ) {
$('#main-menu li').mouseenter(function() {
$(this).children('ul').css('display', 'none').stop(true,
true).slideToggle(1).css('display',
'block').children('ul').css('display', 'none');
});
$('#main-menu li').mouseleave(function() {
$(this).children('ul').stop(true, true).fadeOut(1).css('display', 'block');
})
}
else {
$('.drop-down-toggle').click(function() {
$(this).parent().children('ul').slideToggle(500);
});
}
$(window).resize(function() {
if($(window).width() > 600) {
$('div.menu-navigation-container ul.menu').css('display','block');
$('div.menu-navigation-container ul.menu ul.menu').hide();
//**Disable dropdown click and enable mouse enter and mouse leave**
}
else{
$('div.menu-navigation-container ul.menu').hide();
//**Disable mouse enter and mouse leave but enable dropdown click**
}
});
});
Use a throttle function
function throttle (callback, limit) {
var wait = false; // Initially, we're not waiting
return function () { // We return a throttled function
if (!wait) { // If we're not waiting
callback.call(); // Execute users function
wait = true; // Prevent future invocations
setTimeout(function () { // After a period of time
wait = false; // And allow future invocations
}, limit);
}
}
}
$(window).on('resize', throttle(yourResizeFunction, 200))
Read why here: http://www.paulirish.com/2009/throttled-smartresize-jquery-event-handler/
As I said, move your event binding outside of the resize function as binding event handlers within resize/scroll is not a good idea at all as you'd bind the same event over and over for every pixel resized!.
An example would look like this:
$(document) // or you can even use 'div.menu-navigation-container' as opposed to document
.on("click", ".click", function() {})
.on("mouseenter", ".hover", function() {})
.on("mouseleave", ".hover", function() {});
$(window).resize(function() {
//A bit of breathing time when the resize event pauses. Remember, the statements within the resize will trigger for every pixel resize, otherwise.
setTimeout(function() {
if( $(window).width() > 600 ) {
$('div.menu-navigation-container ul.menu').css('display','block');
$('div.menu-navigation-container ul.menu ul.menu').hide();
//I am assuming your selector on which the events are bound to be '.menu-trigger' as you did not post any HTML. Replace this with the appropriate selector.
$(".menu-trigger").removeClass("click").addClass("hover");
}
else{
$('div.menu-navigation-container ul.menu').hide();
//I am assuming your selector on which the events are bound to be '.menu-trigger' as you did not post any HTML. Replace this with the appropriate selector.
$(".menu-trigger").removeClass("hover").addClass("click");
}
}, 250);
});
Hope that helps.

iScroll page currently scrolling to detection

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/

How to slideToggle Selectize.js dropdown?

I'm using the awesome Selectize.js plugin, and I'm trying to add a simple slide animation when the dropdown is opened using jQuery. And I also change the position to static.
http://jsfiddle.net/TAuEH/1/
I changed a this:
/**
* Shows the autocomplete dropdown containing
* the available options.
*/
open: function() {
var self = this;
if (self.isLocked || self.isOpen || (self.settings.mode === 'multi' && self.isFull())) return;
self.focus(true);
self.isOpen = true;
self.refreshClasses();
self.$dropdown.css({visibility: 'hidden', display: 'block'});
self.positionDropdown();
self.$dropdown.css({visibility: 'visible'});
self.trigger('dropdown_open', this.$dropdown);
},
/**
* Closes the autocomplete dropdown menu.
*/
close: function() {
var self = this;
if (!self.isOpen) return;
self.$dropdown.hide();
self.setActiveOption(null);
self.isOpen = false;
self.refreshClasses();
self.trigger('dropdown_close', self.$dropdown);
},
By this:
/**
* Shows the autocomplete dropdown containing
* the available options.
*/
open: function() {
var self = this;
if (self.isLocked || self.isOpen || (self.settings.mode === 'multi' && self.isFull())) return;
self.focus(true);
self.isOpen = true;
self.refreshClasses();
self.$dropdown.slideDown();
self.positionDropdown();
self.trigger('dropdown_open', this.$dropdown);
},
/**
* Closes the autocomplete dropdown menu.
*/
close: function() {
var self = this;
if (!self.isOpen) return;
self.$dropdown.slideUp();
self.setActiveOption(null);
self.isOpen = false;
self.refreshClasses();
self.trigger('dropdown_close', self.$dropdown);
},
Well, as you see, I'm afraid it does not open properly, and does not do the slideup animation when you close it... anyone has better idea to do it?
Any advice, tip or help will be appreciated, and if you need more info i'll edit the post.
Without any change on the plugin code, you can try using the events onDropdownOpen and onDropdownClose and force an animation.
It's a bit hacky, but it works.
Code:
$(document).ready(function () {
$('#sel').selectize({
create: false,
sortField: 'text',
onDropdownOpen: function () {
$(".selectize-dropdown").hide().slideToggle();
},
onDropdownClose: function () {
$(".selectize-dropdown").show().slideToggle();
}
});
});
Demo: http://jsfiddle.net/IrvinDominin/cHxcZ/
EDIT
In the previous version there is an issue when you try to close it pressing the input again, solved using stop.
Ref:
When .stop() is called on an element, the currently-running animation
(if any) is immediately stopped. If, for instance, an element is being
hidden with .slideUp() when .stop() is called, the element will now
still be displayed, but will be a fraction of its previous height.
Callback functions are not called.
If more than one animation method is called on the same element, the
later animations are placed in the effects queue for the element.
These animations will not begin until the first one completes. When
.stop() is called, the next animation in the queue begins immediately.
If the clearQueue parameter is provided with a value of true, then the
rest of the animations in the queue are removed and never run.
Code:
$(document).ready(function () {
$('#sel').selectize({
create: false,
sortField: 'text',
onDropdownOpen: function ($dropdown) {
$dropdown.stop().hide().slideToggle();
},
onDropdownClose: function ($dropdown) {
$dropdown.stop().show().slideToggle();
}
});
});
Demo: http://jsfiddle.net/IrvinDominin/cHxcZ/1/

revert mootools sortable move

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();
}
}
});

Mootools - add variables to all draggable and droppable elements with .implement

Im making a drag and drop system with mootools drag.move class, but i need all the draggable and droppable elements to have some extra variables and maybe add in a function or two. Ive researched on how to do this using .implement but Ive got no idea how to fit that into my code:
window.addEvent('domready', function(){
$$('#draggables DIV').makeDraggable({
droppables: $$('#droppables DIV'),
onEnter: function(draggable, droppable){
droppable.setStyle('background', 'orange');
droppable.setStyle('opacity', '0.4');
snap_left = droppable.getStyle('left');
snap_top = droppable.getStyle('top');
document.getElementById("slot").innerHTML=droppable.id;
},
onLeave: function(draggable, droppable){
droppable.setStyle('background', null);
},
onDrop: function(draggable, droppable){
if (droppable){
droppable.setStyle('background', '');
draggable.setStyle('left', snap_left );
draggable.setStyle('top', snap_top );
} else {
draggable.setStyle('left', snap_left );
draggable.setStyle('top', snap_top );
}
}
});
});
Is what I want posible using .implement?
Can I add these things to all draggable and droppable elements?
ty in advance!
-Thaiscorpion
edit:
Ive tried adding options directly to the main class in the mootools library and tried accesing them from the onEnter event like this:
onEnter: function(draggable, droppable){
if (droppable.occupied){ //here is where im tryin to acces it, the default option is set to occupied: true
droppable.setStyle('background', 'red');
droppable.setStyle('opacity', '0.4');
document.getElementById("slot").innerHTML=droppable.id;
} else {
droppable.setStyle('background', 'orange');
droppable.setStyle('opacity', '0.4');
snap_left = droppable.getStyle('left');
snap_top = droppable.getStyle('top');
document.getElementById("slot").innerHTML=droppable.id;
}
},
but not getting anything to work.
you can use element storage.
draggable.store("occupied", true);
....
if (draggable.retrieve("occupied") === true) {
}
.... functions or anything can be stored per element
element.store("somekey", function() {
element.toggleClass("foo");
});
element.retrieve("somekey").call(element);
and so forth.
to use Implement:
Element.implement({
dragfoo: function() {
this.set("drag", { });
return this;
}
});
// allows you:
$("someid").dragfoo();
though if you need storage, use storage and dont store properties on the actual element. mootools storage really uses an object hash table that's behind a closure. having proprietary element attributes/properties in IE can slow things down considerably in element access.

Categories

Resources