I'm using dragula and wanted to have a heading within each container. I've managed to make the heading non-draggable via the moves attribute, but, then I also wanted to prohibit that elements can be dropped above the heading so I added:
accepts: function (el, target) {
var itemPos = Array.from(el.parentNode.children).indexOf(el);
var acceptDrop = itemPos > 0;
console.log("Accept Drop = " + acceptDrop);
return acceptDrop;
},
In the console log, I can see that the acceptDrop is false when I move an element to the first position but the drop is possible anyway! But then I can't move it from that position. I.e. If the accepts returns false when the drag is initiated I can't drop the item anywhere, but if it starts with true I can drop it everywhere. Am I missing something or how can I make this dynamic and prevent drops at position zero?
(I know that I can put the heading outside the container with draggable items but that needs extra HTML nesting that shouldn't be needed)
Related
I'm working off of a tutorial from codrops. There is a hover event for each item, as well as a click event that triggers an anime.js function.
I'm trying to work this so certain items (grid cells) don't trigger the anime.js function when clicked, but the hover function still works.
I've tried simple css pointer-events, but that disables the hover function.
I've constructing the two groups as separate items in JS, but then the animation doesn't work the same (it staggers the two different classes).
I've tried things to stop the default javascript behavior, but it seems to have no impact on the code.
Help!!!
I've made a functioning codepen - in the option there I'm trying to disable click event for any grid item with the id="noClick" - to no avail.
$('noClick').observe('click', function(event) {
Event.stop(event);
});
This is the primary function that creates the event
this.DOM.items.forEach((item, pos) => {
// The item's title.
const title = item.dataset.title;
// Show the title next to the cursor.
item.addEventListener('mouseenter', () => cursor.setTitle(title));
item.addEventListener('click', () => {
// Position of the clicked item
this.pos = pos;
this.title = title;
// Start the effect and show the content behind
this.showContent();
// Force to show the title next to the cursor (it might not update because of the grid animation - the item under the mouse can be a different one than the one the user moved the mouse to)
cursor.setTitle(title);
});
});
where 'item' is
this.DOM.grid = this.DOM.el.querySelector('.grid');
// Thr grid items
this.DOM.items = [...this.DOM.grid.children];
// totla number of grid items
this.itemsTotal = this.DOM.items.length;
I've tried to create multiple items
this.DOM.grid = this.DOM.el.querySelector('.grid');
this.DOM.yesClick = this.DOM.el.querySelector('.yes-click');
this.DOM.yesClickTwo = this.DOM.el.querySelector('.yes-click-2');
this.DOM.noClick = this.DOM.el.querySelector('.no-click');
// Thr grid items
this.DOM.items = [...this.DOM.yesClick.children, ...this.DOM.yesClickTwo.children];
this.DOM.itemsNo = [...this.DOM.noClick.children];
this.DOM.allItems = [...this.DOM.noClick.children, ...this.DOM.yesClick.children, ...this.DOM.yesClickTwo.children];
// totla number of grid items
this.itemsTotal = this.DOM.allItems.length;
This works, but messes with the animaton.
Here is the codepen
I feel this is really simple and I'm missing something. Looking to learn, so a push in the right direction or any help would be greatly appreciated!
1. You have multiple elements with the same ID. But ID attribute must be unique.
2. You used $('noClick'), but ID selector would look like #noClick
If you want to mark few elements, use a class and select them like .elementclass. It is possible for element to have multiple classes, separated by space.
Your selector doesn't seem correct so you either need #noClick or .noClick as the selector however you can stop the javascript from bubbling like this :-
$(".noClick").click(function(e) {
// Do something?
e.stopPropagation();
});
UPDATE
I have a jsfiddle showing the issue here: http://jsfiddle.net/waf11s6u/1/ When you type a letter into the search bar, the custom scrollbar attached to the div disappears. The scrollbar may be getting faded out by the code that fades out non-matching words from the div?
~~
I’m creating a custom multi-friend selector for a Facebook game, it looks similar to this: http://tinyurl.com/gus79cf
The user can type into a search bar and any matching friend names appear in the area below.
I’m using a custom scrollbar plugin to design the scrollbar for scrolling down through the list of friends.
This is the plugin’s site: http://manos.malihu.gr/jquery-custom-content-scroller/
Visually the scrollbar is made up of two parts, the first is the track (I’ve drawn the track onto the background image, so it’s not actually part of the Javascript code), and the second part is the icon, the icon is the small image that moves up and down along the track.
The scrollbar works perfectly (meaning that the icon slides up and down correctly), except for one thing, whenever the user types a letter into the search bar the icon disappears, and it only becomes visible again when the search bar is empty.
The div which contains the names & images of friends is created dynamically in Javascript (it's called "mfsForm"). When the user begins typing a name, I have some Javascript that will fade out non-matching friend names & images.
I think that this code is also causing the icon to disappear.
This is the code in question:
// Earlier code here connects to Facebook's API.
// Then get the list of friends for this user with the Graph API
FB.api('/me/invitable_friends?limit=48', function(response) {
var container = document.getElementById('mfs');
// Creating the div "mfsForm" (this will hold the friend names & photos, and is also what the custom scrollbar is applied to.)
var mfsForm = document.createElement('form');
mfsForm.id = 'mfsForm';
mfsForm.className = " mCustomScrollbar mfsForm";
// Iterate through the array of friends object and create a checkbox for each one.
for (var i = 0; i < response.data.length; i++) { //Math.min(response.data.length, 10)
var friendItem = document.createElement('div');
friendItem.id = 'friend_' + response.data[i].id;
friendItem.style.cssText="width:100px; height:100px; padding:7px; color:#FFF;"
friendItem.style.cssFloat="left";
friendItem.innerHTML = '<input type="checkbox" name="friends" value="' + response.data[i].id + '" />';
var img = document.createElement('img');
img.src = response.data[i].picture.data.url;
img.style.cssText = 'width: 70px;height: 70px;'
friendItem.appendChild(img);
var labelName = document.createElement('label');
labelName.style.cssText = 'font-size: 14px;'
labelName.innerHTML = response.data[i].name;
friendItem.appendChild(labelName);
mfsForm.appendChild(friendItem);
}
container.appendChild(mfsForm);
console.log(mfsForm);
$(mfsForm).mCustomScrollbar();
// Create a button to send the Request(s)
var sendButton = document.createElement('div');
sendButton.id = 'sendButton';
sendButton.onclick = sendRequest;
container.appendChild(sendButton);
$("#filter").keyup(function(){
// Retrieve the input field text and reset the count to zero
var filter = $(this).val()//, count = 0;
// Loop through the comment list
$("#mfsForm div").each(function(){
// If the list item does not contain the text phrase fade it out
if ($(this).text().search(new RegExp(filter, "i")) < 0) {
$(this).fadeOut("slow");
// Show the list item if the phrase matches and increase the count by 1
} else {
$(this).show();
//Attempting to fade in the icon here:
$(this).next('.mCSB_dragger_bar').fadeIn("slow");
}
});
})
});
I think that $(this).fadeOut("slow"); is making the scrollbar icon fade out. I've tried to target the icon by referencing its class (mCSB_dragger_bar) and fading it in here:
$(this).next('.mCSB_dragger_bar').fadeIn("slow"); but it's not working.
Any help or suggestions on what I could try to fix this problem would be really appreciated, thank you in advance!
What is the problem?
You do not show normal code to see where your script delete icon and i can say you to force your script to display this icon.
Put to input the code onchange="f()" or onkey pres or other.
And
<script>
function f(){ //$('#icon') the element witch contain icon that disapear
$('#icon').css('visibility','visible').css('display','block');
$('#icon').attr('background','url('/icon.png')')}`
/*$('#parent-of-icon').appendChild(icon );*/
And other depend why the icon disapear.
May be your script delete the icon (html element) then create it.
In this mode the icon will always appear on each key press.
Try $(this).find('.mCSB_dragger_bar').fadeIn("slow"); not $(this).next('.mCSB_dragger_bar').fadeIn("slow");
If element with class name mCSB_dragger_bar exist on $(this) element ( $this -> $("#mfsForm div") -> some div's on element with id=mfsForm) it will find it and show;
NEXT return only one element after $this, may be between $(this) and mCSB_dragger_bar exist another element.
Also try $(this).parent().find('.mCSB_dragger_bar').fadeIn("slow"); if mCSB_dragger_bar and $(this) is on the same doom level
In mozilla, I can select a text and print the selected text using contentWindow.getSelection(). But I am trying to get the underlying html code block for this selected text. Is there any way I can retrieve it?
I need to extract urls and other informations like src, etc. underneath any clickable text that a user selects. I need the code block of its parent node.
Thanks.
Retrieving the HTML should be relatively easy, but it depends on what you are wanting. window.getSelection() returns a selection object. You can use:
window.getSelection().anchorNode to obtain the Node in which the selection begins and
window.getSelection().focusNode to get the Node in which the selection ends.
For instance:
let selection = contentWindow.getSelection();
let firstElement = selection.anchorNode;
let lastElement = selection.focusNode;
What you do once you have the nodes/elements will depend on what it is that you are actually wanting to find. You have not specified that, so manipulating it past finding those nodes would just be a guess as to what you are wanting. For instance, you just might want to find the parent of the anchorNode, verify that it contains the focusNode (firstElement.parentNode.contains(lastElement)) (if not then continue finding the next parent until it does) and use the parent's innerHTML. Alternately, maybe you want to find the first parent element of the anchorNode which contains the focusNode and then use a TreeWalker to walk the DOM tree until you find the anchorNode and start accumulating the HTML until you encounter the focusNode.
Do you have a mouse event listener or something before you do contentWindow.getSelection?
If you do you can get the selected node by doing:
function onMouseUp(event) {
var aWindow = event.target.ownerDocument.defaultView;
// should test if aWindow is chrome area or actually content area
var contentWindow = aWindow.document instanceof Ci.nsIHTMLDocument ? aWindow : null; // i guessed here but testing if its content window is done in some similar way
if (!contentWindow) { return }
// do contentWindow.getSelection im not familiar with the code, if selection exists // check if more then one range selected then get node for each, however im going to assume only one range is selected
var nodeOfFirstRange = event.explicitOriginalTarget
var elementOfNode = nodeOfFirstRange.parentNode;
var htmlOfElement = elementOfNode.innerHTML;
}
Services.wm.getMostRecentWindow('navigator:browser').gBrowser.addEventListener('mouseup');
issue with this code is if user mouses down in content window and then highlights and mouseup while mouse its outside of content window, like on chrome window or even outside the browser (like if the browser window was not in maximum or if user mousedup in taskbar of os etc) so just use this code as a guide
I have two connected sortable lists, #origin and #destination. When you drag and drop from #origin to #destination, I can see that the following events occur in this order:
#origin update
#origin remove
#destination receive
#destination update
However when dragging and dropping within the #origin list, only the #origin update function is executed.
The problem is that when #origin update is executed it looks exactly the same as when dragging and dropping within the same list. In both cases, ui.sender is not set and since it is executed before the remove function is executed, I have no way of setting a temporary variable to say what is happening.
(see this Fiddle and look at the console)
I want to include an ajax call in my update function without it being executed twice. I therefore need a way to differentiate between the #origin update called when dragging from one list to another (so I can basically just return false) and when dragging within the same list.
I thought of getting the ui.position and checking to see if that coordinate is within the boundaries of #origin, but it seems like there has to be a more simple solution.
here is one way you could do it:
Set a flag for each group, origin and destination. Initialize it above the sortable like this:
var updates={origin:false,destination:false};
$( ".config-room-ul" ).sortable({//...
in the update method, add this to the top
update: function(e, ui) {
updates[$(this).attr('id')]=true; //...
now add a handler for the stop event which is fired at the end:
stop:function (e,ui) {
if (updates.origin===true && updates.destination===true)
{
console.log('dragged from one group to another group');
}
else if(updates.origin===true && updates.destination===false)
{
console.log('dragged within origin');
}
else if(updates.origin===false && updates.destination===true)
{
console.log('dragged within destination');
}
//finally, clear out the updates object
updates.origin=false;
updates.destination=false;
}
now the console should show "dragged within origin" or "dragged within destination" if something is dragged inside its own group. it should show "dragged from one group to another group" if you drag to another group.
See the fiddle: http://jsfiddle.net/Wr9d2/3/
PS If you need to determine from which group the drag started and ended when dragging between groups, I think the code is easily editable to do that.
Another way I thought of instead of using the position is to count the number of child elements of the #origin list before and after the drag and comparing them. If they are different then the update function called is from the #origin. You also need to compare the element ID to make sure they match.
First add this before your sortable declaration:
var sender_id = null;
var sender_children = 0;
Then add the following drag start option:
start: function(e, ui) {
sender_id = $(this).attr("id");
// Get number of child elements from the sender. We subtract 1
// because of the placeholder (which adds another child)
sender_children = $(this).children().length - 1;
}
Then in the update function, check if the sender's id matches, ui.sender is null and the number of children for the sender element are different. It should be one less because the element you dragged has been removed. If it is, then skip that one because it is being called from the origin and not the destination.
if ($(this).attr("id") == sender_id
&& ui.sender == null
&& $(this).children().length != sender_children
) {
return true;
}
See it on JSFiddle.
Whilst this does use some of the code from a question I asked yesterday (Dynamically check / uncheck checkboxes in a tree), I feel that this is a slightly different question as I need to add in clearing divs and also slide data in the tree up and down.
I've taken what I learnt yesterday and added in a slider as per this link - http://jsfiddle.net/3V4hg/ - but now I've added clearing divs the tree is not unchecking all the way to the top if the bottom of the tree has no options selected. If you look at the JSFiddle, if you check A and/or B then uncheck it, the parent and grandparent do not uncheck automatically. Also, for some reason that I haven't figured out yet - the slider decides to slide upon clicking the checkbox in the child area (I've also noticed that the toggle image for the region area to display changes when the continent one toggles - haven't tried to solve that as just noticed when adding to JSFiddle).
I'm also thinking that there may be a better way to code the togglers/sliders (since used by more than one kind of toggle, but I'm unsure).
Fiddle: http://jsfiddle.net/3V4hg/2/
I have applied some modifications to your code. Have a look at the fiddle and comments (at the code, and at the bottom of the answer):
$('#delivery_zones :checkbox').change(function(){
$(this).siblings('ul').find(':checkbox').prop('checked', this.checked);
if(this.checked){
$(this).parentsUntil('#delivery_zones', 'ul').siblings(':checkbox').prop('checked', true);
} else {
$(this).parentsUntil('#delivery_zones', 'ul').each(function() {
var $this = $(this);
var childSelected = $this.find(':checkbox:checked').length;
if(!childSelected){
// Using `prevAll` and `:first` to get the closest previous checkbox
$this.prevAll(':checkbox:first').prop('checked', false);
}
});
}
});
// collapse countries and counties onload
$(".country_wrap").hide();
$(".county_wrap").hide();
// Merged two click handlers
$("#delivery_zones").click(function(event){
var root = event.target; // Get the target of the element
if($.nodeName(root, 'input')) return; // Ignore input
else if(!$.nodeName(root, 'li')) {
root = $(root).parents('li').eq(0); // Get closest <li>
}
// Define references to <img>
var img = $('.toggle img', root).eq(0);
// Define reference to one of the wrap elements *
var c_wrap = $('.country_wrap, .county_wrap', root).eq(0);
if(img.attr('src') == "http://uk.primadonna.eu/images/arrow_white_up.gif"){
img.attr('src', 'http://www.prbuzzer.com/images/downarrow-white.png');
c_wrap.slideUp("slow");
} else {
img.attr('src', 'http://uk.primadonna.eu/images/arrow_white_up.gif');
c_wrap.slideDown("slow");
}
});
* I have defined the root to be a <li> element. The first occurrence of the .count(r)y_wrap element should be selected, which is achieved using .eq(0).
Your previous code contained some logical errors, which I have also fixed: $('.toggle img', this) selects every <img> element which is a child of .toggle, which caused the arrows at the end of the tree to toggle too. My solution using event.target is more neater, and allows your example to be extended to even deeper trees.