Get mangled content from jQuery .html()

jQery .html() can be used to get the contents of any element in html document. I just found that .html() does not return the exactly same content of selected element. The following are two examples,

& is replaced with &

& is replaced with & in URLs. This is not a bad thing, actually, I just learned that to avoid problems with both validators and browsers, we should always use & in place of & when writing URLs in HTML, so then if you have parameter named copy,  for example, &copy=3, then it will not be translated to ©=3 in some browsers. (Read this article for details)

URL is encoded in Firefox

I found jQuery .html() returns URL encoded contents in Firefox (By this time, I only test this in Firefox 13.0.1.) For example, if the content contains

<a href="http://www.caiapps.com/?abc=!^{}<>">special</a>

in Firefox, .html() will return the following result,

<a href="http://www.caiapps.com/?abc=%21%5E%7B%7D%3C%3E">special</a>

Not sure this is a bug of Firefox, or something need to be fixed in jQuery library, .html() doesn’t encode URL in Chrome and IE. This may not cause issue in most case, but in my case, I use html() to generate some dynamic content, which including some tags like, {$abc}, if it’s mangled, then it will be replaced with correct content. So I have to decode url in the content got from .html() using unescape() function as the following,

var escaped_html = unescape($(this).html())

If you also want to keep & untouched, then you will have to use regexp, because unescape() does not replace &amp to &. It will be like the following,

var full_escaped_html = unescape($(this).html()).replace(/\&/g, "&");

Hope this helps.

jQuery open external link in new window

I hate every links on a web page to open in a new window like most Chinese websites do. But I also believe it should be a standard that the external link should open in a new window. Because if you don’t do that, after visitors click an external link, they will jump out of your website, and then the only way to go back to your website is clicking back button. If they close the external page, they will have trouble to go back to your page.

However when you write a post, it’s very easy to forget to make external link open in a new window. Here I would like to share a snippet that help you fix this problem.

$('#content a:not(has(img))').filter(function() {
  return this.hostname && this.hostname !== location.hostname;
}).attr('target', '_blank').after(' <img src="/images/external.png" alt="external link" />');

Note

  • this snippet also adds a standard external png image (like wiki site does) after a link.
  • the fix only applies to any non image <a> tag in #content DIV,  but it should be easy to change to what you want.
  • the code assumes there is no mixed use of www and non-www host, otherwise, you would need to modify the condition of ‘this.hostname !=location.hostname’. For example, in your article, you use www.example.com for a link, and someone visitor your website using example.com, which will cause your internal link becomes an external link.

Demo

MMG

406 error to retrieve jquery.cookie.js file

In a project, I need to use jquery.cookie.js file. It’s weird that this file is already uploaded to the server, and I just could not retrieve it, but got 406 Error. The following is the message I got from Firefox:

Not Acceptable
An appropriate representation of the requested resource /wocai/jquery.cookie.js could not be found on this server.
Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.

Cannot figure out why, but after I changed the file name to jquery_cookie.js, it fixed the problem. Could the server is not happy file the filename?

Slick HTML Encoder and Decoder

In these couple days, I created a online tool to help me do HTML Encoding and Decoding.  If you search HTML Encode in Google you probably find many online tools already do these similar things.

So why redo this?

There are two reasons:

  • Most of those online tools have pool interface design and have many ADs on the page, which is kindof disturbing when you are using it.
  • I made it on my own server, which is easier to access.

What’s new?

Yes, I tried to make it different. It not just looks clean, but also generating encoded/decoded output without page refresh by using Ajax and jQuery.

Check it out here. Please let me know if you see any problems or have any comments.

Facebox no display problem in Chrome

In my previous post, I provide a solution to allow all anchor tags being loaded in a Facebox, which I call it "Stick on Facebox". And I just found there is a bug either on Facebox or Chrome causes the hidden element’s content could be displayed in the Facebox.

See the code in the following,

<style>
.hidden { display:none;}
</style>

<div class="hidden" id="hide1">
I am a hidden div
</div>

<a href="hide1" rel="facebox">View Hidden Content</a>

