<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rommel Santor&#039;s Clog &#187; jQuery</title>
	<atom:link href="https://rommelsantor.com/clog/category/jquery/feed/" rel="self" type="application/rss+xml" />
	<link>https://rommelsantor.com/clog</link>
	<description>my exploits and misadventures in programming</description>
	<lastBuildDate>Thu, 04 Feb 2016 12:56:01 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.0.38</generator>
	<item>
		<title>AngularJS Scroll to Top for New Pages on Single-Page-App</title>
		<link>https://rommelsantor.com/clog/2015/10/20/angularjs-scroll-to-top-for-new-pages-on-single-page-app/</link>
		<comments>https://rommelsantor.com/clog/2015/10/20/angularjs-scroll-to-top-for-new-pages-on-single-page-app/#comments</comments>
		<pubDate>Wed, 21 Oct 2015 07:53:35 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ngRoute]]></category>
		<category><![CDATA[SIngle Page App]]></category>
		<category><![CDATA[SPA]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=444</guid>
		<description><![CDATA[As promised in my last post, I&#8217;m going to try to keep updating with things I learn on my trek down the long road to Angular-ville. As far as I could tell, there isn&#8217;t much info about the issue I was facing online, so either I&#8217;m doing something wrong (and if I am, for heaven&#8217;s [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As promised in my last post, I&#8217;m going to try to keep updating with things I learn on my trek down the long road to Angular-ville. As far as I could tell, there isn&#8217;t much info about the issue I was facing online, so either I&#8217;m doing something wrong (and if I am, for heaven&#8217;s sake, don&#8217;t just sit there; please tell me!) or there aren&#8217;t as many people concerned with what I felt was a noticeable UX flaw in single page apps (SPA). To try to make clear my explanation of the issue, I&#8217;ll just walk through some steps that an end-user might experience with an SPA and how the page responds by default:</p>
<ol>
<li>User loads the home page. Angular fetches the template and inserts it into the ng-view.</li>
<li>User scrolls down the page a bit, say 600px.</li>
<li>User clicks a link to another page. Angular fetches the requested page&#8217;s template and inserts it into the ng-view, but the browser stays scrolled 600px, so the user doesn&#8217;t actually see the content they loaded.</li>
<li>User clicks the browser&#8217;s back button and sees again the content they were at before clicking the link.</li>
</ol>
<p><span id="more-444"></span>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">// <![CDATA[

// ]]&gt;</script></div>
</p>
<p>The quick, dirty, incomplete &#8220;solution&#8221; to this might be to simply detect when the route is changing and auto-scroll to the top of the window in all cases. However, if we did that, upon clicking back in step 4 above, the browser would scroll back to the top of the page instead of landing the user back where they came from. So what we need is a real solution that will auto-scroll to the top of the page when a *new* page is loaded, but allow the browser to restore the scroll position for any page that was navigated away from.</p>
<p>My first thought was to just store the most recently viewed page and detect a new page load, compare the new page to the most recent page, and if it&#8217;s different, scroll to the top. This doesn&#8217;t work, however, when the user clicks back more than one page.</p>
<p>My second thought was to just store the history of pages viewed and only scroll to top if the newly loaded page is not in that history. This, however, doesn&#8217;t take into consideration that a user may go back in the browser then go forward again, and if they go forward to a page they just came from, we don&#8217;t want that scrolling away on them.</p>
<p>No, what we need is to store the history of all pages loaded both backward and forward. Below is the solution I implemented which stores the current page, a stack for all backward pages, and another stack for all forward pages. When the location changes, the new URL is compared to the top of the backward stack and the forward stack. If it&#8217;s either one, the matching element is popped and we leave the scroll position where it is. If it&#8217;s neither, the user must be linking forward into a new path, so the forward stack is emptied.</p>
<p>Overall the solution works pretty nicely. The only less-than-usual thing to be aware of is that if you click a link that takes you backward or forward one page (i.e., instead of clicking the back button back to the homepage you click a &#8220;home&#8221; link), it will look to the code like you used your back button and leave the scroll position unchanged, but I actually like that behavior. It makes the whole SPA thing feel much more solid.</p>
<p>[<a href="https://github.com/rommelsantor/ng-bwdfwdscroll" target="_blank">GitHUB &raquo;</a>]</p>

<pre class="js:nocontrols:nogutter">&lt;script&gt;
// first thing's first; initialize the app
var app = angular.module('yourAppName', ['ngRoute']);// '

// use $rootScope since this is for application-wide behavior
app.run(function _bwdFwdDetect($rootScope, $location) {
  $rootScope.path = $location.path();// stores only the current page being viewed
  $rootScope.pathBwd = [];// stores up to the last page viewed before the current one
  $rootScope.pathFwd = [];// stores starting with the page viewed before coming back to the current one

  // detect that the location is about to change
  $rootScope.$on('$locationChangeStart', function(event) {
    var newPath = $location.path();// take note of the new path (using path instead of url is good)

    // grab the last backward page for comparison
    var bwd = !$rootScope.pathBwd.length ? null :
      $rootScope.pathBwd[$rootScope.pathBwd.length - 1];

    // grab the last forward page for comparison
    var fwd = !$rootScope.pathFwd.length ? null :
      $rootScope.pathFwd[$rootScope.pathFwd.length - 1];

    // if the new page is the last backward page, assume the user went "back"
    if (bwd == newPath) {
      // it's no longer the last backward page, so remove it
      $rootScope.pathBwd.pop();

      // and push into the forward stack the page we're just leaving to go backward from
      $rootScope.pathFwd.push($rootScope.path);
    }
    // the new page is the last page we came backward from, assume the user went "forward"
    else if (fwd == newPath) {
      // it's no longer the last forward page, so remove it
      $rootScope.pathFwd.pop();

      // and push into the backward stack the page we're going forward away from
      $rootScope.pathBwd.push($rootScope.path);
    }
    // we didn't go back or forward; assume it's a new forward trail being started
    else if ($rootScope.path != newPath) {
      // remember the page we're leaving as our last backward page
      $rootScope.pathBwd.push($rootScope.path);

      // empty out our forward stack since we're now starting a wholly new forward path
      $rootScope.pathFwd = [];

      // this is what it's all about; scroll to the top of the freshly-loaded page
      $('html,body').animate({ scrollTop: 0 }, 'slow');
    }

    // now that we're done with our comparisons, we can remember our new current page
    $rootScope.path = newPath;
  });
});
&lt;/script&gt;</pre>

<p><script type="text/javascript">// <![CDATA[
//< ![CDATA[
$("pre").attr({name:'code'});
// ]]&gt;</script></p>
<p>Of course this whole &#8220;new page detection&#8221; thing I&#8217;m doing doesn&#8217;t only have to be used to scroll to the top of the page. There could be any number of things you might want to do depending on whether the route is changing backward or forward or down a new path.</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2015/10/20/angularjs-scroll-to-top-for-new-pages-on-single-page-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AngularJS Auto-Focus Input After Router Template is Loaded in SPA</title>
		<link>https://rommelsantor.com/clog/2015/10/14/angularjs-auto-focus-input-after-router-template-is-loaded-in-spa/</link>
		<comments>https://rommelsantor.com/clog/2015/10/14/angularjs-auto-focus-input-after-router-template-is-loaded-in-spa/#comments</comments>
		<pubDate>Wed, 14 Oct 2015 10:46:16 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[autofocus]]></category>
		<category><![CDATA[ngRoute]]></category>
		<category><![CDATA[SIngle Page App]]></category>
		<category><![CDATA[SPA]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=422</guid>
		<description><![CDATA[It&#8217;s been just a little while (oh, only about 3.5 years) since I last published any new posts here. Too busy. At the moment I&#8217;ve been delving head-first into some modern frameworks like AngularJS and Bootstrap, so I plan to document things I learn along the way that I think will help other developers also new [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s been just a little while (oh, only about 3.5 years) since I last published any new posts here. Too busy.</p>
<p>At the moment I&#8217;ve been delving head-first into some modern frameworks like AngularJS and Bootstrap, so I plan to document things I learn along the way that I think will help other developers also new to these technologies who might come up against some of the same issues or who might just find interesting the things I&#8217;m discovering.</p>
<p>Without further ado, this is my first of such posts, which is a little more advanced than just starting to learn everything from scratch, but I do plan to back-track and cover more in future posts the basics of using AngularJS.</p>
<p><span id="more-422"></span>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">// <![CDATA[

// ]]&gt;</script></div>
</p>
<p>If you&#8217;re developing a Single Page Application (SPA) with Angular, you may find that loading an HTML fragment with a form input that should be auto-focused might not work. Assuming you&#8217;ve already set up ngRoute to dynamically control the routing of your application, the simplest way I came up with to set focus on an input after ensuring the HTML template is fully loaded is to define a callback for <code>$routeChangeSuccess</code> which is invoked after the route has finished changing. The best place to respond to that event is in a run block, since it&#8217;s an application-wide action we&#8217;re taking. The trick is that the DOM may still not be ready for you to set focus at that point, but setting focus inside a $timeout will ensure the $digest loop has ended.</p>
<p>The other, more obvious decision was to ensure the input I want to auto-focus has the &#8220;autofocus&#8221; attribute so it can be targeted using a simple jQuery selector. Below is a bit of sample code demonstrating what I just described with comments, so hopefully it&#8217;s all pretty obvious to you (and it <i>should</i> be if you&#8217;re using Angular yourself).</p>
<p>[<a href="https://github.com/rommelsantor/ng-dynautofocus" target="_blank">GitHUB &raquo;</a>]</p>

<pre class="js:nocontrols:nogutter">&lt;script&gt;
// first thing's first; initialize the app
var app = angular.module('yourAppName', ['ngRoute']);// '

//... do other things like set up your routing (not covered here)

// set up a Run Block
app.run(function _forceAutofocus($rootScope, $timeout) {

  // tell Angular to call this function when a route change completes
  $rootScope.$on('$routeChangeSuccess', function() {
    // we can't set focus at this point; the DOM isn't ready for us

    // instead, we define a callback to be called after the $digest loop
    $timeout(function(){
      // once this is executed, our input should be focusable, so find (with jQuery)
      // whatever is on the page with the autofocus attribute and focus it; fin.
      $('[autofocus]').focus();
    });
  });

});
&lt;/script&gt;</pre>

<p><script type="text/javascript">// <![CDATA[
//< ![CDATA[
$("pre").attr({name:'code'});
// ]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2015/10/14/angularjs-auto-focus-input-after-router-template-is-loaded-in-spa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fixing the IE7 &lt;Button&gt; Submit Value</title>
		<link>https://rommelsantor.com/clog/2012/03/12/fixing-the-ie7-submit-value/</link>
		<comments>https://rommelsantor.com/clog/2012/03/12/fixing-the-ie7-submit-value/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 18:22:52 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[attribute]]></category>
		<category><![CDATA[iesucks]]></category>
		<category><![CDATA[internet explorer]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=334</guid>
		<description><![CDATA[If you&#8217;ve ever used &#60;BUTTON&#62; tags in your HTML forms, you&#8217;ve probably noticed that there are a couple of problems with them in IE7 and older. For starters, clicking a BUTTON does not cause its form to be submitted. This means that a user will never be able to submit the form by clicking it. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;ve ever used <code>&lt;BUTTON&gt;</code> tags in your HTML forms, you&#8217;ve probably noticed that there are a couple of problems with them in IE7 and older.</p>
<p>For starters, clicking a BUTTON does not cause its form to be submitted. This means that a user will never be able to submit the form by clicking it. Furthermore, if you are using JavaScript including jQuery to trigger a callback upon form submit, that callback will never be fired.</p>
<p><span id="more-334"></span>
<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
That problem is easy enough to fix by making all BUTTON elements trigger form submit, but the second problem which is a tad more difficult to work around is that IE7 will submit the incorrect value of the BUTTON because it uses the innerHTML of the pair of &lt;BUTTON&gt;&lt;/BUTTON&gt; tags rather than the value=&#8221;&#8221; attribute. Consider the following form:</p>
<pre>
&lt;form method="post" action=""&gt;
  &lt;!-- ... your form fields go here ... --&gt;

  &lt;button name="proceed" value="save"&gt;Update Record&lt;/button&gt;
  &lt;button name="proceed" value="undo"&gt;Cancel&lt;/button&gt;
&lt;/form&gt;
</pre>
<p>The easiest fix, which might be your best option, would be to simply replace those BUTTON elements with INPUT elements:</p>
<pre>
  &lt;input type="submit" name="proceed" value="Update Record"/&gt;
  &lt;input type="submit" name="proceed" value="Cancel"/&gt;
</pre>
<p>Again, this is a simple fix, and if it satisfies your requirements, you should definitely stick with it. The problems with this, however, are:</p>
<ol>
<li>You may be dealing with legacy or third-party code and you don&#8217;t want to go fumbling through thousands of lines of someone else&#8217;s code to change their HTML. (This could also break other parts of the system that make assumptions about the fields being of type BUTTON or having a specific value attribute.)</li>
<li>The other issue is that you cannot specify an arbitrary value for the fields because the value attribute also doubles as the user-friendly display value.</li>
</ol>
<p><br/>So, to tackle both of our issues, we&#8217;ll need to bind a click handler to every BUTTON on a page contained within a FORM element. We can do this with jQuery by using the following code:</p>
<pre name="code" class="js:nocontrols:nogutter">
$(document).ready(function(){
  // use live() to handle dynamically added buttons (pre jQuery v1.7)
  $("form button").live('click',function(){
    var f = $(this).get(0).form;

    if (typeof(f) !== 'undefined') {
      if (this.type &#038;&#038; this.type != 'submit')
        return;

      if (this.name) {
        this.trueName = this.name;
        this.name = '';
      }

      $("input[type='hidden'][name='"+this.trueName+"']", f).remove();

      if (typeof(this.attributes.value) !== 'undefined')
        $(f)
          .append('<input type="hidden" name="'+this.trueName+
            '" value="'+this.attributes.value.value+'"/>');

      $(f).trigger('submit');
      return false;
    }
  });
});
/*
Note: As of jQuery v1.7, live() has been deprecated. You can replace
that line above with the following if you're using the latest jQuery:
  $("form").on("click", "button", function(){
*/
</pre>
<p>Note that we don&#8217;t want this code to be executed in other browsers than IE7 and older, so you should put it into a file, let&#8217;s call it <b>ie7.js</b>, and use Microsoft&#8217;s conditional comments in your HTML file to import it only if the user is using a version of Internet Explorer before version 8:</p>
<pre>
&lt;!--[if lt IE 8]&gt;
&lt;script type="text/javascript" src="ie7.js"&gt;&lt;/script&gt;
&lt;![endif]--&gt;
</pre>
<p>Now, if you&#8217;re interested, let&#8217;s consider how that code works. It will cause any click of a BUTTON element contained within a FORM element to trigger the callback we defined. The callback does two important things:</p>
<ol>
<li>It <i>appends</i> a hidden INPUT element to the FORM using the name of the clicked BUTTON and its real value attribute (rather than the display label).</li>
<li>It triggers the submit event on the FORM element, so any callbacks you&#8217;ve bound on form submission will get executed.</li>
</ol>
<p><br/>Side note: Fetching the actual &#8220;value&#8221; attribute can seem a tricky thing to figure out. If you&#8217;re just trying to use $button.attr(&#8216;value&#8217;) you&#8217;ll always get the button label. Instead, we use the &#8220;attributes&#8221; value of the element.</p>
<p>That should be all you need to get your BUTTON elements working properly in IE7.</p>
<p>As an added bonus, you may want to add a handler to submit your form when the user presses enter while focused on an entry field. To do so, you can use this to trigger the click event on the first non-disabled button in the form:</p>
<pre name="code" class="js:nocontrols:nogutter">
$(document).ready(function(){
  $("form").on("keypress", "input,select", function(e){
    if (e.keyCode == 13)
      $("button:not(disabled):first", this.form).trigger('click');
  });
});
</pre>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('html:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2012/03/12/fixing-the-ie7-submit-value/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>jQuery Placeholder Fallback</title>
		<link>https://rommelsantor.com/clog/2011/08/01/jquery-placeholder-fallback/</link>
		<comments>https://rommelsantor.com/clog/2011/08/01/jquery-placeholder-fallback/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 16:36:15 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[HTML5]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[attribute]]></category>
		<category><![CDATA[degradation]]></category>
		<category><![CDATA[fallback]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[placeholder]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=209</guid>
		<description><![CDATA[One of the handy new features for &#60;input&#62; elements in HTML5 is the &#8220;placeholder&#8221; attribute. If you&#8217;re unfamiliar with this attribute, it allows you to pre-populate a text input with instructions which disappear when the element receives focus or there is any entry in the element. For example, if you had a field prompting a [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>One of the handy new features for &lt;input&gt; elements in HTML5 is the &#8220;placeholder&#8221; attribute. If you&#8217;re unfamiliar with this attribute, it allows you to pre-populate a text input with instructions which disappear when the element receives focus or there is any entry in the element.</p>
<p>For example, if you had a field prompting a user to enter their username, the placeholder text might be &#8220;Enter your username here.&#8221; With the introduction and support of the &#8220;placeholder&#8221; attribute, all that would be required is the use of an input tag like &lt;input type=&#8221;text&#8221; placeholder=&#8221;Enter your username here.&#8221;/&gt; and the browser will automatically display your text whenever there is no entry in the field and it does not have the keyboard focus.</p>
<p>The only problem is that older web browsers (and even those that are not-so-old, such as IE8) lack support for placeholders, so a standalone solution is required. After contemplating a couple of different fallback implementations, I decided that for my requirements, an extremely simple implementation would be best.</p>
<p><span id="more-209"></span>Other people have designed jQuery plugins mainly in one of two ways: 1) use the input&#8217;s own value to display the placeholder text when there is no user entry, and 2) float the placeholder text in front of the input.</p>
<p>Option 1 seems like the most obvious solution, but after brief contemplation, it is obviously a very sloppy one considering that overriding the input value means you&#8217;d have to design special handling to carry the true user entry. It also mucks things up that the input might be of type &#8220;password&#8221; which means you can&#8217;t just set the placeholder text as its value, since it will just show up obscured. Furthermore, if the input has a &#8220;maxlength&#8221; attribute that is shorter than the length of your placeholder text, you&#8217;d have to work around that as well. And as far as styling goes, if you wanted your placeholder text to appear differently than the input text, you&#8217;d need to also keep track of the styles of both. Clearly, a complete solution this isn&#8217;t.</p>
<p>Option 2 seems to be the much better implementation. Unfortunately, most all such solutions I&#8217;ve been able to find out there seem to be poorly designed, overlooking several key requirements for half-decent functionality. For example, they ignore the fact that the browser window might be resized (in which case the placeholder needs to move with the input) or the input might become hidden (in which case the placeholder should also be hidden).</p>
<p>And finally, here is the solution I came up with. You should be able to just drop it into your own page as-is, or minify it first if you&#8217;d like. (It&#8217;s a bit bloated here for readability and documentation.)<br />

<pre class="js:nocontrols:nogutter">&lt;script type="text/javascript"&gt;
$(document).ready(function(){// wait until the DOM is ready
  $(function(){// encapsulate our variables into their own scope
    // test if HTML5 placeholder is supported; if so, quit
    var el = document.createElement('input');
    if ('placeholder' in el)
      return;

    // traverse all inputs with a placeholder attribute
    $("input[placeholder],textarea[placeholder]").each(function(){
      var $ip = $(this),// the input itself (in a jQuery object)
          tx = $ip.attr('placeholder');// placeholder text

      // create a label and a span within it
      var $lb = $('<label></label>'),
          $sp = $('<span class="placeholder">'+tx+'</span>').appendTo($lb);

      // the label surrounds the input
      $lb.insertBefore($ip).append($ip);

      // try getting the input's size
      var w = $ip.width(),
          h = $ip.height();

      // if it fails, it's likely because the input is not visible
      if (!w || !h) {
        // clone the input and make it have size/shape without showing it
        var $clone = $ip.clone().appendTo('body').css({
          position : 'absolute',
          visibility : 'hidden',
          display : 'block'
        });

        // fetch the correct size (hopefully)
        w = $clone.width();
        h = $clone.height();

        $clone.remove();
      }

      // copy the position, size, and font into the
      // placeholder text's span
      $sp.css({
        position : 'absolute',
        display : 'block',
        width : w+'px',
        height : h+'px',
        lineHeight : $ip.css('line-height'),
        paddingLeft : $ip.css('padding-left'),
        paddingTop : $ip.css('padding-top'),
        marginLeft : $ip.css('margin-left'),
        marginTop : $ip.css('margin-top'),
        fontSize : $ip.css('font-size'),
        fontWeight : $ip.css('font-weight'),
        overflow : 'hidden',
        cursor : 'text'
      });

      // in MSIE 7 the text is vertically misaligned
      if ($.browser.msie &amp;&amp; parseInt($.browser.version) &lt;= 7)
        $sp.css({marginTop:parseInt($sp.css('margin-top'))+2+'px'});

      // if the input is hidden or shown, so should the placeholder be
      $ip.bind('hide', function(){ $sp.hide(); });
      // when showing, ensure the text is the right size
      $ip.bind('show', function(){
        $sp.show().css({
          width:$ip.width()+'px',
          height:$ip.height()+'px'
        });
      });

      // if the input is starting out hidden or there is a default value in
      // the input already, hide the placeholder
      if (!$ip.is(':visible') || $ip.val().length)
        $sp.hide();

      // when input gets focus, hide the placeholder and
      // when we leave the input, if it has no user entry
      // show the placeholder
      $ip.focus(function(){ $sp.hide(); });
      $ip.blur(function(){ if ($(this).val() == '') $sp.show(); });

      // if the placeholder is focused, send focus to the input
      $sp.focus(function(){ $ip.focus(); });
    });

    // override jQuery.hide() to trigger the 'hide' event
    var hide = $.fn.hide;
    $.fn.hide = function() {
      $(this).trigger('hide');
      return hide.apply(this, arguments);
    };

    // override jQuery.show() to trigger the 'show' event
    var show = $.fn.show;
    $.fn.show = function() {
      $(this).trigger('show');
      return show.apply(this, arguments);
    };
  });
});
&lt;/script&gt;</pre>
<br />
To style the placeholder text, just use CSS selector .placeholder. Keep in mind that if you are specifying any style attributes that have been assigned in the JS above, you must include !important in your CSS for the style to take effect.</p>
<pre class="css:nocontrols:nogutter">
.placeholder { color: #bbb; margin-top: 5px !important; }
/* you should use it alongside, and identically to, your style rules for HTML5
placeholder text, which as of this writing can be done in Mozilla and Webkit
browsers as follows: */
::-webkit-input-placeholder { color: #bbb; margin-top: 5px !important; }
/* single-colon for older Mozilla */
:-moz-placeholder { color: #bbb; margin-top: 5px !important; }
/* double-colon for newer Mozilla */
::-moz-placeholder { color: #bbb; margin-top: 5px !important; }
</pre>
<p>
<div style="float: left; margin: 0 10px 10px 0;"><script type="text/javascript">// <![CDATA[
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
// ]]&gt;</script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">// <![CDATA[

// ]]&gt;</script></div>
<br />
Three notes about my implementation:</p>
<p>1) I could obviously make it into a plugin, but for my purposes, I&#8217;m just using it as-is.</p>
<p>2) I opted to override hide() and show() in jQuery. This might not be preferable and could possibly conflict with any other overrides of those same functions that might be present in your scripts. If this is an issue, you can just remove them.</p>
<p>3) The issue with some inputs is they may start out hidden when the page is loaded. If so, the width/height will not be known. To help mitigate this issue, we clone the input and make it take shape so we can determine its size. This helps, but it can still be inaccurate when the size of the input depends on CSS specific to its hierarchy (because we&#8217;re appending the clone to &#8220;body&#8221;, not to the input&#8217;s parent, who might also be non-visible due to some ancestor).</p>
<p>For example, if the CSS for your input is something like:</p>
<pre class="css:nocontrols:nogutter">#some-panel { display: none; }
#some-panel .some-box input { width: 500px; }</pre>
<p>Then we&#8217;ll clone the input, append the clone to &#8220;body&#8221;, and apply its width to the placeholder text. But since the CSS width depends on the input being a descendant of #some-panel and then .some-box, the width of our clone will very certainly not be the 500px we&#8217;re after.</p>
<p>The complete solution is: when showing the container of the input, always explicitly call something like <code>$("#some-panel .some-box input[placeholder]").show()</code> to trigger our input&#8217;s show() event, which triggers its placeholder&#8217;s show() event, which in turn adjusts the text to match the input&#8217;s size. It&#8217;s not elegant, but it works.</p>
<p>As always, if you encounter any issues or have any questions. Please comment below.<br />
<script type="text/javascript">// <![CDATA[
//< ![CDATA[
$("pre").attr({name:'code'});
// ]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/08/01/jquery-placeholder-fallback/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Fancy Opts jQuery Plugin &#8211; Custom Radio and Checkbox Inputs</title>
		<link>https://rommelsantor.com/clog/2011/03/16/fancy-opts-jquery-plugin-custom-radio-checkbox-inputs/</link>
		<comments>https://rommelsantor.com/clog/2011/03/16/fancy-opts-jquery-plugin-custom-radio-checkbox-inputs/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 20:57:47 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[checkbox]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[radio button]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=164</guid>
		<description><![CDATA[I was in need of a quality jQuery plugin that would allow me to customize radio buttons and checkboxes. After a bit of googling, I was only able to find offerings that weren&#8217;t fully featured. Specifically, they lacked graceful degradation, required custom HTML, and/or just functioned far too much unlike a native input. As is [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I was in need of a quality jQuery plugin that would allow me to customize radio buttons and checkboxes. After a bit of googling, I was only able to find offerings that weren&#8217;t fully featured. Specifically, they lacked graceful degradation, required custom HTML, and/or just functioned far too much unlike a native input.</p>
<p>As is usually the case, I couldn&#8217;t find what I needed so I decided to create it myself, and so the Fancy Opts plugin was born. It allows you to simply create flexible and completely unique radio button and checkbox inputs.<span id="more-164"></span></p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>I compiled the info, download, and demo info here: <a href="http://rommelsantor.com/jquery/fancyopts" title="Fancy Radio Checkbox Opts jQuery Plugin">Fancy Opts jQuery Plugin</a>. It&#8217;s really simple to use, degrades gracefully, and acts very much like a traditional input.</p>
<p>If you have any comments, suggestions, or problems with the plugin, please feel free to let me know!</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/03/16/fancy-opts-jquery-plugin-custom-radio-checkbox-inputs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>TH Float jQuery Plugin &#8211; Fixed THEAD and TFOOT</title>
		<link>https://rommelsantor.com/clog/2011/03/03/th-float-jquery-plugin-fixed-thead-tfoot-table/</link>
		<comments>https://rommelsantor.com/clog/2011/03/03/th-float-jquery-plugin-fixed-thead-tfoot-table/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 18:39:07 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[tables]]></category>
		<category><![CDATA[tfoot]]></category>
		<category><![CDATA[thead]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=156</guid>
		<description><![CDATA[I recently found myself in need of an elegant, simple solution allowing users to know which column in a table contained which value once the table header has scrolled out of view. A quick google lead me to believe that no such plugin for jQuery currently exists. I did find a few table-centric plugins that [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I recently found myself in need of an elegant, simple solution allowing users to know which column in a table contained which value once the table header has scrolled out of view.</p>
<p>A quick google lead me to believe that no such plugin for jQuery currently exists. I did find a few table-centric plugins that (maybe) include the kind of functionality that I wanted, but nothing looked to provide just what I had in mind. So, I started working on the plugin myself.</p>
<p>I call the plugin TH Float, but it could also aptly be named Sticky Table TH or Fixed THEAD / TFOOT. What it does is make the &lt;thead&gt; or &lt;tfoot&gt; of a table remain floating in view at the top or bottom, respectively, of the scrollable container until the table is completely out of view.<span id="more-156"></span></p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>I&#8217;ve thrown together a simple info page and demo: <a href="http://rommelsantor.com/jquery/thfloat" title="Fixed THEAD jQuery Plugin">TH Float jQuery Plugin</a>. It&#8217;s really simple to use and from my tests works identically and flawlessly in (most?) all browsers (though, interestingly, I did discover <a href="http://rommelsantor.com/clog/2011/03/02/ie8-crash-inline-block-scroll-dom-append/">an obscure bug in IE8</a> while creating the demo page).</p>
<p>If you have any comments, suggestions, or problems with the plugin, please feel free to let me know!</p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2011/03/03/th-float-jquery-plugin-fixed-thead-tfoot-table/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Dynamic Drop-Down Navigation Menu Like Wired.com&#8217;s</title>
		<link>https://rommelsantor.com/clog/2010/04/24/dynamic-drop-down-navigation-menu-like-wired-com/</link>
		<comments>https://rommelsantor.com/clog/2010/04/24/dynamic-drop-down-navigation-menu-like-wired-com/#comments</comments>
		<pubDate>Sun, 25 Apr 2010 04:14:42 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[drop down]]></category>
		<category><![CDATA[dynamic]]></category>
		<category><![CDATA[menu]]></category>
		<category><![CDATA[navigation]]></category>
		<category><![CDATA[pop open]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=89</guid>
		<description><![CDATA[A friend recently asked me for a tip on how to create a dynamic pop-up menu like the one used on the main navigation bar of Wired.com. It&#8217;s a pretty typical implementation of a menu that pops open when the user hovers over a navigation tab, but I thought I&#8217;d share the solution I came [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>A friend recently asked me for a tip on how to create a dynamic pop-up menu like the one used on the main navigation bar of Wired.com. It&#8217;s a pretty typical implementation of a menu that pops open when the user hovers over a navigation tab, but I thought I&#8217;d share the solution I came up with.</p>
<p>This is a screenshot of what the menu currently looks like at Wired.com:<br />
<img class="aligncenter size-full wp-image-92" title="Wired.com Navigation Menu" src="http://rommelsantor.com/clog/wp-content/uploads/2010/04/wired-menu.png" alt="" width="654" height="234" /><br />
<span id="more-89"></span><br />
And this is a screenshot of the menu I created:<br />
<img class="aligncenter size-full wp-image-93" title="My Menu Like Wired.com's" src="http://rommelsantor.com/clog/wp-content/uploads/2010/04/my-wired-menu.png" alt="" width="436" height="168" /></p>
<p>I just used a bit of straightforward CSS and jQuery JavaScript to get it done. Below is the code and a functional demo for your viewing pleasure. Admittedly it&#8217;s not the most elegant solution, but it suffices and provides the bare essentials that can be tweaked to suit your liking.</p>
<h2>CSS</h2>

<pre class="css:nocontrols:nogutter">
#navbar {
  width: 100%;
  height: 25px;
  background: #000;
}

#navbar &gt; ul {
  list-style: none;
}

#navbar &gt; ul &gt; li {
  float: left;
  display: inline-block;
}

#navbar &gt; ul &gt; li &gt; a {
  display: block;
  color: #fff;
  padding: 5px 20px;
  text-align: center;
}

#navbar &gt; ul &gt; li &gt; a:hover, #navbar &gt; ul &gt; li &gt; a.open {
  background: #888;
}

#navbar .dropdown {
  display: none;
  position: absolute;
  margin-top: -2px;
  background: #fafafa;
  border: 3px solid #aaa;
  padding: 5px;
  padding-left: 0;
}

#navbar .dropdown ul {
  list-style-type: none;
  display: inline-block;
  float: left;
  margin: 0 0 0 5px;
  padding: 0;
}

#navbar .dropdown ul li {
  border-bottom: 1px solid #aaa;
  margin: 0;
  padding: 0;
}

/* would use :last-child but IE doesn't recognize it */
#navbar .dropdown ul li.last {
  border: 0;
}

#navbar .dropdown ul li a {
  display: block;
  min-width: 100px;
  padding: 3px 5px 3px 10px;
  margin: 1px 0;
  font-weight: normal;
  font-size: 0.85em;
}

#navbar .dropdown ul li a:hover {
  background: #eee;
}
</pre>

<h2>HTML</h2>

<pre class="html:nocontrols:nogutter">
&lt;div id="navbar"&gt; 
  &lt;ul&gt; 
    &lt;li&gt; 
      &lt;a href="#"&gt;Apple&lt;/a&gt; 
      &lt;div class="dropdown"&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column A #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column B #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
      &lt;/div&gt; 
    &lt;/li&gt; 
    &lt;li&gt; 
      &lt;a href="#"&gt;Banana&lt;/a&gt; 
      &lt;div class="dropdown"&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column A #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column B #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
      &lt;/div&gt; 
    &lt;/li&gt; 
    &lt;li&gt; 
      &lt;a href="#"&gt;Cherry&lt;/a&gt; 
      &lt;div class="dropdown"&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column A #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column B #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
      &lt;/div&gt; 
    &lt;/li&gt; 
    &lt;li&gt; 
      &lt;a href="#"&gt;Durian&lt;/a&gt; 
      &lt;div class="dropdown"&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column A #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column B #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
      &lt;/div&gt; 
    &lt;/li&gt; 
    &lt;li&gt; 
      &lt;a href="#"&gt;Elephant&lt;/a&gt; 
      &lt;div class="dropdown"&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column A #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column A #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
        &lt;ul&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #1&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #2&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #3&lt;/a&gt;&lt;/li&gt; 
          &lt;li&gt;&lt;a href="#"&gt;Column B #4&lt;/a&gt;&lt;/li&gt; 
          &lt;li class="last"&gt;&lt;a href="#"&gt;Column B #5&lt;/a&gt;&lt;/li&gt; 
        &lt;/ul&gt; 
      &lt;/div&gt; 
    &lt;/li&gt; 
  &lt;/ul&gt; 
&lt;/div&gt;
</pre>

<h2>jQuery JavaScript</h2>

<pre class="js:nocontrols:nogutter">
$("#navbar &gt; ul &gt; li &gt; a").mouseover(function(){
  $("#navbar &gt; ul &gt; li &gt; a").each(function(){
    $(this).removeClass('over open');
    $(this).next().removeClass('over').hide();
  });

  $(this).addClass('over open');
  $(this).next().show();
});
$("#navbar &gt; ul &gt; li &gt; a").mouseout(function(){
  var a = $(this);
  a.removeClass('over');
  setTimeout(function(){
    if (a.hasClass('over') || a.next().hasClass('over')) return;
    a.removeClass('open');
    a.next().hide();
    }, 1000);
});
$("#navbar &gt; ul &gt; li &gt; div.dropdown").mouseover(function(){
  $(this).addClass('over');
});
$("#navbar &gt; ul &gt; li &gt; div.dropdown").mouseout(function(){
  var a = $(this);
  a.removeClass('over');
  setTimeout(function(){
    if (a.hasClass('over') || a.prev().hasClass('over')) return;
    a.prev().removeClass('open');
    a.hide();
    }, 1000);
});
</pre>


<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<div style="clear:left"></div>

<h1>Demonstration</h1>

<style type="text/css">
#navbar {
width: 100%;
height: 25px;
background: #000;
}

#navbar > ul {
list-style: none;
}

#navbar > ul > li {
float: left;
display: inline-block;
}

#navbar > ul > li > a {
display: block;
color: #fff;
padding: 5px 20px;
text-align: center;
}

#navbar > ul > li > a:hover, #navbar > ul > li > a.open {
background: #888;
}

#navbar .dropdown {
display: none;
position: absolute;
margin-top: -2px;
background: #fafafa;
border: 3px solid #aaa;
padding: 5px;
padding-left: 0;
}

#navbar .dropdown ul {
list-style-type: none;
display: inline-block;
float: left;
margin: 0 0 0 5px;
padding: 0;
}

#navbar .dropdown ul li {
border-bottom: 1px solid #aaa;
margin: 0;
padding: 0;
}

#navbar .dropdown ul li.last {
border: 0;
}

#navbar .dropdown ul li a {
display: block;
min-width: 100px;
padding: 3px 5px 3px 10px;
margin: 1px 0;
font-weight: normal;
font-size: 0.85em;
}

#navbar .dropdown ul li a:hover {
background: #eee;
}
</style>
<div id="navbar">
<ul>
	<li> <a href="#">Apple</a>
<div class="dropdown">
<ul>
	<li><a href="#">Column A #1</a></li>
	<li><a href="#">Column A #2</a></li>
	<li><a href="#">Column A #3</a></li>
	<li><a href="#">Column A #4</a></li>
	<li class="last"><a href="#">Column A #5</a></li>
</ul>
<ul>
	<li><a href="#">Column B #1</a></li>
	<li><a href="#">Column B #2</a></li>
	<li><a href="#">Column B #3</a></li>
	<li><a href="#">Column B #4</a></li>
	<li class="last"><a href="#">Column B #5</a></li>
</ul>
</div></li>
	<li> <a href="#">Banana</a>
<div class="dropdown">
<ul>
	<li><a href="#">Column A #1</a></li>
	<li><a href="#">Column A #2</a></li>
	<li><a href="#">Column A #3</a></li>
	<li><a href="#">Column A #4</a></li>
	<li class="last"><a href="#">Column A #5</a></li>
</ul>
<ul>
	<li><a href="#">Column B #1</a></li>
	<li><a href="#">Column B #2</a></li>
	<li><a href="#">Column B #3</a></li>
	<li><a href="#">Column B #4</a></li>
	<li class="last"><a href="#">Column B #5</a></li>
</ul>
</div></li>
	<li> <a href="#">Cherry</a>
<div class="dropdown">
<ul>
	<li><a href="#">Column A #1</a></li>
	<li><a href="#">Column A #2</a></li>
	<li><a href="#">Column A #3</a></li>
	<li><a href="#">Column A #4</a></li>
	<li class="last"><a href="#">Column A #5</a></li>
</ul>
<ul>
	<li><a href="#">Column B #1</a></li>
	<li><a href="#">Column B #2</a></li>
	<li><a href="#">Column B #3</a></li>
	<li><a href="#">Column B #4</a></li>
	<li class="last"><a href="#">Column B #5</a></li>
</ul>
</div></li>
	<li> <a href="#">Durian</a>
<div class="dropdown">
<ul>
	<li><a href="#">Column A #1 with a really long label</a></li>
	<li><a href="#">Column A #2</a></li>
	<li><a href="#">Column A #3</a></li>
	<li><a href="#">Column A #4</a></li>
	<li><a href="#">Column A #5</a></li>
	<li><a href="#">Column A #6</a></li>
	<li><a href="#">Column A #7</a></li>
	<li><a href="#">Column A #8</a></li>
	<li><a href="#">Column A #9</a></li>
	<li class="last"><a href="#">Column A #10</a></li>
</ul>
</div></li>
	<li> <a href="#">Elephant</a>
<div class="dropdown">
<ul>
	<li><a href="#">Column A #1</a></li>
	<li><a href="#">Column A #2</a></li>
	<li><a href="#">Column A #3</a></li>
	<li><a href="#">Column A #4</a></li>
	<li class="last"><a href="#">Column A #5</a></li>
</ul>
<ul>
	<li><a href="#">Column B #1</a></li>
	<li><a href="#">Column B #2</a></li>
	<li><a href="#">Column B #3</a></li>
	<li><a href="#">Column B #4</a></li>
	<li class="last"><a href="#">Column B #5</a></li>
</ul>
</div></li>
</ul>
</div>
<script type="text/javascript">
$("pre").attr({name:'code'});

$("#navbar > ul > li > a").mouseover(function(){
  $("#navbar > ul > li > a").each(function(){
    $(this).removeClass('over open');
    $(this).next().removeClass('over').hide();
  });

  $(this).addClass('over open');
  $(this).next().show();
});
$("#navbar > ul > li > a").mouseout(function(){
  var a = $(this);
  a.removeClass('over');
  setTimeout(function(){
    if (a.hasClass('over') || a.next().hasClass('over')) return;
    a.removeClass('open');
    a.next().hide();
    }, 1000);
});
$("#navbar > ul > li > div.dropdown").mouseover(function(){
  $(this).addClass('over');
});
$("#navbar > ul > li > div.dropdown").mouseout(function(){
  var a = $(this);
  a.removeClass('over');
  setTimeout(function(){
    if (a.hasClass('over') || a.prev().hasClass('over')) return;
    a.prev().removeClass('open');
    a.hide();
    }, 1000);
});
</script>

]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2010/04/24/dynamic-drop-down-navigation-menu-like-wired-com/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Dynamic Facebook and Tweetmeme Widgets</title>
		<link>https://rommelsantor.com/clog/2010/04/09/dynamic-facebook-and-tweetmeme-widgets/</link>
		<comments>https://rommelsantor.com/clog/2010/04/09/dynamic-facebook-and-tweetmeme-widgets/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 21:19:27 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[VideoSift]]></category>
		<category><![CDATA[dynamic]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[FB.Share]]></category>
		<category><![CDATA[retweet]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[tweetmeme]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[widget]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=45</guid>
		<description><![CDATA[We just made a change on YouTube videos so that at the end of playback a Facebook &#8220;share&#8221; button and a Tweetmeme &#8220;retweet&#8221; button appear as part of an effort to encourage users to spread videos in their personal social networks. This presented a couple of problems because, similar to an issue touched on in [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
We just made a change on YouTube videos so that at the end of playback a Facebook &#8220;share&#8221; button and a Tweetmeme &#8220;retweet&#8221; button appear as part of an effort to encourage users to spread videos in their personal social networks.
</p>
<p><a rel="attachment wp-att-46" href="http://rommelsantor.com/clog/2010/04/09/dynamic-facebook-and-tweetmeme-widgets/shares/"><img class="aligncenter size-full wp-image-46" style="border: 1px solid #999;" title="Dynamic Facebook and Retweet Widgets" src="http://rommelsantor.com/clog/wp-content/uploads/2010/04/shares.jpg" alt="" width="537" height="407" /></a><br />
<span id="more-45"></span></p>
<p>
This presented a couple of problems because, similar to an issue touched on in <a href="http://rommelsantor.com/clog/2010/04/06/javascript-video-embed-widget/">my last clog</a>, the widgets needed to be inserted dynamically and that&#8217;s usually easier said than done. After a little bit of digging into how the widgets function, I was able to make them seemingly load normally on-the-fly.
</p>
<h1>Dynamic Facebook Share Button</h1>
<p>
Facebook share buttons are created in a couple of pieces. I started with the default widget code <a href="http://www.facebook.com/facebook-widgets/share.php" target="_blank">supplied</a> by Facebook:
</p>
<pre class="html:nocontrols:nogutter">
&lt;a type="button_count" name="fb_share"
  href="http://www.facebook.com/sharer.php"&gt;Share&lt;/a&gt;
&lt;script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" type="text/javascript"&gt;&lt;/script&gt;
</pre>
<p>
Understanding how to make this work dynamically first means understanding what exactly this code does. The &lt;a&gt; tag is clearly a link to Facebook&#8217;s share service where users can submit our page. The <tt>&lt;script&gt;</tt> tag loads a JavaScript object named FB.Share.
</p>
<h2>Failed Insertion</h2>
<p>If you were to try inserting these bits of code dynamically, you&#8217;d discover in no time flat that it just won&#8217;t work. For example, this might look like a good idea, but it&#8217;s useless:</p>
<pre>
$("#somediv").append('&lt;a type="button_count" name="fb_share" '+
  'href="http://www.facebook.com/sharer.php"&gt;Share&lt;/a&gt;');
$("#somediv").append('&lt;script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" '+
  'type="text/javascript"&gt;&lt;/script&gt;');
</pre>
<p>
And you may even try it a little more manually by directly modifying the DOM:
</p>
<pre>a = document.createElement('a');
a.type='button_count';
a.name='fb_share';
a.href='http://www.facebook.com/sharer.php';
a.innerHTML = 'Share';
document.getElementById('somediv').appendChild(a);

s = document.createElement('script');
s.type='text/javascript';
s.src='http://static.ak.fbcdn.net/connect.php/js/FB.Share';
document.getElementById('somediv').appendChild(s);
</pre>
<p>
But you&#8217;ll be disappointed by the results. A working solution required a little more digging.
</p>
<h2>Successful Buttonization</h2>
<p>I opened <a href="http://static.ak.fbcdn.net/connect.php/js/FB.Share" target="_blank">Facebook&#8217;s JavaScript file</a> and started sniffing around. Their code is designed to initialize all buttons on the page just once, which makes perfect sense. So the solution is to add the <tt>&lt;a&gt;</tt> tag as per the above but then manually force FB.Share to re-execute, thus turning our dynamically added link into a button. The required function call is rather simple:
</p>
<pre>
if (typeof(FB.Share) != 'undefined') {// make sure it exists
  // FB.Share.onFirst();
  // *** UPDATE: 17 Aug 2011 - Thanks to zr0ck who informed
  // FB has modified their Share script ***
  // FB.Share.onFirst() no longer exists; you must now instead call:
  FB.Share.renderPass();
}
</pre>
<p>
Just execute that after you&#8217;ve inserted your <tt>&lt;a&gt;</tt> link and it&#8217;ll become a pretty Facebook button.
</p>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<h2>Multiple Buttons Per Page</h2>
<p>The above solution works splendidly, assuming that you use it on a URL specific to the content you&#8217;re sharing because FB.Share will by default use the address of the current page when adding to the user&#8217;s wall. However, if you are on a listing page where there are multiple content posts and the URL is not specific to any one of them (e.g., http://videosift.com), then every dynamic button you add will reference the same address.
</p>
<p>
Facebook provides a straightforward method for you to specify an alternate URL than the current one, which is to add a <tt>u</tt> variable to the query string of the link:
</p>
<pre class="html:nocontrols:nogutter">
&lt;a type="button_count" name="fb_share"
  href="http://www.facebook.com/sharer.php?u=SOMEURL"&gt;
</pre>
<p>
However that method doesn&#8217;t work with our dynamic buttonizing for whatever reason. A little more sniffing through the FB.Share code reveals exactly how it determines what URL to use:
</p>
<pre>
FB.Share {
//...
getUrl:function(a){return a.getAttribute('share_url')||window.location.href;}
//...
}
</pre>
<p>
Aha- it checks for an attribute named <tt>share_url</tt>. So all we have to do is add that attribute to our link et voila, we&#8217;re in business!
</p>
<pre class="html:nocontrols:nogutter">
&lt;a type="button_count" name="fb_share"
  href="http://www.facebook.com/sharer.php" share_url="SOMEURL"&gt;
</pre>
<h1>Dynamic Tweetmeme Retweet Button</h1>
<p>
Fortunately, the retweet button was much less involved than the FB share button, but also require just a little bit of digging. As described on <a href="http://help.tweetmeme.com/2009/04/06/tweetmeme-button/" target="_blank">tweetmeme&#8217;s widget page</a>, the following is the code you&#8217;d typically want to use on a web page:
</p>
<pre>
&lt;script type="text/javascript"&gt;
tweetmeme_url = 'http://yoururl.com';
&lt;/script&gt;
&lt;script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"&gt;&lt;/script&gt;
</pre>
<p>
As with the FB widget, attempting to insert this code into the DOM on-the-fly just results in failure. (I&#8217;ll spare you the sample broken code.) So I cracked open the <a href="http://tweetmeme.com/i/scripts/button.js" target="_blank">button&#8217;s js code</a> and investigated how it worked.
</p>
<p>
It turns out tweetmeme doesn&#8217;t use a lot of JS tomfoolery to make their widgets work. Instead, they insert a simple <tt>&lt;iframe&gt;</tt> and allow that to do all work, which makes it easy for us because all we have to do is insert the same type of iframe and we&#8217;re in business. So we did something like the following and it worked like a charm:
</p>
<pre>
$("#somediv").append('&lt;iframe frameborder="0" scrolling="no" height="61" width="50"
  src="http://api.tweetmeme.com/button.js?url='+SOMEURL+'"&gt;&lt;/iframe&gt;');
</pre>
<h1>Enjoy!</h1>
<p><script type="text/javascript">//<![CDATA[
$("pre").attr({name:'code'}).each(function(){if($(this).attr('class')=='')$(this).addClass('js:nocontrols:nogutter');});
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2010/04/09/dynamic-facebook-and-tweetmeme-widgets/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>JavaScript Video Embed Widget</title>
		<link>https://rommelsantor.com/clog/2010/04/06/javascript-video-embed-widget/</link>
		<comments>https://rommelsantor.com/clog/2010/04/06/javascript-video-embed-widget/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 05:22:18 +0000</pubDate>
		<dc:creator><![CDATA[rommel]]></dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[VideoSift]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[widget]]></category>
		<category><![CDATA[xmlhttprequest]]></category>

		<guid isPermaLink="false">http://rommelsantor.com/clog/?p=6</guid>
		<description><![CDATA[Overview &#124; Inserting the Widget &#124; Name Collision &#124; Dynamic &#60;script&#62; Loading Cross-Domain Scripting and XMLHttpRequest &#124; In Conclusion Overview At VideoSift we have always made available the embed code for every video on the site. Until now, the provided code has just been the raw &#60;object&#62; and &#60;embed&#62; tags as you would acquire directly [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><center><a href="#overview">Overview</a> | <a href="#inserting_the_widget">Inserting the Widget</a> | <a href="#name_collision">Name Collision</a> | <a href="#dynamic_script_loading">Dynamic &lt;script&gt; Loading</a><br />
<a href="#cross_domain_scripting_and_xmlhttprequest">Cross-Domain Scripting and XMLHttpRequest</a> | <a href="#in_conclusion">In Conclusion</a></center></p>
<h1 id="overview">Overview</h1>
<p>At VideoSift we have always made available the embed code for every video on the site. Until now, the provided code has just been the raw &lt;object&gt; and &lt;embed&gt; tags as you would acquire directly from the video host, but we wanted to provide a much more attractive embed.</p>
<p>We opted to achieve such a thing by providing users with a &lt;script&gt; tag that builds the fancy new widget into the DOM of the host page. Initially, the plan was to just generate a pretty simple DOM structure  wrapped around a video, but it evolved from there to include:</p>
<ul>
<li>the ability to optionally start out as a thumbnail image that when clicked will expand into the full widget</li>
<li>a functional vote button that would remotely cast an up-vote for logged in members</li>
<li>a brief, scrollable listing of comments on the video</li>
</ul>
<p>There were a few interesting issues that needed to be resolved along the way:</p>
<ul>
<li>Where on the host page should the widget be inserted?</li>
<li>What happens if the host page contains multiple widget &lt;script&gt; tags?</li>
<li>How should we dynamically load the widget in comments on VideoSift?</li>
<li>How should we cast votes on remote host pages that need to be posted to VideoSift?</li>
</ul>
<p><span id="more-6"></span></p>
<h1 id="inserting_the_widget">Inserting the Widget</h1>
<p>When it came to inserting the widget into the DOM of the host page, the desired location was obvious: immediately adjacent to the &lt;script&gt; tag itself. Really the only issue was to locate the appropriate &lt;script&gt; tag.</p>
<p>We start by searching for the target node in the DOM tree for all nodes with tagName &#8216;script&#8217; and examine their &#8220;src&#8221; attribute:</p>
<pre>function createWidgetDiv() {
  scripts = document.getElementsByTagName('script');
  for (i=0; i &lt; scripts.length; ++i) {
    if (/videosift\.com\/widget\.js\?.*video=123456(&amp;|$)/.test(scripts[i].src)) {
      widgetdiv = document.createElement('div');
      scripts[i].parentNode.insertBefore(widgetdiv, scripts[i].nextSibling);
      break;
    }
  }

// now we can start inserting our widget contents into widgetdiv
}</pre>

<div style="float:left;margin:0 10px 10px 0">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-7639656561235411";
/* Square (250x250) */
google_ad_slot = "8522038794";
google_ad_width = 250;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<h1 id="name_collision">Name Collision</h1>
<p>At this point we discover another issue. How are we sure this &lt;script&gt; tag belongs to the widget that&#8217;s currently executing? The user could have inserted onto the host page two &lt;script&gt; embeds. We handle the issue of there being two different embeds on the same page by checking if the &lt;script&gt; src URL contains the video ID that we&#8217;re currently executing with. We do not, however, handle the situation where a user inserts two embeds for the exact same video ID. In that case, both the first and the second widget will insert themselves after the first &lt;script&gt; tag because it&#8217;s the first one encountered in the DOM tree.</p>
<p>This brings us to the related issue of variable and function name collisions shared by multiple embedded scripts. With just a single widget on the page, we wouldn&#8217;t have to worry about naming convention, but let&#8217;s say we have two widgets with video IDs 111 and 222 both on the same host page. When the widget for 111 executes, everything will be fine, but when 222 executes, it will define a new createWidgetDiv(). If after that happens 111 calls createWidgetDiv() again, it will then be calling that defined by 222.</p>
<p>One way to fix this is to define the functions with a video ID specific suffix, e.g., createWidgetDiv_111() and createWidgetDiv_222(). This is not ideal, however, because considering again the situation where the host page contains two widgets with the same video ID, there will again be overlap. So, I opted to append a random number to every important function and variable name like createWidgetDiv_3948717().</p>
<h1 id="dynamic_script_loading">Dynamic &lt;script&gt; Loading</h1>
<p>So far, so good. At this point a page can load with any number of widgets already embedded in the HTML, but uh oh- what happens if we try to insert a &lt;script&gt; tag into a page that&#8217;s already been loaded? When we decided to modify VideoSift comment listings to allow just our special &lt;script&gt; tag, we needed to adjust how we loaded it. Here&#8217;s a very simple example trying to insert a &lt;script&gt; tag with jQuery:</p>
<pre>$("#some_div").html('&lt;script type="text/javascript"
  src="http://videosift.com/widget.js?video=111"&gt;&lt;/script&gt;');</pre>
<p>This won&#8217;t work because the &lt;script&gt; tags won&#8217;t be parsed. (This is not just jQuery-specific.) The fix, unfortunately, is not an issue that can be dealt with in the widget itself, but by the host page that is loading the script. Rather than attempting to insert a script tag, you&#8217;ll have to manually manipulate the DOM to insert a node with tagName &#8216;script&#8217;. You could use a function along these lines:</p>
<pre>function dynScript(src) {
  script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = src;
  return script;
}

// insert it somewhere
$("#some_div").append(dynScript('http://videosift.com/widget.js?video=111'));</pre>
<h1 id="cross_domain_scripting_and_xmlhttprequest">Cross-Domain Scripting and XMLHttpRequest</h1>
<p>The final piece of the puzzle was getting the vote button to function when the widget is hosted on a remote domain. For security, XMLHttpRequest/Ajax requests are disallowed from communicating with scripts on foreign websites.</p>
<p>We clearly want to allow VideoSift users to cast votes for videos embedded on external sites, so we used a common workaround for the cross-domain restriction and inserted a dynamic script tag into the DOM specifying the vote URL as the &lt;script&gt; src attribute.</p>
<p>If that sounds familiar, yep, you guessed it. We reuse the dynScript() function for this purpose and it works splendidly. For example, we can do something like this:</p>
<pre>$("#vote_btn").click(function(){
  // normally we'd make an Ajax request here, but not this time
  $(body).append(dynScript('http://videosift.com/widget_vote.js?video=111'));
  return false;
});</pre>
<p>And the loaded script can take care of the post-processing for the host page that would normally happen in the Ajax callback. For example:</p>
<pre>if (voting_failed)
  alert('Could not cast your vote!');
else
  updateVoteButton();</pre>
<h1 id="in_conclusion">In Conclusion</h1>
<p>Well, that&#8217;s it for my very first clog post. I hope most of what I wrote up there isn&#8217;t too vague to be appreciated by anyone who might be looking for some guidance or answers. My intent was to provide in broad strokes a breakdown of the wrinkles encountered on this project and how they were ironed out.</p>
<p>Here is an example of the widget in action.</p>
<p><script src="http://videosift.com/widget.js?video=170447&amp;width=540&amp;comments=15&amp;minimized=1" type="text/javascript"></script></p>
<p>The embed code for this widget follows:</p>
<pre>&lt;script type="text/javascript"
  src="http://videosift.com/widget.js?video=170447&amp;width=540&amp;comments=15&amp;minimized=1"&gt;&lt;/script&gt;</pre>
<p><script type="text/javascript">//< ![CDATA[
$("pre").attr({name:'code'}).addClass('js:nocontrols:nogutter');
//]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>https://rommelsantor.com/clog/2010/04/06/javascript-video-embed-widget/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
