Page 1 of 2 12 LastLast
Results 1 to 10 of 17

Thread: deconstructing jquery

  1. #1
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default deconstructing jquery

    hi all,
    yes, I have only myself to blame for "learning" javascript by learning jquery. you can slap me later.

    I've got a function here; I'm trying to rewrite it in standard javascript (it's for a bookmarklet and I'm pretty sure jquery won't be loaded on the page where it is to be used).
    Code:
    function(){
    	var can = $('.class1');
    	$(can).live(
    		'click'
    		,function(){
    			var txt = $('.class2 textarea').val();
    			alert(txt);
    		}
    	);
    }
    So far, Ive got this:
    Code:
    function(){
    	var can = document.getElementsByClassName('class1');
    	can.addEventListener(
    		'click'
    		,function(){
    			var txt = document.getElementsByClassName('class2').getElementsByTagName('textarea').nodeValue;
    			alert(txt);
    		}
    		,false
    	);
    }
    It doesn't like when I call getElementsByTagName - it's "not a function" (I guess that means it's not a valid method of the nodelist that getElementsByClassName returns?). can anyone help me out with how to approach this?

    I need to get the contents of the <textarea> that's inside the element with class="class2". (also, if nodeValue is not the way to get those contents, please LMK.)

    --------------------------------
    Second issue (less important): I'm aware that IE < 9 doesn't support getElementsByClassName. How can I find them, in that case?

    --------------------------------
    thanks, everyone : )
    Last edited by traq; 07-27-2011 at 04:40 PM.

  2. #2
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I'm not sure where you're getting that error. One obvious issue is that with:

    Code:
    var can = document.getElementsByClassName('class1');
    can is a nodeList. You cannot addEventListener to a nodeList, only to a single element.

    Are there/can there be more than one element with that class? I know there could be, but in your scenario is there likely to be. If not, use id - in ordinary javascript it's much easier to deal with.

    Otherwise you have to loop through the nodeList performing the same action on each member. In this case adding the event listener to each one.

    Also the implications of 'live' are different than addEventListener. Using 'live' means that all elements that are currently in the DOM that qualify and any that might arrive later. Using addEventListener only affects a single element and it must currently be in the DOM.

    Oh and the equivalent of .val() in ordinary javascript is .value, not .nodeValue.

    The way your jQuery code is constructed implies that there's probably only one element with a class name of class1, and probably only one with the class of class2, which probably has only one child that's a textarea. If that's all true, and they're all already there, you can specify them via their index in their respective nodeLists (ByTagName is also a nodeList), and we could do:

    Code:
    function(){
    	var can = document.getElementsByClassName('class1')[0];
    	can.addEventListener(
    		'click'
    		,function(){
    			var txt = document.getElementsByClassName('class2')[0].getElementsByTagName('textarea')[0].value;
    			alert(txt);
    		}
    		,false
    	);
    }
    Other things to consider -

    If the page has jQuery on it your code can use it.

    How many bookmarklets have you used/written? I've never seen a bookmarklet constructed like this. Are you sure your jQuery one could work even if jQuery were on the page?

    IE < 9 doesn't support addEventListener.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  3. #3
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    Hi John,

    thanks for the clarifications. as a result of learning jQuery, I'm not as familiar as I ought to be with regular javascript properties and methods.

    I've used a few bookmarklets, and written a few from tutorials. This is my first experiment without a model.

    yes, the jQuery version works (not in the format I posted, of course, but like so:
    Code:
    <a href="javascript:(function(){var can=$('.class1');$(can).live('click',function(){var txt=$('.class2 textarea').val();alert(txt);});})();">Bookmarklet</a>
    as to your other questions:

    The page in question will never include jQuery. I don't control the page, either; so IDs are out (too bad - as you say, they're very quick and easy. I've already got this working on a mockup using IDs).

    it's actually quite possible that there will be at least one other .class1 element on the page - but only one will be available to be clicked at any given time.

    there is usually only one instance of .class2 (I've never found two on the same page, but I don't know for certain). it always shares a common ancestor with .class1, but they're never siblings.

    the textarea is several generations below the .class2 element, and it's always the only textarea in that element.

    I think they're all always at static positions - but I'd have to do more checking to be sure - so finding them by index is a possibility. (I was hoping I wouldn't have to - it seems fragile to me...? I guess only if their positions vary.)

    I'm aware of the differences between jQuery's .live() and regular event listeners, but I don't know how to construct the latter in ordinary js. .live() is preferable, since there's lots of generated content I'm working with.

  4. #4
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Because of the exigencies of that difference (live vs addEventListener) and other differences between generic javascript and jQuery, a slightly different approach seems desirable:

    Code:
    <a href="javascript:(function(){
    	var re1 = /\bclass1\b/, re2 = /\bclass2\b/;
    	function func(e){
    		e = e || event;
    		var t = e.target || e.srcElement, t1, t2, t3, pn;
    		while(t.parentNode){
    			if(!t1 && re1.test(t.className)){
    				t1 = t;			
    			}
    			t = t.parentNode;
    			pn = t.getElementsByTagName('*');
    			for(var i = 0; i < pn.length; ++i){
    				if(!t2 && re2.test(pn[i].className)){
    					t2 = pn[i];
    				}
    			}
    		}
    		if(t1 && t2 && (t3 = t2.getElementsByTagName('textarea')[0])){
    			alert(t3.value);
    		}
    	}
    	if (window.addEventListener){
    		document.addEventListener('click', func, false);
    	}
    	else if (window.attachEvent){
    		document.attachEvent('onclick', func);
    	}
    })();">Bookmarklet</a>
    That's cross browser, doesn't require ByClassName, or standards mode, and acts like 'live' because it listens for clicks on the document and then evaluates/works off of what was clicked.

    If you have trouble following it, read it over a few times.

    Still having trouble, ask.

    It checks to see if what was clicked has the class1 and then finds the class2 if any that's a child of a common ancestor (all tags on a page have at least one common ancestor, this stops at the nearest one as you seemed to indicate would be good), and then alerts the value of that class2's first if any textarea.

    Sound about right?
    Last edited by jscheuer1; 07-28-2011 at 01:34 PM. Reason: code efficiency
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  5. #5
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    ...wow.

    it looks good. totally backwards from the approach I had, but straightforward and very simple. I'll see if it works as expected.

    thanks a bunch!
    Edit: well, it didn't quite work yet, but it's because I didn't have the correct dom. I'm going to try to work things out a little more. I think there may also be other scripts (on the live target page) that are canceling the event I want before it bubbles up to my listeners. We'll see what happens.

    thanks, in any case, your code was very helpful!

    Last edited by traq; 07-28-2011 at 04:41 AM.

  6. #6
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Could I have a link to a page you're trying to run this bookmarklet on?
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  7. #7
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    yeah, sure.

    I'm messing around with twitter. don't know if you have an account or not, but you'd need one to see what I'm working with: I want to see if I can capture the contents of an @-reply when I cancel sending it.

    it's just for fun/ education, so I would like to try and figure out as much of it as possible, but obviously I do need some guidance.

    I think part of the issue might be in the 1,000 lines of other javascript on the page (and that's just the inline scripts!). if this doesn't work out, it's no big deal: as I said, I'm just trying to learn from it.

    here's the relevant section of the dom
    (on the fourth line is div.twttr-dialog-close, which is the click event I'm listening for; and further down is the textbox.twitter-anywhere-tweet-box-editor, which I want to get the contents of when canceling):
    HTML Code:
    <div class="twttr-dialog-container" style="visibility: hidden;">
    	<div type="reply" style="width: 500px; height: auto; left: 454px; top: 225px;" class="twttr-dialog draggable ui-draggable">
    		<div class="twttr-dialog-header">
    			<h3>Reply to @meyerweb</h3> <div class="twttr-dialog-close"><b>×</b></div>
    		</div>
    	    <div class="twttr-dialog-inside">
    			<div class="twttr-dialog-body clearfix">
    		        <div class="twttr-dialog-content">
    			        <div class="tweet-box">
          					<div class="tweet-box-title">
    					    	<h2>Reply to @meyerweb</h2>
    					    </div>
    						<div class="text-area">
    						    <div class="text-area-editor twttr-editor">
    						    	<textarea style="width: 452px; height: 56px;" class="twitter-anywhere-tweet-box-editor"></textarea>
    						    	<ul style="width: 468px; top: 73px; left: 0px; visibility: hidden;" class="autocomplete-container"></ul>
    						    </div>
    						</div>
    						<div class="tweet-button-container">
    							<span class="geo-control">
    								<a href="#" class="geo-location">
    									<span original-title="" class="geo-icon">&nbsp;</span>
    									<span style="" class="geo-text ellipsify-container">
    										<span style="" class="content"></span>
    									</span>
    									<span style="display: none; visibility: visible;" class="geo-dropdown-icon">&nbsp;</span>
    								</a>
    							</span>
    							<div class="tweet-button-sub-container">
    								<img src="/images/spinner.gif" class="tweet-spinner" style="display: none;">
    								<span style="opacity: 0;" class="tweetbox-counter-tipsy"></span><input class="tweet-counter" value="140" disabled="disabled">
    								<a href="#" class="tweet-button button">Tweet</a>
    							</div>
    						</div>
    					</div>
    				</div>
    			</div>

  8. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I'm not on Twitter and have no intention of joining for this.

    But I would want to know if the code in your post is in an iframe. If it is we would need to get to the iframe document in our code.

    I'd also like to know if the twitter-anywhere-tweet-box-editor is really an ordinary textarea. Like are you looking at 'view source' or at a DOM inspector? There's a good chance that the editor is enhanced and changed via javascript and that the element twitter-anywhere-tweet-box-editor may no longer exist in the DOM.

    One way to answer both questions would be to use Firefox with the Developer Tools extension installed. Use its 'view source' > 'view generated source'.

    Then you will see if the elements you are looking for are even there in the generated source (the actual DOM).

    Use its DOM Inspector to try to find them as well. It has a find element by clicking on it, and a find element by attribute. If they're in an iframe, you can walk up the tree to the iframe, find its name if any or at least its position in the window.frames collection.

    You could also experiment with the code:

    Code:
    <a href="javascript:(function(){
    	function func(e){
    		alert('here');
    	}
    	if (window.addEventListener){
    		document.addEventListener('click', func, false);
    	}
    	else if (window.attachEvent){
    		document.attachEvent('onclick', func);
    	}
    })();">Bookmarklet</a>
    Click on your button or whatever it is. If it doesn't alert, the event isn't bubbling, or has been removed, or the element is in an iframe.

    If it does alert try:

    Code:
    <a href="javascript:(function(){
    	function func(e){
    		e = e || event;
    		var t = e.target || e.srcElement, t1, t2, t3, pn;
    		alert(t.tagName);
    		alert(t.parentNode.innerHTML);
    		alert(t.className);
    	}
    	if (window.addEventListener){
    		document.addEventListener('click', func, false);
    	}
    	else if (window.attachEvent){
    		document.attachEvent('onclick', func);
    	}
    })();">Bookmarklet</a>
    If those work, tell me what they alert.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  9. #9
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    Quote Originally Posted by jscheuer1 View Post
    I'm not on Twitter and have no intention of joining for this.
    of course; I wouldn't expect you to. in fact I'd object if you were signing up solely for this.

    Quote Originally Posted by jscheuer1 View Post
    But I would want to know if the code in your post is in an iframe. If it is we would need to get to the iframe document in our code.

    I'd also like to know if the twitter-anywhere-tweet-box-editor is really an ordinary textarea. Like are you looking at 'view source' or at a DOM inspector? There's a good chance that the editor is enhanced and changed via javascript and that the element twitter-anywhere-tweet-box-editor may no longer exist in the DOM.
    no, it's not in an iframe; yes, my excerpt is from the actual DOM ("view generated source").

    I tried your bookmarklet and there was no response from the "close" dialog div. it alerts on most clicks, up until I click on "reply" - which opens a modal reply window - from then until I cancel the reply, nothing alerts.

  10. #10
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I'm not saying that this one does, but modal windows can contain iframes.

    • Is the cancel button inside the modal?

    • Does the modal have an overlay that dims out the rest of the page?

    • If so, does clicking on the overlay produce the alert?
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •