How to specify multiple selectors within an iframe using jQuery? - javascript

There is not nice HTML structure I need to work with and the list of elements I need to select is within an iframe. The problem is that I am interested just in 2 type of divs within many other divs on same level.
I am able to select such a type from the iframe but just one at time:
$("#someIframe").contents().find(".class a img[src*='type1']")
But I am unable to select both:
$("#someIframe").contents().find(".class a img[src*='type1'], .class a img[src*='type2']") -> does not work
The problem is that I need to select the first one, but I don't know which one is the first one :) something like:
$("#someIframe").contents().find(".class a img[src*='type1'], .class a img[src*='type2']").first()
UPDATE 1:
I have found another way around. I have noticed that those elements I don't want to select contains specific text:
<div>not listed</div>
However, again finding the correct selector would be the problem since I need opposite of this below :)
$("#someIframe").contents().find(".someclass div:contains('not listed')").first()

I have figured it out. Here is the code if anyone needs it in the future:
$("#someIframe").contents().find(".someclass").not($("#someIframe").contents().find(".someclass div:contains('not listed')").parent()).first()
It's not nice, but the markup itself is not nice, so I guess it's fine :)

Related

Select second element by custom data/attirbute

OK. I'm trying to get elements in javascript by CSS selector. To get one by custom element I know is like 'element[custom-name="Literal name"]'.
OK. This works. But now I need to get the second one. I mean I have some elements with the exact custom-name, and for everyone I need to apply a diferent rule (tehere are only 5).
How can I select the other ones? Is posibble select them by CSS?
PS: They are located in random positions, so maybe the first one is the 5 element one time and if I refresh the page it can be the 10 element inside the container.
PS2: No, It's not possible to change the HTML in my case :( . The only code I'm alowed to change is CSS and javascript.
Thanks for reading me! :D
Assuming you can't select specific ones by another, non-order-dependent factor, you can use the pseudo-selector :nth-child. In your case, the complete CSS selector would be element[custom-name="Literal name"]:nth-child(2) - substitute the 2 for any other number as you see fit. Generally it's not the best idea to select only by position in the document, as position may change more often than attributes - but in any case, there's a pure CSS solution!
Note that this only works if the elements you're working with are the only children of a common parent element - if you're looking for the second element that matches that query in general across the entire document, there is no way to do that with a CSS selector. Instead, you can make sure to add a unique class or other differentiating attribute to each element, or simply use querySelectorAll - in that case, you could get the second element using this little snippet: document.querySelectorAll('element[custom-name="Literal name"]')[1].

How to use common js function for two divs containig elements of identical ids?