Note that for the hidden div, instead of using inline css, <div style="display:none;">, I define a class named hidden with the same style. When click "View Hidden Content" link, we expect the content of hide1 will be displayed in the facebox. (of course, we need to attached facebox function to anchor where rel="facebox"). It works fine in IE6+ and Firefox, however, in the Chrome, it displays nothing. Looks like Chrome think the div (#hide1) should be hidden because it has class defined as display as none. However, if we define div (#hide1) using inline css, it would fix the problem.

<div style="display:none"; id="hide1">
I am a hidden div
</div>

Is it odd? Anyway, if you have multiple hidden divs, like the example in the Stick on Facebox, you can still use class hidden, but code will be like this,

<div class="hidden"><!--use this hidden wrap-->
<div id="hide01">I am hidden div #1!<br /><a href="#hide02" class="infinite-find">Click here</a> to find hidden div #2</div>
<div id="hide02">I am hidden div #2!<br /><a href="#hide03" class="infinite-find">Click here</a> to find hidden div #3</div>
<!--more ...-->
</div>

Stick on Facebox

I wrote a short tutorial to explain “how to click a link inside Facebox and load it on the same Facebox” a few days ago. Today I will extend this solution more, eventually, you will see the anchor tags are bound continually, so they can stick on Facebox.

Updates

  • 09/01/2010 – fixed no display problem on Chrome. Note script has been updated in Download folder, but not in this article.
  • 11/18/2010 – Updated function to support external page, which answers Aaron Layton‘s question in the comment.
  • 01/11/2011 – Added new function to display select box (dropdown menu) on facebox

Initial Version

First let’s see the method shown at Facebox official Guide, which attachs Facebox function on any anchor tag after document ready.

<a href="#info" rel="facebox">first link<a>
<!--div 1-->
<div id="info">
Some info here and also some link<br />
<a href="#another-info" rel="facebox">another link</a>
</div>
<!--div 2-->
<div id="another-info">
another info here
</div>

<script type="text/javascript">
jQuery(document).ready(function($) {
  //attached facebox onLoad on all anchors with rel=facebox
  $('a[rel*=facebox]').facebox()
})
</script>

Ok. when you click the “first link”, because it was attached facebox function, it’s open the “info” div in the facebox. And there is another link in the “info” div, which was also attached facebox function, so you expect to view the content of “another-info” div in the facebox, too. However, it does not work, because the content of “info” div is dynamically generated to be viewed in the facebox, and the facebox function attached to anchor tag inside “info” div does not persist. One solution as I explained in the previous post is attaching the facebox function “on fly.”  See the following,

<p><a href="#hide1" id="start">Start to find some</a> hidden divs</p>
<div class="hidden" id="hide1">

I am hidden div #1!<br />

<a href="#hide2" class="find all">Click here</a> to find hidden div #2

</div>
<div class="hidden" id="hide2">

I am hidden div #2.<br> No more hidden div :-(

</div>
<script type="text/javascript">
jQuery(document).ready(function($){
        $("#start").click(function(){
                jQuery.facebox({div:'#hide1'});
                $('.find').click(function(){
                        var glink = $(this).attr('href');
                        jQuery.facebox({div: glink});
                        return false;
                });
        });

})
</script>

In the example above, you see that we don’t attach facebox function onLoad, but control it programmatically. We use jQuery.facebox({div:’#hide1′} to pass the div content into the facebox, and at the same time, we attach the same event handler to the anchor tag, so then when you click the link on the facebox, which can be loaded on the same facebox. But this is not a elegant solution. Says there is another link in the secondary facebox (i.e., div “hide2” in this case), then it will not be open in the facebox, because you know, the event handlers could not persist in the way we bind it.

So the much better solution will be using recursive binding technique. Here is what the code looks like,

<p><a href="#hide01" class="infinite-find">Start infinite finding</a> and have fun!</p>

<div class="hidden" id="hide01">
I am hidden div #1!<br />
<a href="#hide02" class="infinite-find">Click here</a> to find hidden div #2
</div>
<div class="hidden" id="hide02">
I am hidden div #2!<br />
<a href="#hide03" class="infinite-find">Click here</a> to find hidden div #3
</div>
<div class="hidden" id="hide03">
I am hidden div #3!<br />
<a href="#hide04" class="infinite-find">Click here</a> to find hidden div #4
</div>
<div class="hidden" id="hide04">
I am hidden div #4!<br />
<a href="#hide05" class="infinite-find">Click here</a> to find hidden div #5
</div>
<div class="hidden" id="hide05">
I am hidden div #5 (last one).<br /><a href="#hide02" class="infinite-find">Start Over :-)</a>
</div>

<script type="text/javascript">
function find_hidden(){
        $('.infinite-find')
        .unbind('click')
        .bind('click', function() {
                var glink = $(this).attr('href');
                jQuery.facebox({div: glink});
                find_hidden();
        });
}

jQuery(document).ready(function($){
//infinite find - really stick in facebox
        find_hidden();

})
</script>

As you see, I created a recursive function find_hidden() to unbind and rebind event recursively, so facebox function is attached continually, which I called “Stick on facebox”.

Display External Page

Updated on 11/18/2010
As you see in the previous version above, I used the following code to display the content of hidden div on the facebox,

jQuery.facebox({div: glink});

In order to display an external page, we can use ajax method, so just need to slightly update the code to support both as the following,

function find_hidden(){
   $('.infinite-find')
   .unbind('click')
   .bind('click', function() {
      var glink = $(this).attr('href');
//if glink match #, then we say it's div, otherwise, it's an external page.
//of course, you may make this smarter as you need.
      if(glink.match(/^#/)){
                jQuery.facebox({div: glink});
      }else{
         jQuery.facebox({ajax: glink});
      }
      find_hidden();
      return false;
   });
}

And then in the HTML, you can do this,

<p><a href="external1.html" class="infinite-find">
Start infinite finding on EXTERNAL PAGE</a> and have fun!</p>

And the external page will be something like this,

<h3>Exteranl Page 01</h3>
<div>I am EXTERNAL page #1!<br />
<a href="external2.html" class="infinite-find">Click here</a> to find EXTERNAL page #2
<div>
<script type="text/javascript">
   //infinite find - really stick in facebox
   find_hidden();
</script>

Note that you have to call find_hidden function again in the external page, because the one called in the start up page does not bind the click function to the links on the external page.

Display Select Box

Updated on 01/11/2011
As a request from one of my reader, I added this function to display select box (I also call it dropdown menu) on facebox, and the select result will be display on the facebox without leaving facebox. Basically, it uses another ajax call inside the facebox. Nothing complicated. :-) Just need to add the following code in a external page.

<h3>Quotes of the Day</h3>
<div>
Select a quote:
    <select id="link">
       <option value="drop1.html">Quote1</option>
       <option value="drop2.html">Quote2</option>
       <option value="drop3.html">Quote3</option>
    </select>
<div>
<div id="innerajax" style="border:1px solid #2297CA; padding:5px; margin-top:10px;">
You can't build a reputation on what you are going to do.<br />
<b>- Henry Ford</b>
</div>

<script type="text/javascript">
   $('#link').change(function(){
      var innerlink = $("#link option:selected").val()
      $("#innerajax").load(innerlink);
   });
</script>

Check out the updated Demo. And feel free to leave comments if you have any questions.

Open Link Within Facebox

Facebox is a great jQuery plugin, which I have used in many projects. The official Facebox guide is a good start, but it may not cover all you need.  Also, some functions are missing in original Facebox plugin, which you may need in your real work. So I would like to share you some Facebox tips.

OK. The first tip is how to “Open Link Within Facebox and load in the same Facebox”?

Let’s start with a hidden div. If you already read the official Facebox guide, you probably know that the plugin allows you to open a hidden div on a pretty Facebox. For example,

<div id="secret" style="display:none;">
I am a hidden div, you cannot see me until you click "dig" link.
<a class="see" href="#your-new-link">guesswhat?</a>
</div>
<a href="#secret" id="fb-pop">dig</a>

You see there is a link in the hidden div.  By default, when you click that link, it will open in a new window. If you want to load it in the same Facebox. Here is a solution,

$(document).ready(function(){
   $('#fb-pop').click(function(){
      var divid = $(this).attr('href');
      jQuery.facebox({div: divid});
      $('.see').click(function(){
      var glink = $(this).attr('href');
      jQuery.facebox({image: glink});
      return false;
      });
   });
});

Check out Demo right here: dig

Note:

  1. The main point is that you need to bind click event to the <a> link with Facebox on fly.
  2. The <a> link with Facebox, can be another hidden div in the page, or ajax, or image, etc.
  3. The <a> link in hidden div must use ‘class’, not ‘id’ (Not sure why), in this example, I use <a class="see">.