Drag more than one jQuery ui - javascript

Can I drag and save to cookies more than one without repeating all the code?
$(function() {
$('.demo').draggable({
cursor: "move"
,
stop: function(event, ui) {
$.cookie('demox', $(this).css('left'));
$.cookie('demoy', $(this).css('top'));
}
})
.resizable({
aspectRatio: true,
})
})
$(function() {
if ($.cookie('demox') != null) {
$('.demo').css('left', $.cookie('demox'));
}
if ($.cookie('demoy') != null) {
$('.demo').css('top', $.cookie('demoy'));
}
})

You could do something like this:
Is using a specific ID for each element an option to you? With this, you could attach the same handler to these objects and check it when the handler is called, by checking this
By Handler I mean a
function handler(event, ui)
{
$.cookie('demox_'+this.id, $(this).css('left'));
$.cookie('demoy_'+this.id, $(this).css('top'));
}
And you can attach it do the draggable by just writing
$('.demo').draggable({
cursor: "move",
stop: handler
})
Of course you would have to give your ".demo"-Elements an ID.
I hope this something reasonable for you :)
P.S.: Later you can use the following:
$(function() {
$('[id*="demoID_"]').forEach(function(element)
{
if ($.cookie('demox_'+element.id) != null) {
element.css('left', $.cookie('demox_'+element.id));
}
if ($.cookie('demoy_'+element.id) != null) {
element.css('top', $.cookie('demoy_'+element.id));
}
});
});
I hope I don't have a typo in there :)
In this case your elements should have an ID like this: demoID_n and the cookies will be then stored in demox_demoID_0, demox_demoID_1 and so on

Related

jQuery $(this).addClass not working

I have a list of textboxes in which a user can drop a letter but when a wrong letter is dropped inside the textbox I want to addClass("danger") I want to addClass only on the wrong letter textbox I have also attached a screenshot to illustrate the problem.
The textbox has a class with the name of box assigned.
Now my drop function is given below.
function dropabc(event) {
if ($(objBox).attr("correct1") != event.target.id) {
$(".imageError").fadeIn('slow').delay(1000).hide(0);
console.log("error");
$(this).addClass('danger');
} else {
console.log(event.target.id);
console.log("ok");
}
}
$(this).addClass("danger")
However, this is not working, I only want to add the danger class to the box on which a wrong value is dropped.
//makes all the textbox red
$(".box").addClass("danger")
Any help would be very appreciated!
This is the jQuery UI drag and droppable function which is working fine:
var objBox;
$('.drag').draggable({
revert: true,
helper: 'clone',
cursor: 'pointer',
start: function(event, ui) {
$(this).fadeTo('fast', 0.5);
objBox=$(this);
},
stop: function(event, ui) {
$(this).fadeTo(0, 1);
}
});
$("#textbox, .box").droppable({
hoverClass: "hoverPath",
drop: function(event, ui) {
var $this = $(this);
if ($this.val() == '') {
$this.val(ui.draggable.text());
$(this).addClass("checkDiv");
$(this).each(function(i, el){
$(el).addClass(myid[3]);
});
}
var empty = $(this).parent().find("input").filter(function() {
return this.value === "";
});
if(empty.length) {
console.log(empty.length);
}
else{
console.log("done");
}
}
});
This is the PHP code which is echo the number of textbox:
for($x = 0 ; $x < count($code_words); $x++){
echo "<input id='".$code_words[$x]."' ondrop='dropabc(event)' class='box' type='textbox'/>";
}
You're just running a function when you embed the ondrop event inside your input tag.
So instead of embedding it try using the jQuery on("drop").
$(document).on("drop", ".box", function(event){
if ($(objBox).attr("correct1") != event.target.id) {
$(".imageError").fadeIn('slow').delay(1000).hide(0);
console.log("error");
$(this).addClass('danger');
} else {
console.log(event.target.id);
console.log("ok");
}
})
Great it helped you :)
Cheers,

JQuery toggler - Click one toggle should update another

I am using this https://github.com/simontabor/jquery-toggles plugin to toggle an element on my page.
The plugin works fine on one item.
$('.toggle').toggles({
on: true,
text:{
on:'COMPLETE',
off:'INCOMPLETE'
}
});
$('.toggle').on('toggle', function (e, active) {
if(active) {
$(this).removeClass('off');
$(this).addClass('on');
} else {
$(this).removeClass('on');
$(this).addClass('off');
}
});
But I have 2 identical elements, one at the top and one at the bottom of the page.
I am trying to have both updated(toggle) at the same time. I tried just targeting the class but that did not work:
$('.toggle').toggles({
on: true,
text:{
on:'COMPLETE',
off:'INCOMPLETE'
}
});
$('.toggle').on('toggle', function (e, active) {
if(active) {
$('.toggle').removeClass('off');
$('.toggle').addClass('on');
} else {
$('.toggle').removeClass('on');
$('.toggle').addClass('off');
}
});
Any ideas?
I have tried using each but it does not quite work
http://giphy.com/gifs/3o85xxJ7f2fYakUzQs
try adding this line
$('.toggle').toggles(active);
into the .on event like this
$('.toggle').toggles({
on: true,
text:{
on:'COMPLETE',
off:'INCOMPLETE'
}
});
$(".toggle").on("toggle", function(e, active) {
$('.toggle').toggles(active);
if(active) {
$('.toggle').removeClass('off');
$('.toggle').addClass('on');
} else {
$('.toggle').removeClass('on');
$('.toggle').addClass('off');
}
});
You need to handle each element seperately:
$('.toggle').on('toggle', function (e, active) {
$.each($('.toggle'), function(index, element) {
if(element.hasClass('off')){
$('.toggle').removeClass('off');
$('.toggle').addClass('on');
}
if(element.hasClass('on')){
$('.toggle').removeClass('on');
$('.toggle').addClass('off');
}
});
});

Javascript + Differentiate user clicks and clicks sent from function

