How to slideToggle Selectize.js dropdown? - javascript

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/

Related

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/

Integrate virtual keyboard into extjs 4.2 form

I'm adding the virtual keyboard from http://www.greywyvern.com/code/javascript/keyboard to a text field of an extjs 4.2 form.
It basically works, see here: http://jsfiddle.net/g5VN8/1/
1) My first question is: is this really the best way to connect them? Looks ugly to me with a timer instead of events to keep the extjs value up to date.
Plus I can't overcome the following two issues:
2) the keyboard icon is wrapped to a new line. It should instead be at the end of the field, on the right side, just as in the examples here: http://www.greywyvern.com/code/javascript/keyboard
3) The field focus doesn't work. I have it in a show listener. Even when wrapped in a window.setTimeout() it doesn't work, so it's not a timing issue. No error is thrown.
Here is a copy-paste (stackoverflow's rules). I'll keep both places up to date.
Ext.onReady(function() {
Ext.QuickTips.init();
var formPanel = Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
bodyStyle: 'padding: 5px 5px 0 5px;',
defaults: {
anchor: '100%',
},
items: [{
xtype:'textfield',
name: 'string',
fieldLabel: 'String',
maxLength:30, enforceMaxLength:true,
allowBlank: false,
listeners: {
show: function(field) {
//focus the field when the window shows
field.focus(true, 1000); //TODO: doesn't work, no error
},
afterrender:function(cmp){
cmp.inputEl.set({ //see http://jsfiddle.net/4TSDu/19/
autocomplete:'on'
});
//attach the keyboard
//because it modifies the dom directly we need to hack it to
//inform extjs (really, ext has no such listener option?)
var interval = window.setInterval(function() {
try {
var newValue = cmp.inputEl.dom.value;
var oldValue = cmp.getValue();
if (newValue != oldValue) {
//only do it then, cause it also moves the cursor
//to the end and that sucks.
cmp.setValue( newValue );
}
} catch (e) {
//form was removed
window.clearInterval(interval);
}
}, 100);
// see http://www.greywyvern.com/code/javascript/keyboard
VKI_attach(cmp.inputEl.dom);
}
}
}],
buttons: [{
text: 'Alert string',
handler: function() {
var stringField = this.up('form').getForm().findField('string');
alert(stringField.getValue());
}
}]
});
});
You can attach a listener to the keyboard and when the user clicks on a VKI key you trigger the textfield change event.
Ext.getBody().on({
mousedown: function (ev) {
if (ev.target.tagName === 'TD') {
// We trigger change event only on textfield with the focus
if (document.activeElement) {
if (document.activeElement.id === cmp.inputEl.dom.id) cmp.fireEvent('change');
}
}
},
delegate: '#keyboardInputMaster'
});
This is because ExtJS 4 writes the input field with "style=width:100%".
An easy way is to add a negative margin to the textfield
fieldStyle: 'margin-right:-40px'
Weird ExtJS behaviour. You must focus the input element, not te thextfield component
Ext.defer(function () {
cmp.inputEl.dom.focus();
}, 100);
You can see the whole solution here: http://jsfiddle.net/EGbLn/3/
Avoid timers. Use regular dom event listeners instead.
afterrender: function (cmp) {
...
// simply attach this to the change event from dom element
cmp.inputEl.dom.addEventListener('change', function(){
cmp.setValue(this.value);
});
...
}
(answered already by Samy Rancho)
fieldStyle: 'margin-right:-40px',
Again, avoid timers and anything similar. Simply add this:
afterrender: function (cmp) {
...
//focus on field
cmp.inputEl.dom.focus();
...
}
Find updated fiddle here: http://jsfiddle.net/g5VN8/11/

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

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

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.

jQuery event to trigger action when a div is made visible