I have common jQuery function and two div tags. Both div tags have different names but both containing elements of identical ids now i want to use this common Jquery function for them both?
I have implemented common function but it's not working for both.
Here's link to my jsfiddle -jsfiddle.net/xS7zF/1/
In my jsfiddle there are two div tags namely example1 and example2 and both tags have elements of identical ids. Function is working fine for first div but not for second.
please help me to sort out this.
Yeah, under the hood, jQuery selection on an ID will use the Document.GetElementById() function implemented by the browser, which is really fast, but (i guess depending on the browser) will stop after it finds the first element, since ID's should be unique and no further searching is needed after the first one is found.
For instance, rename the divs with id="eb" to class="eb" and you can still target specific elements using $("#example1 .eb") and $("#example2 .eb")
UPDATE:
Using your new Fiddle I created this: http://jsfiddle.net/xS7zF/5/
I cleaned up a lot of code and hopefully you can see what I have done. I changed all elements that appear twice from id to class. Now, when you attach an event to an element using $(".classname").click(), it attaches to all the elements. In the handler function where you set HTML and do your show()/hide(), you don't target a specific element using it's ID, but you find it relative to the element that does the event. You can do this using parent(), parentsUntil(), next(), find(), etc. Check jQuery docs for all possibilities. So for instance, the change-handler attaches to all inputs with name=Assets. But instead of doing $("#b1").show(), I go to the parent of the specific input that fires using $(this).parent(). Then I find the element with a class=".b1", which it will only find the one that is next to this specific input and I set the HTML to just that element.
Since there is another input, the same actions happen when THAT input changes, but instead it finds IT's parent, and finds the element with class=".b1" that is next to IT. So both divs with input are contained since they act on elements relative to itself and not across the document.
For extra fun and to show you how flexible this way of programming is, here is a fiddle with the Javascript-code unchanged, but with the exact same question-div copied 8 times. No matter how many times you repeat this, the same code will act on as many divs as you create since everything works relative. http://jsfiddle.net/xS7zF/7/
Hopefully this helps, the rest is up to you!
ID's must be unique, you should not repeat them. You could replace id with class and in the jQuery function do (".ub").each() or manually referencing the object using eq(x). e.g. (".ub").eq(1).
You shouldn't assign same id's to different elements.
You CAN but you SHOULDN'T. Instead of giving the same id, use class
IDs must be unique, try fix this, change to classes.
You can try something like this:
$("div div:first-child")
instead of
$("#eb")
But depends of the rest of your page code. So, change to classes first and use
$(".eb")
when jQuery / javascript find the first ID it would ignore the rest, please read more about it
http://www.w3schools.com/tags/att_global_id.asp

Show context-menus only when certain elements are clicked

I am kinda stuck with something and I need your help.
I am trying to show context-menus only when a user right-clicks on a certain elements in the page.
I thought I solve this problem by using getElementByClassName(...) and adding an onClick listener to each one of the elements, and when the user clicks on any of them I will then create the context-menus. And then remove the content menu later when everything is done.
Problem is that I don't have the full class names of those elements, all I know that they start with "story".
I am not sure how to go about doing this. Is there a way to use regex and getting all elements with a class name of story? Or is that not possible.
Thanks in advance,
There's this library that allows for regex selectors.
<div class="story-blabla"></div>
$("div:regex(class, story.*)")
However, you may not want to implement a full library. There's another solution:
$('div').filter(function() {
return this.class.match(/story.*/);
})
This will return the objects you want.
You can do this using attribute starts with selector
document.querySelectorAll("[class^=story]")

Jquery .children() not working as expected

I am trying to make a basic captcha module for jQuery. I have a decent start on it, but for some reason .children() doesn't seem to work. See it here: http://jsfiddle.net/pTbeW/
I currently have this:
$(this).children('.captchain-start').hide();
$(this).children('.captchain-show').show();
If I change it to
$('.captchain-start').hide();
$('.captchain-show').show();
it works perfectly. But this solution is less than ideal, because it wouldn't allow two instances of this captcha to be on the same page. I suspect it has to do with the html being set by query, but I'm not sure how. I'm far from a javascript and jQuery expert, but this seemed like a relatively easy thing to do. What am I missing? Do I have tired eyes from looking at it so long? Any help would be appreciated.
Because the '.captchain-*' elements are not children, but are siblings. Try the following:
$(this).nextAll('.captchain-start').hide();
$(this).nextAll('.captchain-show').show();
You should use $(this).nextAll() instead of $(this).children() because the elements you want to hide and show are not children of the a element, but siblings.
See http://api.jquery.com/nextAll/
this
In your click event references the clicked element, which is the element with the class 'captchain-start'. So you do not have to scan for the children, you can use:
$(this)
for the actually clicked element or the element selector instead
instead.

HTML5,draggable and contentEditable not working together