I have an Accordion function like this:
$("#notaccordion").addClass("ui-accordion ui-widget ui-helper-reset")
.find("h3")
.addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom")
.prepend('<span class="ui-icon ui-icon-triangle-1-e"/>')
.click(function () {
$(this).toggleClass("ui-accordion-header-active").toggleClass("ui-state-active")
.toggleClass("ui-state-default").toggleClass("ui-corner-bottom")
.find("> .ui-icon").toggleClass("ui-icon-triangle-1-e").toggleClass("ui-icon-triangle-1-s");
if ($(this).next().is(':hidden') == true) {
;
$(this).addClass('active'); $(this).next().slideDown('normal');
}
else {
$(this).removeClass('active'); $(this).next().slideUp('normal');
}
//.end().next().slideUp('normal');
return false;
})
.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide();
and a click all panels function to expand all panels at once:
function clickAllPanels() {
var elm = document.getElementsByTagName('table');
var i = elm.length; while (i--) {
clickItem(elm[i]);
}
}
function clickItem(divObj) {
if (divObj.click) {
divObj.click();
} else if (document.createEvent) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
var allowDefault = divObj.dispatchEvent(evt);
}
}
How can I let the accordion .click(function () function know that it's clickAllPanels that is sending the 'clicks' instead of a user's physical click. I need to do this because I want to change the slide up and down logic if it's from clickAllPanels.
The way I'd do it is to use two different event names, one being "click" and the other being something like "forced-click":
$( ... whatever ... ).bind("click forced-click", function(ev) {
if (ev.type === "forced-click") {
// called by programmatic trigger
}
// ...
});
When you trigger the event:
$( ... whatever ... ).trigger("forced-click");
Another way to do it I guess would be to check the event object to see if there's an "originalEvent" property. If not, then you know it was triggered programmatically. Personally I don't like to rely on that because it's not documented.
It is often a good idea to have separate functions for the event handler and for the actual work you are doing:
function do_stuff(suitable_arguments, a_flag){
//...
}
$(/*...*/).click(function(){
do_stuff( /*...*/, true);
}
in_my_other_code(){
do_stuff( /*...*/, false);
}
By detaching your logic from the event handling you have much more flexibility in choosing when and how to invoke it.
Why don't you use jquery in your 'clickItem()' function:
function clickItem(divObj) {
$(divObj).trigger('click', { manual: true });
}
The event parameter in you click handler will have a property "isTrigger", which won't exist when items are clicked with the mouse:
$("#notaccordion")
...
.click(function(e) {
if (e['isTrigger']) {
// do this
} else {
// do that
}
});
Here's a fiddle

How do I select a div with its children as handles using jQuerys Selectable?

I have a div which contains two elements which dont fill up that div. I want selecting the elements to select the containing div instead. Also, I want that clicking in the div but outside the elements doesnt select the element (and triggers a deselect). How do i do this?
fiddle: http://jsfiddle.net/U5cmy/1/
$("#all").on("mousedown", function(event) {
if (!$(event.target).is(".item-top, .item-bottom") && !$(event.target).hasClass("ui-selected")) {
event.stopImmediatePropagation();
return false;
}
});
$('#all').selectable({
start: function(event, ui) {
$(this).data("isDeselect", $(event.target).is(".item"))
},
selected: function(e, ui) {
if ($(this).data("isDeselect") === true) {
$(ui.selected).removeClass("ui-selected");
ui.selected = null;
}
}
});
fiddle: http://jsfiddle.net/1stein/sNMw3/

Preventing click event with jQuery drag and drop

I have elements on the page which are draggable with jQuery. Do these elements have click event which navigates to another page (ordinary links for example).
What is the best way to prevent click from firing on dropping such element while allowing clicking it is not dragged and drop state?
I have this problem with sortable elements but think it is good to have a solution for general drag and drop.
I've solved the problem for myself. After that I found that same solution exists for Scriptaculous, but maybe someone has a better way to achieve that.
A solution that worked well for me and that doesn't require a timeout: (yes I'm a bit pedantic ;-)
I add a marker class to the element when dragging starts, e.g. 'noclick'. When the element is dropped, the click event is triggered -- more precisely if dragging ends, actually it doesn't have to be dropped onto a valid target. In the click handler, I remove the marker class if present, otherwise the click is handled normally.
$('your selector').draggable({
start: function(event, ui) {
$(this).addClass('noclick');
}
});
$('your selector').click(function(event) {
if ($(this).hasClass('noclick')) {
$(this).removeClass('noclick');
}
else {
// actual click event code
}
});
Solution is to add click handler that will prevent click to propagate on start of drag. And then remove that handler after drop is performed. The last action should be delayed a bit for click prevention to work.
Solution for sortable:
...
.sortable({
...
start: function(event, ui) {
ui.item.bind("click.prevent",
function(event) { event.preventDefault(); });
},
stop: function(event, ui) {
setTimeout(function(){ui.item.unbind("click.prevent");}, 300);
}
...
})
Solution for draggable:
...
.draggable({
...
start: function(event, ui) {
ui.helper.bind("click.prevent",
function(event) { event.preventDefault(); });
},
stop: function(event, ui) {
setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
}
...
})
I had the same problem and tried multiple approaches and none worked for me.
Solution 1
$('.item').click(function(e)
{
if ( $(this).is('.ui-draggable-dragging') ) return false;
});
does nothing for me. The item is being clicked after the dragging is done.
Solution 2 (by Tom de Boer)
$('.item').draggable(
{
stop: function(event, ui)
{
$( event.originalEvent.target).one('click', function(e){ e.stopImmediatePropagation(); } );
}
});
This works just fine but fails in one case- when I was going fullscreen onclick:
var body = $('body')[0];
req = body.requestFullScreen || body.webkitRequestFullScreen || body.mozRequestFullScreen;
req.call(body);
Solution 3 (by Sasha Yanovets)
$('.item').draggable({
start: function(event, ui) {
ui.helper.bind("click.prevent",
function(event) { event.preventDefault(); });
},
stop: function(event, ui) {
setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
}
})
This does not work for me.
Solution 4- the only one that worked just fine
$('.item').draggable(
{
});
$('.item').click(function(e)
{
});
Yep, that's it- the correct order does the trick- first you need to bind draggable() then click() event. Even when I put fullscreen toggling code in click() event it still didn't go to fullscreen when dragging. Perfect for me!
I'd like to add to this that it seems preventing the click event only works if the click event is defined AFTER the draggable or sortable event. If the click is added first, it gets activated on drag.
I don't really like to use timers or preventing, so what I did is this:
var el, dragged
el = $( '#some_element' );
el.on( 'mousedown', onMouseDown );
el.on( 'mouseup', onMouseUp );
el.draggable( { start: onStartDrag } );
onMouseDown = function( ) {
dragged = false;
}
onMouseUp = function( ) {
if( !dragged ) {
console.log('no drag, normal click')
}
}
onStartDrag = function( ) {
dragged = true;
}
Rocksolid..
lex82's version but for .sortable()
start: function(event, ui){
ui.item.find('.ui-widget-header').addClass('noclick');
},
and you may only need:
start: function(event, ui){
ui.item.addClass('noclick');
},
and here's what I'm using for the toggle:
$("#datasign-widgets .ui-widget-header").click(function(){
if ($(this).hasClass('noclick')) {
$(this).removeClass('noclick');
}
else {
$(this).next().slideToggle();
$(this).find('.ui-icon').toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
}
});
A possible alternative for Sasha's answer without preventing default:
var tmp_handler;
.sortable({
start : function(event,ui){
tmp_handler = ui.item.data("events").click[0].handler;
ui.item.off();
},
stop : function(event,ui){
setTimeout(function(){ui.item.on("click", tmp_handler)}, 300);
},
In jQuery UI, elements being dragged are given the class "ui-draggable-dragging".
We can therefore use this class to determine whether to click or not, just delay the event.
You don't need to use the "start" or "stop" callback functions, simply do:
$('#foo').on('mouseup', function () {
if (! $(this).hasClass('ui-draggable-dragging')) {
// your click function
}
});
This is triggered from "mouseup", rather than "mousedown" or "click" - so there's a slight delay, might not be perfect - but it's easier than other solutions suggested here.
In my case it worked like this:
$('#draggable').draggable({
start: function(event, ui) {
$(event.toElement).one('click', function(e) { e.stopPropagation(); });
}
});
After reading through this and a few threads this was the solution I went with.
var dragging = false;
$("#sortable").mouseover(function() {
$(this).parent().sortable({
start: function(event, ui) {
dragging = true;
},
stop: function(event, ui) {
// Update Code here
}
})
});
$("#sortable").click(function(mouseEvent){
if (!dragging) {
alert($(this).attr("id"));
} else {
dragging = false;
}
});
the most easy and robust solution? just create transparent element over your draggable.
.click-passthrough {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: transparent;
}
element.draggable({
start: function () {
},
drag: function(event, ui) {
// important! if create the 'cover' in start, then you will not see click events at all
if (!element.find('.click-passthrough').length) {
element.append("<div class='click-passthrough'></div>");
}
},
stop: function() {
// remove the cover
element.find('.click-passthrough').remove();
}
});
Have you tried disabling the link using event.preventDefault(); in the start event and re-enabling it in the drag stopped event or drop event using unbind?
Just a little wrinkle to add to the answers given above. I had to make a div that contains a SalesForce element draggable, but the SalesForce element has an onclick action defined in the html through some VisualForce gobbledigook.
Obviously this violates the "define click action after the drag action" rule, so as a workaround I redefined the SalesForce element's action to be triggered "onDblClick", and used this code for the container div:
$(this).draggable({
zIndex: 999,
revert: true,
revertDuration: 0,
start: function(event, ui) {
$(this).addClass('noclick');
}
});
$(this).click(function(){
if( $(this).hasClass('noclick'))
{
$(this).removeClass('noclick');
}
else
{
$(this).children(":first").trigger('dblclick');
}
});
The parent's click event essentially hides the need to double-click the child element, leaving the user experience intact.
I tried like this:
var dragging = true;
$(this).click(function(){
if(!dragging){
do str...
}
});
$(this).draggable({
start: function(event, ui) {
dragging = true;
},
stop: function(event, ui) {
setTimeout(function(){dragging = false;}, 300);
}
});
for me helped passing the helper in options object as:
.sortable({
helper : 'clone',
start:function(),
stop:function(),
.....
});
Seems cloning dom element that is dragged prevented the bubbling of the event. I couldnĀ“t avoid it with any eventPropagation, bubbling, etc. This was the only working solution for me.
The onmousedown and onmouseup events worked in one of my smaller projects.
var mousePos = [0,0];
function startClick()
{
mousePos = [event.clientX,event.clientY];
}
function endClick()
{
if ( event.clientX != mousePos[0] && event.clientY != mousePos[1] )
{
alert( "DRAG CLICK" );
}
else
{
alert( "CLICK" );
}
}
<img src=".." onmousedown="startClick();" onmouseup="endClick();" />
Yes, I know. Not the cleanest way, but you get the idea.

Categories