As of 2016-02-26, there will be no more posts for this blog. s/blog/pba/
Showing posts with label jQuery. Show all posts

Recently, I had a thought about the Disqus loading. Instead of loading by a button, automatically loading when comments section (about) comes into view might be a nice idea. But I dropped the idea as I thought about my browsing behavior, most of time, I would scroll down to the bottom of page. If so, simply loading the Disqus is a better method in my opinion.

Anyway, I still made a quick sample code:

The important part is the detection:
if ($w.scrollTop() + $w.height() >= $t.offset().top - $w.height()) {
    inview = true;
}
$w = $(window) and $t = $('#target'). When the bottom of view area reaches target's top with a margin $w.height(), then it's detected. Much like sticking an element at top, this is as simple as that, nothing much to explain.

You can do many things with such detection, such as infinite scroll (which I don't like), loading images or external resources, or loading Disqus comments to reduce bloating.

This only demonstrates the Y-axis and trigger-from-above detection. In practice, it should only be triggered once if the state has not reverted back. It's not hard to do, only I don't need it, so the post ends here.

As you may have noticed that there are some marks on the right edge, which are the "Right-side navigation" as what I'd call it. They serve as like Table of Contents.

For now, it's three levels:
  1. Post title,
  2. First heading level in the post, and
  3. Second heading level.
Here is a screenshot:


I hope this will encourage people to go through the headings and may be interested in reading more if you don't have to scroll down a page in order to skim over the content, but simply hover their cursors over these marks.

At first, I was planning a list-like at top-right corner as opposite to the settings at top-left corner. It would look like an automatic Table of Content, which I'd wanted for long time, but never started to write it.

However, I got this idea that visualizes the logical position of the heading in the page on the right side.

I wrote first changeset for post titles only, because I was afraid that subheadings might crowd the navigation. Later, subheadings were added in second changeset and the navigation looks fine, not over-crowded at all.

I didn't add a switch for this new navigation yet, I might or not. If you think this navigation doesn't look good, please complain in comment, so I can be motivated to add a switch for it for you to shut it off.

When you click on one mark, the page will scroll to the heading smoothly, not just jump to it directly. This reminds me of my jQuery jk navigation plugin, which also uses smoothing scroll and was installed briefly on this blog long time ago. I seriously want to add it back, so visitors can not only click on the right-side navigation with mouse, but also use keyboard to navigate.

I believe that I am not the first one to implement such navigation style, if you know someone has implemented similar feature for a page, or as a plugin or script, please post the link.

I think this it worth to make it as a jQuery plugin, if you would like to use it, please do let me know. I may create one based on these code and generalize it for broad usages.

I have only tested it on Firefox, so if you see any bugs, I am sure you will, please leave a comment with what browser you are using. Also, any feedback are welcome!

Updated on 2012-05-21T09:40:04Z

It has problem with Google Chrome and since no one even commented about this navigation, I decided to remove this right-side navigation. However, you may still see it in this page.

I found this jquery-lifestream plugin on GitHub and its fairly easy to use, here is a quick example of my blog feed, GitHub, and Google Code updates:

It already has support for more 20 or 30 services (its a long list, didnt count), and you can write your template for layout which fits in with your design. The following code is the setup, you can see I add blog post author name for the output:

$("#lifestream").lifestream({
  limit: 15,
  list: [
    {
      service: "blogger",
      user: "yjlv",
      template: {
        posted: '${author.name} posted <a href="${origLink}">${title}</a>'
      }
    },
    {
      service: "github",
      user: "livibetter"
    },
    {
      service: "gcode",
      user: "http://code.google.com/feeds/u/115422682039760465813/updates/user/basic"
    }
  ]
});

You can even add more services without adding to the original code. For example, it does not support Google Code but you can see I have the updates from my Google Code account listed above. The updates on Google Code uses Atom feed, but jquery-lifestream doesnt support it. But thats fine, because you can easily expand jquery-lifestream:

(function($) {
  $.fn.lifestream.feeds.gcode = function( config, callback ) {

    parseFeed = function( input ) {
      var output = [], list, i = 0, j;
      if(input.query && input.query.count && input.query.count > 0) {
        list = input.query.results.entry;
        j = list.length;
        for( ; i<j; i++) {
          var item = list[i];

          output.push({
            url: config.user,
            date: new Date( item.updated ),
            config: config,
            html: item.title.content
          });
        }
      }
      return output;
    };

    $.ajax({
      url: $.fn.lifestream.createYqlUrl('select * from atom where url="'
        + config.user + '"'),
      dataType: 'jsonp',
      success: function( data ) {
        callback(parseFeed(data));
      }
    });

  };
})(jQuery);

You can rewrite the parser, do some advanced tasks, such as filter or extraction of some data from feed. For example, you can use jQuery to parse the html and extract the image, so it can be used as thumbnail. If you know about JavaScript, you can enrich the results easily.

I think this can be used in many cases and it doesnt have to be your contents. You can add some blogroll, photo collection of multiple Flickr account, or updates from all kinds of social networkings for a project. Or just a gadget for your blog, which gathers your photos, tweets, etc. It can keep your blog or webpage cleaner.

In this blog, a CSS class .wrapper is used for limiting the maximal width of post content, set to 640 pixel. I make sure every image will be resized to 640 pixel if either larger or smaller than 640 pixel in width using JavaScript. For YouTube videos, I always choose embedding code for 640px. I do these to have a better visual presentation, having a clear edges, stuff wouldnt poke out like a mess.

Note

This blog is no longer using this and width has changed to 800px. (2015-12-25T04:36:41Z)

But I wonder, though I am not planning using the result I would have, if its possible that I could unwrap the wrapper?

Basically, I use jQuery to (re)calculate margins for each element with .unwrapper, so those element would be located and increased the width by only using margins.

Got unwrapped yet?

A standard asynchronous Google Analytics tracking code would look like:

<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-#######-#']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>

I didnt like how they look, so I decided to re-write with jQuery:

if (window._gat) {
  _gat._getTracker("UA-#######-#")._trackPageview();
  }
else {
  $.ajaxSetup({cache: true});
  $.getScript(('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js', function () {
      _gat._getTracker("UA-#######-#")._trackPageview();
      });
  $.ajaxSetup({cache: false});
  }

It checks if there already is a Google Analytics script included. The script is the same and reusable, some websites might have multiple tracking code being executed. There is no need to create many <script>. If the script isnt included, then it loads it using jQuerys getScript(). Within the callback, it logs the pageview. You might also want to put _gat... into a try {} catch.... The older non-asynchronous tracking code does that.

You can also see it uses $.ajaxSetup() to set up cache use. By default, jQuery appends a timestamp like _=1234567890 as a query parameter after the URL of the script you want to load, that timestamp is called cachebuster, which causes web server sends same content to client even the content isnt modified. I discovered this behavior when I was adding new code on this blog.

In normal request, your web browser will check with server. If server returns 304, then browser will use the ga.js it already has in hand. With cachebuster, that wont happen, browser receives same content again and again. Using ajaxSetup() is to ensure cache is in use.

The only part I dont like in my code is how it decides the script link, it doesnt look pretty to me.

1Let it slide!

See what between here moving and here
See what between here moving and here

I made this script because someone posted a gig on Craiglist. Start to them!

I had thought about a jQuery plugin for jk binding navigation for a while and I finally wrote it. This jQuery plugin actually is my first plugin.

Note

I have removed jknav from this blog, please check out the demo page, instead. (2010-09-20)

Here is what you can try to see how it works on this blog: Press h and l to navigate between posts; j and k to navigate between sections.

I have the following code installed:

<script src="http://lilbtn.yjl.im/js/jquery/jquery.jknav.min.js"></script>
<script>
$('h3').jknav();
$.jknav.init({up: 'l', down: 'h', reevaluate: true});

$('h3,h4,h5,h6').jknav(null, 'all-headers');
$.jknav.init({name: 'all-headers', reevaluate: true});
</script>

It actually has two navigation settings, jk and hl.

Basically, you use jQuery to select what element should be navigated to by calling jknav(), then init() to set up some variable that plugin needs and the keyup event handler, done. Thats all. You can call jknav() as many times as your like, and the selectors dont have to be the same, you can mix tag names. This plugin will sort them by their position on page, top to bottom, left to right.

You can read the documentation and check out this demo page, which uses callback.

This chart only counted (egrep -v '^$' file | wc -l) the uncompressed JavaScript files, jquery-*.js, (jquery.)effects.*.js and (jquery.)ui.*.js. (localization, demo, test, etc. files are not included) The release dates may not be accurate because some are hard to find out. You can see there are three data lines for jQuery UI from chart, they need specific jQuery versions to work, which are noted within parentheses, e.g. UI (1.3) means those jQuery UI releases require jQuery 1.3.x.

Half a day ago, I suddenly had a very strong feeling while showering, so I tweeted this:

How I Code HTML on Seasons:<em>Spring</em> <big>Summer</big> <strong>Autumn</strong> <div style="visibility:hidden"><del>Winter</del></div>.

Now I came up with this (wait for 10 seconds, or reload page to see it again):

Four Seasons: Spring, Summer, Autumn, Winter.
<div id="seasons" style="background-color:#444;border:2px solid #888;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;padding:5px;">Four Seasons: <em style="color:#4c4">Spring</em>, <big style="color:#f00">Summer</big>, <strong style="color:#ea4">Autumn</strong>, <span style="color:#cee">Winter</span>.</div>

<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('jquery', '1');
function kill_slowly() {
        var t = $('#seasons span del').text();
        if (t.length > 0)
                $('#seasons span del').text(t.substring(0, t.length - 1));
        if ($('#seasons span del').text())
                setTimeout(kill_slowly, 1000)
        else {
                $('#seasons span').remove();
                $('#seasons').html($('#seasons').html()
                        .replace(/Four/, '<em>Three</em>')
                        .replace(/Spring/, 'Spring (Something new!)')
                        .replace(/Summer/, 'Summer (Hot, Beach, Bikinis! XD)')
                        .replace(/Autumn/, 'Autumn (Falling leaves, beautiful!)')
                        .replace(/, \./, '. <span style="color:#f00;font-style:italic;">Awesome!</span>'));
                }
        }
google.setOnLoadCallback(function(){
        setTimeout(function() {
                $('#seasons span').wrapInner('<del></del>').append(' (Freaking f**king cold!)');
                setTimeout(function() {
                        $('#seasons span').fadeOut(6000);
                        kill_slowly();
                        }, 1000);
                }, 10000);
        });
</script>

Really dont like Winter much.