When a draggable attribute is enabled on a parent element(<li>) I cant make contenteditable work on its child element (<a>).
The focus goes on to child element (<a>),but I cant edit it at all.
Please check this sample
http://jsfiddle.net/pavank/4rdpV/11/
EDIT: I can edit content when I disable draggable on <li>
I came across the same problem today, and found a solution [using jQuery]
$('body').delegate('[contenteditable=true]','focus',function(){
$(this).parents('[draggable=true]')
.attr('data-draggableDisabled',1)
.removeAttr('draggable');
$(this).blur(function(){
$(this).parents('[data-draggableDisabled="1"]')
.attr('draggable','true')
.removeAttr('data-draggableDisabled');
});
});
$('body') can be replaced by anything more specific.
If new contenteditable elements are not added in the runtime, one can use bind instead of delegate.
It makes sense that the draggable and contenteditable properties would collide. contenteditable elements, like any text field, will focus on mousedown (not click). draggable elements operate based on mousemove, but so does selecting text in a contenteditable element, so how would the browser determine whether you are trying to drag the element or select text? Since the properties can't coexist on the same element, it appears that you need a javascript solution.
Try adding these two attributes to your anchor tag:
onfocus="this.parentNode.draggable = false;"
onblur="this.parentNode.draggable = true;"
That works for me if I add it to the <a> tags in your jsFiddle. You could also use jQuery if it's more complicated than getting the parentNode.
Note: This is a workaround since I believe the inability for these two functionalities to work together resides in the HTML spec itself (i.e. the not working together thing is intentional since the browser can't determine whether you want to focus or drag on the mousedown event)
I noticed you explicitly set 'no libraries', so I will provide a raw javascript/HTML5 answer
http://jsfiddle.net/4rdpV/26/
This was my crack at it.
First of all, it might be better to include the data in one single localStorage item, rather than scatter it.
storage={
'1.text':'test 1',
'2.text':'test 2'
}
if(localStorage['test']){
storage=JSON.parse(localStorage['test'])
}
this creates that ability, using JSON to convert between object and string. Objects can indeed be nested
I also added (edit) links next to the items, when clicked, these links will transform the items into input elements, so you can edit the text. After hitting enter, it transforms it back and saves the data. At the same time, the list items remain draggable.
After saving, hit F12 in chrome, find the console, and look in the localStorage object, you will see all the data was saved in localStorage['test'] as an Object using JSON.stringify()
I tried my best to design this to be scaleable, and I think I succeeded well enough; you just need to replace the HTML with a container and use a javascript for loop to write out several items, using the iterator of your choice to fill the parameter for edit(). For example:
Say you changed storage to hold "paradigms" of lists, and you have one called "shopping list". And say the storage object looks something like this:
{
"shopping list":{
1:"Milk",
2:"Eggs",
3:"Bread"
}
}
This could render that list out:
for(i in storage['shopping list']){
_item = storage['shopping list'][i];
container.innerHTML+='<li draggable=true><a id="item'+i+'">'+_item+'</a> (edit)</li>'
}
Of course, if you were to edit the structure of the storage object, you would need to edit the functions as well.
The output would look something like this:
Milk (edit)
Eggs (edit)
Bread (edit)
Don't worry about the input elements if that worries you; CSS can easily fix it to look like it didn't just change.
If you don't want the (edit) links to be visible, for example, you can do this in CSS:
a[href="#"]{
display:none;
}
li[draggable="true"]:hover a[href="#"]{
display:inline;
}
Now the edit links will only appear when you hover the mouse over the list item, like this version:
http://jsfiddle.net/4rdpV/27/
I hope this answer helped.
Using html5sortable and newer JQuery events (delegate is deprecated, answer 3 years after initial question), bug still affects Chrome 37. Contenteditable spans and html5sortable seem to play nice in other browsers. I know this is only partially relevant, just keeping documentation on changes I've noticed.
$(document).on('focus', 'li span[contenteditable]', function() {
$(this).parent().parent().sortable('destroy'); // removes sortable from the whole parent UL
});
$(document).on('blur', 'li span[contenteditable]', function() {
$(this).parent().parent().sortable({ connectWith: '.sortable' }); // re-adds sortable to the parent UL
});

Categories