<?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; widget</title>
	<atom:link href="https://rommelsantor.com/clog/tag/widget/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>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>