I'm using jQuery in my site and I would like to trigger certain actions when a certain div is made visible.
Is it possible to attach some sort of "isvisible" event handler to arbitrary divs and have certain code run when they the div is made visible?
I would like something like the following pseudocode:
$(function() {
$('#contentDiv').isvisible(function() {
alert("do something");
});
});
The alert("do something") code should not fire until the contentDiv is actually made visible.
Thanks.
You could always add to the original .show() method so you don't have to trigger events every time you show something or if you need it to work with legacy code:
Jquery extension:
jQuery(function($) {
var _oldShow = $.fn.show;
$.fn.show = function(speed, oldCallback) {
return $(this).each(function() {
var obj = $(this),
newCallback = function() {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
// you can trigger a before show if you want
obj.trigger('beforeShow');
// now use the old function to show the element passing the new callback
_oldShow.apply(obj, [speed, newCallback]);
});
}
});
Usage example:
jQuery(function($) {
$('#test')
.bind('beforeShow', function() {
alert('beforeShow');
})
.bind('afterShow', function() {
alert('afterShow');
})
.show(1000, function() {
alert('in show callback');
})
.show();
});
This effectively lets you do something beforeShow and afterShow while still executing the normal behavior of the original .show() method.
You could also create another method so you don't have to override the original .show() method.
The problem is being addressed by DOM mutation observers. They allow you to bind an observer (a function) to events of changing content, text or attributes of dom elements.
With the release of IE11, all major browsers support this feature, check http://caniuse.com/mutationobserver
The example code is a follows:
$(function() {
$('#show').click(function() {
$('#testdiv').show();
});
var observer = new MutationObserver(function(mutations) {
alert('Attributes changed!');
});
var target = document.querySelector('#testdiv');
observer.observe(target, {
attributes: true
});
});
<div id="testdiv" style="display:none;">hidden</div>
<button id="show">Show hidden div</button>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
There is no native event you can hook into for this however you can trigger an event from your script after you have made the div visible using the .trigger function
e.g
//declare event to run when div is visible
function isVisible(){
//do something
}
//hookup the event
$('#someDivId').bind('isVisible', isVisible);
//show div and trigger custom event in callback when div is visible
$('#someDivId').show('slow', function(){
$(this).trigger('isVisible');
});
You can use jQuery's Live Query plugin.
And write code as follows:
$('#contentDiv:visible').livequery(function() {
alert("do something");
});
Then everytime the contentDiv is visible, "do something" will be alerted!
redsquare's solution is the right answer.
But as an IN-THEORY solution you can write a function which is selecting the elements classed by .visibilityCheck (not all visible elements) and check their visibility property value; if true then do something.
Afterward, the function should be performed periodically using the setInterval() function. You can stop the timer using the clearInterval() upon successful call-out.
Here's an example:
function foo() {
$('.visibilityCheck').each(function() {
if ($(this).is(':visible')){
// do something
}
});
}
window.setInterval(foo, 100);
You can also perform some performance improvements on it, however, the solution is basically absurd to be used in action. So...
The following code (pulled from http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery/) will enable you to use $('#someDiv').on('show', someFunc);.
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
If you want to trigger the event on all elements (and child elements) that are actually made visible, by $.show, toggle, toggleClass, addClass, or removeClass:
$.each(["show", "toggle", "toggleClass", "addClass", "removeClass"], function(){
var _oldFn = $.fn[this];
$.fn[this] = function(){
var hidden = this.find(":hidden").add(this.filter(":hidden"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function(){
$(this).triggerHandler("show"); //No bubbling
});
return result;
}
});
And now your element:
$("#myLazyUl").bind("show", function(){
alert(this);
});
You could add overrides to additional jQuery functions by adding them to the array at the top (like "attr")
a hide/show event trigger based on Glenns ideea:
removed toggle because it fires show/hide and we don't want 2fires for one event
$(function(){
$.each(["show","hide", "toggleClass", "addClass", "removeClass"], function(){
var _oldFn = $.fn[this];
$.fn[this] = function(){
var hidden = this.find(":hidden").add(this.filter(":hidden"));
var visible = this.find(":visible").add(this.filter(":visible"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function(){
$(this).triggerHandler("show");
});
visible.filter(":hidden").each(function(){
$(this).triggerHandler("hide");
});
return result;
}
});
});
I had this same problem and created a jQuery plugin to solve it for our site.
https://github.com/shaunbowe/jquery.visibilityChanged
Here is how you would use it based on your example:
$('#contentDiv').visibilityChanged(function(element, visible) {
alert("do something");
});
What helped me here is recent ResizeObserver spec polyfill:
const divEl = $('#section60');
const ro = new ResizeObserver(() => {
if (divEl.is(':visible')) {
console.log("it's visible now!");
}
});
ro.observe(divEl[0]);
Note that it's crossbrowser and performant (no polling).
Just bind a trigger with the selector and put the code into the trigger event:
jQuery(function() {
jQuery("#contentDiv:hidden").show().trigger('show');
jQuery('#contentDiv').on('show', function() {
console.log('#contentDiv is now visible');
// your code here
});
});
Use jQuery Waypoints :
$('#contentDiv').waypoint(function() {
alert('do something');
});
Other examples on the site of jQuery Waypoints.
I did a simple setinterval function to achieve this. If element with class div1 is visible, it sets div2 to be visible. I know not a good method, but a simple fix.
setInterval(function(){
if($('.div1').is(':visible')){
$('.div2').show();
}
else {
$('.div2').hide();
}
}, 100);
You can also try jQuery appear plugin as mentioned in parallel thread https://stackoverflow.com/a/3535028/741782
This support easing and trigger event after animation done! [tested on jQuery 2.2.4]
(function ($) {
$.each(['show', 'hide', 'fadeOut', 'fadeIn'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
var result = el.apply(this, arguments);
var _self=this;
result.promise().done(function () {
_self.triggerHandler(ev, [result]);
//console.log(_self);
});
return result;
};
});
})(jQuery);
Inspired By http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
There is a jQuery plugin available for watching change in DOM attributes,
https://github.com/darcyclarke/jQuery-Watch-Plugin
The plugin wraps All you need do is bind MutationObserver
You can then use it to watch the div using:
$("#selector").watch('css', function() {
console.log("Visibility: " + this.style.display == 'none'?'hidden':'shown'));
//or any random events
});
Hope this will do the job in simplest manner:
$("#myID").on('show').trigger('displayShow');
$('#myID').off('displayShow').on('displayShow', function(e) {
console.log('This event will be triggered when myID will be visible');
});
I changed the hide/show event trigger from Catalint based on Glenns idea.
My problem was that I have a modular application. I change between modules showing and hiding divs parents. Then when I hide a module and show another one, with his method I have a visible delay when I change between modules. I only need sometimes to liten this event, and in some special childs. So I decided to notify only the childs with the class "displayObserver"
$.each(["show", "hide", "toggleClass", "addClass", "removeClass"], function () {
var _oldFn = $.fn[this];
$.fn[this] = function () {
var hidden = this.find(".displayObserver:hidden").add(this.filter(":hidden"));
var visible = this.find(".displayObserver:visible").add(this.filter(":visible"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function () {
$(this).triggerHandler("show");
});
visible.filter(":hidden").each(function () {
$(this).triggerHandler("hide");
});
return result;
}
});
Then when a child wants to listen for "show" or "hide" event I have to add him the class "displayObserver", and when It does not want to continue listen it, I remove him the class
bindDisplayEvent: function () {
$("#child1").addClass("displayObserver");
$("#child1").off("show", this.onParentShow);
$("#child1").on("show", this.onParentShow);
},
bindDisplayEvent: function () {
$("#child1").removeClass("displayObserver");
$("#child1").off("show", this.onParentShow);
},
I wish help
One way to do this.
Works only on visibility changes that are made by css class change, but can be extended to watch for attribute changes too.
var observer = new MutationObserver(function(mutations) {
var clone = $(mutations[0].target).clone();
clone.removeClass();
for(var i = 0; i < mutations.length; i++){
clone.addClass(mutations[i].oldValue);
}
$(document.body).append(clone);
var cloneVisibility = $(clone).is(":visible");
$(clone).remove();
if (cloneVisibility != $(mutations[0].target).is(":visible")){
var visibilityChangedEvent = document.createEvent('Event');
visibilityChangedEvent.initEvent('visibilityChanged', true, true);
mutations[0].target.dispatchEvent(visibilityChangedEvent);
}
});
var targets = $('.ui-collapsible-content');
$.each(targets, function(i,target){
target.addEventListener('visibilityChanged',VisbilityChanedEventHandler});
target.addEventListener('DOMNodeRemovedFromDocument',VisbilityChanedEventHandler });
observer.observe(target, { attributes: true, attributeFilter : ['class'], childList: false, attributeOldValue: true });
});
function VisbilityChanedEventHandler(e){console.log('Kaboom babe'); console.log(e.target); }
my solution:
; (function ($) {
$.each([ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = $.fn[ name ];
$.fn[ name ] = function( speed, easing, callback ) {
if(speed == null || typeof speed === "boolean"){
var ret=cssFn.apply( this, arguments )
$.fn.triggerVisibleEvent.apply(this,arguments)
return ret
}else{
var that=this
var new_callback=function(){
callback.call(this)
$.fn.triggerVisibleEvent.apply(that,arguments)
}
var ret=this.animate( genFx( name, true ), speed, easing, new_callback )
return ret
}
};
});
$.fn.triggerVisibleEvent=function(){
this.each(function(){
if($(this).is(':visible')){
$(this).trigger('visible')
$(this).find('[data-trigger-visible-event]').triggerVisibleEvent()
}
})
}
})(jQuery);
example usage:
if(!$info_center.is(':visible')){
$info_center.attr('data-trigger-visible-event','true').one('visible',processMoreLessButton)
}else{
processMoreLessButton()
}
function processMoreLessButton(){
//some logic
}
$( window ).scroll(function(e,i) {
win_top = $( window ).scrollTop();
win_bottom = $( window ).height() + win_top;
//console.log( win_top,win_bottom );
$('.onvisible').each(function()
{
t = $(this).offset().top;
b = t + $(this).height();
if( t > win_top && b < win_bottom )
alert("do something");
});
});
$(function() {
$(document).click(function (){
if ($('#contentDiv').is(':visible')) {
alert("Visible");
} else {
alert("Hidden");
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="contentDiv">Test I'm here</div>
<button onclick="$('#contentDiv').toggle();">Toggle the div</button>
<div id="welcometo">Özhan</div>
<input type="button" name="ooo"
onclick="JavaScript:
if(document.all.welcometo.style.display=='none') {
document.all.welcometo.style.display='';
} else {
document.all.welcometo.style.display='none';
}">
This code auto control not required query visible or unvisible control

Categories

Resources