前回の続きです。
cssとhtmlには特に見るべき所が無さそうなので、javascriptだけチェックしていきます。
zb_jq("div.zenback-twitterbtn > a:first").click(function() { this.disabled = true; var title = (document.title || ""); if (title) { title += " → "; } window.top.location = "http://widget.zenback.jp/_t/twitter_post_redirect/?url=http%3A//nanoappli.com/blog/&title="+encodeURIComponent(title); }); //end click |
div.zenback-twitterbtnがクリックされたらページ遷移するスクリプトですが、zenback-twitterbtnの定義自体がhtmlに無かったので既に使われてないコードっぽいです。
実際に上記URLにアクセスしてみても、以下のようなエラーでした。
ちなみに余談ですが、このエラーページの右下にあるbluebridge、以下の企業でした。
http://bluebridge.jp/
zb_escape_html()
var zb_escape_html = function (str) { str = str.replace("&","&"); str = str.replace("\"","""); str = str.replace("'","'"); str = str.replace("<","<"); str = str.replace(">",">"); return str; }; |
HTMLエンコードの処理です。
これとまったく同じ処理。→JavaScript/jQuery HTML Encoding
どこからも呼ばれていない模様なので過去の遺産かも。
zb_load_script()
var zb_load_script = function (options) { var script = document.createElement('script'); script.src = options.url; script.type = 'text/javascript'; script.charset = 'utf-8'; if (options.async) { script.async = true; } if (window.ActiveXObject) { // for IE script.onreadystatechange = function () { if (this.readyState === 'onloaded' || this.readyState === 'complete') { options.onload && options.onload(); } }; } else { // for other script.onloaddone = false; // for opera script.onload = function () { if (!this.onloaddone) { options.onload && options.onload(); this.onloaddone = true; } }; } if (options.element) { var s = options.element; s.appendChild(script); } else { // default insert var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(script, s); } }; |
引数で指定されたoptions.urlのスクリプトを実行する処理。
options.urlにはjavascriptのurlが指定される。
また、options.asyncがtrueの時は非同期で処理がコールされ、JavaScriptのロードが完了したタイミングでoptions.onloadをコールバックしてくれる。
ブラウザ毎の非互換性の吸収とかしてますね。
この辺の処理は汎用性が有りそう。
_zb_print_error()
var _zb_print_error = function (msg) { window.console && console.error(msg); }; |
デバッグログ的な関数。
console(window.console)は、クライアントよっては存在しない可能性があるので、チェックしてますね。
zb_load_jsonp()
var zb_load_jsonp = function (params, callback) { if (!params || !callback) { throw new Error('Invalid Parameter'); } try { var cb_key = params.callbackKey || 'callback'; var cb_value = params.callbackValue || 'callback'; var url = (params.url + (params.url.match(/\?/) ? '&' : '?')); url += (cb_key + '=' + cb_value); var frame = document.createElement("iframe"); frame.style.display = "none"; document.body.appendChild(frame); var doc = frame.contentWindow.document; var count = 0; // for Opera frame[frame.readyState/*IE*/ ? "onreadystatechange" : "onload"] = function () { if (this.readyState && this.readyState !== 'complete' || count++) { return; } if (doc['__zb_jsonp__']) { callback(null, doc['__zb_jsonp__']); } else if (params.retry && params.retry >= 1) { var timeout = params.timeout || 1000; setTimeout(function () { zb_load_jsonp({ url: params.url ,callbackKey: cb_key ,callbackValue: cb_value ,retry: params.retry - 1 ,timeout: timeout }, callback)}, timeout); } else { callback({ message: 'Failed load jsonp' }); } setTimeout(function () { try { frame && frame.parentNode && frame.parentNode.removeChild(frame); } catch (e) { _zb_print_error(e.message); } }, 0); }; doc.open(); doc.write('<' + 'script type="text/javascript">' + 'function ' + cb_value + ' (v) { document["__zb_jsonp__"] = v };' + '</' + 'script>' + '<' + 'script type="text/javascript" src="' + url + '"></' + 'script>'); doc.close(); return frame; } catch (e) { callback(e); } }; |
なんだろう…
雰囲気的にはiframeを作って、jsonpの呼び出しの感じだけど、ちょっと複雑なので後回し。
zb_load_twitter_favorites()からコールされている。
zb_abort_jsonp()
var zb_abort_jsonp = function (frame) { try { frame && frame.parentNode && frame.parentNode.removeChild(frame); } catch (e) { _zb_print_error(e.message); } }; |
jsonpコールを中断したとき、一旦作ったiframeを消しに走っている。
残念ながら誰からも呼ばれてない。
script_container()
var script_container = document.getElementById('zenback-script-container'); var zb_ga_track_settings = function () { _gaq.push(['zb._setAccount', 'UA-17145123-2']); _gaq.push(['zb._trackPageview']); _gaq.push(['zb._trackEvent', 'widgetNSID', '353091eea229c2955b2271a0c215dd8bcb210a67']); _gaq.push(['zb_ads._setAccount', 'UA-17145123-5']); }; |
google analysticsの下準備。
zb_ga_track_XXXX()
var zb_ga_track_entries = function () { zb_jq('.zenback-entries .zenback-list a').click(function () { _gaq.push(['zb._trackEvent', 'kanren_entries', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; var zb_ga_track_links = function () { zb_jq('.zenback-links .zenback-list a').click(function () { _gaq.push(['zb._trackEvent', 'kanren_links', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; var zb_ga_track_keywords = function () { zb_jq('.zenback-keywords .zenback-list a').click(function () { _gaq.push(['zb._trackEvent', 'kanren_keywords', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; var zb_ga_track_newsitem = function () { zb_jq('.zenback-newsitem a').click(function () { _gaq.push(['zb._trackEvent', 'zenback_news', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; var zb_ga_track_twitter_widget = function () { zb_jq('.zenback-twitter .zenback-list a').click(function() { _gaq.push(['zb._trackEvent', 'twitter', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; var zb_ga_track_mixi = function () { zb_jq('.zenback-socialbar .zenback-socialbar-mixicheck a').click(function () { _gaq.push(['zb._trackEvent', 'mixi', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; var zb_ga_track_evernote = function () { zb_jq('.zenback-socialbar .zenback-socialbar-evernote a').click(function () { _gaq.push(['zb._trackEvent', 'evernote', encodeURI(this.href), 'http://nanoappli.com/blog/']); }); }; |
アクセスログを取る際に、どのボタンが押されたかクリックログを仕込んでいる。
ボタンクリックのイベントハンドラを登録し、クリックのタイミングでどのボタンが押されたかgoogle analysticsのトラッキング用変数に値をセットしてる。
_gaq.pushの第二引数が違うだけなんだから共通関数にしてください!! な所。
zb_ga_track_XXXX()再び
var zb_ga_track_hatena_bookmark = function () { _gaq.push(['zb._trackEvent', 'hatena_bookmark', encodeURI(this.href), 'http://nanoappli.com/blog/']); }; var zb_ga_track_googleplusone = function (obj) { _gaq.push(['zb._trackSocial', 'google+1', obj.state, obj.href]); }; var zb_ga_track_twitter_tweet = function (url) { _gaq.push(['zb._trackSocial', 'twitter', 'tweet', url]); }; var zb_ga_track_twitter_follow = function () { _gaq.push(['zb._trackSocial', 'twitter', 'follow']); }; var zb_ga_track_fb_comments = function (comment) { _gaq.push(['zb._trackSocial', 'facebook', 'comment', comment.href]); }; var zb_ga_track_fb_uncomments = function (comment) { _gaq.push(['zb._trackSocial', 'facebook', 'uncomment', comment.href]); }; |
さっきと同じ。
今回はまったく同じでは無いけど、もう少し共通関数できると思うんだけど。
google analsticsのロード処理
zb_load_script({ url: ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js' ,async: true ,onload: function () { zb_ga_track_settings(); zb_ga_track_entries(); zb_ga_track_links(); zb_ga_track_newsitem(); zb_ga_track_keywords(); zb_ga_track_twitter_widget(); zb_ga_track_mixi(); zb_ga_track_evernote(); } }); |
google analsticsのロード処理を,zb_load_script()経由でコールしている。
zb_load_script()の中身は既に前述済み。
gaのロードが完了したタイミングで、前述のクリックログの仕込みに入っている。
tweetボタン関係のロード処理
zb_load_script({ url: 'http://platform.twitter.com/widgets.js' ,element: script_container ,async: true ,onload: function () { var zb_extract_param_from_uri = function (uri, paramName) { if (!uri) { return ''; } var uri = uri.split('#')[0]; // Remove anchor. var parts = uri.split('?'); // Check for query params. if (parts.length == 1) { return ''; } var query = decodeURI(parts[1]); // Find url param. paramName += '='; var params = query.split('&'); for (var i = 0, param; param = params[i]; ++i) { if (param.indexOf(paramName) === 0) { return unescape(param.split('=')[1]); } } }; if (window.twttr) { window.twttr.events.bind('tweet', function (event) { if (event) { var targetUrl; if (event.target && event.target.nodeName == 'IFRAME') { targetUrl = zb_extract_param_from_uri(event.target.src, 'url'); } zb_ga_track_twitter_tweet(targetUrl); } }); window.twttr.events.bind('follow', function (event) { event && zb_ga_track_twitter_follow(); }); } } }); |
twitter公式のtweetボタン関係のライブラリをロードしてる。
ライブラリAPIは下記のページに説明があります。
https://dev.twitter.com/docs/tweet-button
hatenaボタン関係のロード処理
zb_load_script({ url: 'http://b.st-hatena.com/js/bookmark_button.js' ,element: script_container ,async: true ,onload: function () { } }); |
はてなのボタン。
google+1ボタン関係のロード処理
window.___gcfg = { lang: 'ja' ,parsetags: 'explicit' }; zb_load_script({ url: 'https://apis.google.com/js/plusone.js' ,element: script_container ,async: true ,onload: function () { gapi.plusone.render('zenback-google-plusone', { 'size': 'medium' ,'count': 'true' ,'callback': 'zb_ga_track_googleplusone' }); } }); |
googleのボタン
APIはこちら→ +1 Button
zb_render_ad_view()
var zb_render_ad_view = function (params) { var result = false; try { var $zb_ads_body = zb_jq('#zenback-ads span.tweet_body'); var $zb_ads_text_a = zb_jq('<a></a>') .attr('href', params.link_url) .attr('target', '_blank') .addClass('zenback-ads-ad') .click(params.ga_click_tracking_code); var $zb_ads_link_span = zb_jq('<span></span>') .addClass('link'); $zb_ads_link_span.append($zb_ads_text_a.clone().text(params.view_url)); $zb_ads_text_a.text(params.ad_text); var $zb_ads_metadata_span = zb_jq('<span></span>') .addClass('metadata'); var $zb_ads_author_span = zb_jq('<span></span>') .addClass('author'); var $zb_ads_twitter_a = zb_jq('<a></a>') .attr('href', params.twitter_url) .attr('target', '_blank') .addClass('zenback-ads-twitter') .click(params.ga_click_tracking_code); var $zb_ads_twitter_a_clone = $zb_ads_twitter_a.clone() .text('@' + params.twtiter_screen_name); var $zb_ads_img = zb_jq('<img />') .attr('src', params.twitter_icon_url) .attr('alt', params.twtiter_screen_name); $zb_ads_twitter_a.append($zb_ads_img); var $zb_ads_strong = zb_jq('<strong></strong>') .append($zb_ads_twitter_a_clone); $zb_ads_author_span.append($zb_ads_twitter_a) .append($zb_ads_strong) .append(zb_jq('<br />')) .append(zb_jq('<span></span>').text(params.twtiter_screen_name)); $zb_ads_metadata_span.append($zb_ads_author_span); $zb_ads_body.append($zb_ads_text_a) .append(zb_jq('<br />')) .append($zb_ads_link_span) .append($zb_ads_metadata_span) .show(); result = true; } catch (e) { _zb_print_error(e.message); } return result; }; |
zenbackの広告のエリア。
なぜ全部動的に生成する必要があるんだろう??
jQuery使ってるなら変数部だけ差し込めばいい気もするんだけど。
zb_show_default_ad_view()
var zb_show_default_ad_view = function (ga_category) { var ga_category = ga_category || 'default'; var link_url = 'http://zenback.jp/?s=ads_fl01'; var view_url = 'http://zenback.jp'; var result = zb_render_ad_view({ link_url: link_url ,view_url: view_url ,ad_text: 'zenbackは自分のブログの記事と、過去の自分の記事、他のブログ記事、TwitterやFacebookなどソーシャルメディアをつなげるウィジェットです。多くのブログサービスに対応。設置はコードをコピペするだけ、5分で完了します。ご利用は無料です。' ,twitter_url: 'http://twitter.com/zenback' ,twitter_icon_url: 'http://a1.twimg.com/profile_images/1185414381/zenback_icon_normal.png' ,twtiter_screen_name: 'zenback' ,ga_click_tracking_code: function () { _gaq.push(['zb_ads._trackEvent', ga_category, 'click', link_url]); } }); if (result) { _gaq.push(['zb_ads._trackPageview', ga_category, link_url]); } else { _zb_print_error('Failed the default ad rendering.'); } }; |
諸々のエラーでロードが出来なかったときに、デフォルトで表示される広告の情報を作ってる。
zb_load_twitter_favorites(), zb_select_ad_tweet(), zb_show_ad_view()
var zb_load_twitter_favorites = function (twitter_id, load_count, callback) { try { var retry = 4; var favorites_api_base_url = 'https://api.twitter.com/1/favorites.json'; var favorites_api_call_url = favorites_api_base_url + '?id=' + twitter_id + '&count=' + load_count; zb_load_jsonp({ url: favorites_api_call_url, retry: retry }, function (err, jsonp) { if (err) { callback(err); return; } callback(null, jsonp); }); } catch (e) { callback(e); } }; var zb_select_ad_tweet = function (free_tweets, filler_tweets, callback) { try { if (!free_tweets || !filler_tweets) { callback({ message: 'Invalid parameter' }, null); return; } var timestamp = (+new Date()); var select_index = timestamp % 40; if (select_index < free_tweets.length) { callback(null, { ad: free_tweets[select_index] ,ga_category: 'zbcf' }); } else { if (filler_tweets.length === 0) { callback({ message: 'Nothing filler' }, null); } else { callback(null, { ad: filler_tweets[timestamp % filler_tweets.length] ,ga_category: 'zbcf2' }); } } } catch (e) { _zb_print_error(e.message); callback(e); } }; var zb_show_ad_view = function (tweet, ga_category) { if (!tweet) { return; } var link_url = 'https://twitter.com/#!/' + tweet.user.screen_name + '/status/' + tweet.id_str; var view_url = link_url; var url_regex = /((?:https?):\/\/[!-~]+)/m; if (tweet.text.match(url_regex)) { link_url = RegExp.$1; view_url = RegExp.$1; } var twitter_url = 'http://twitter.com/' + tweet.user.screen_name; var result = zb_render_ad_view({ link_url: link_url ,view_url: view_url ,ad_text: tweet.text ,twitter_url: twitter_url ,twitter_icon_url: tweet.user.profile_image_url ,twtiter_screen_name: tweet.user.screen_name ,ga_click_tracking_code: function () { _gaq.push(['zb_ads._trackEvent', ga_category, 'click', tweet.id_str]); } }); if (result) { _gaq.push(['zb_ads._trackPageview', ga_category, tweet.id_str]); } else { _zb_print_error('Failed the free ad rendering.'); } }; |
読むのがめんどくさくなってきたので省略…
twitterのお気に入りとか広告の表示処理っぽい。
広告のロード処理
try { var ads_free_id = 'zbcf'; var ads_free_load_number = 40; zb_load_twitter_favorites(ads_free_id, ads_free_load_number, function (err, data) { if (err) { _zb_print_error(err.message); zb_show_default_ad_view(); return; } var ads_free_tweets = data; var ads_filler_id = 'zbcf2'; var ads_filler_load_number = 40; zb_load_twitter_favorites(ads_filler_id, ads_filler_load_number, function (err, data) { if (err) { _zb_print_error(err.message); zb_show_default_ad_view(); return; } var ads_filler_tweets = data; zb_select_ad_tweet(ads_free_tweets, ads_filler_tweets, function (err, data) { if (err) { _zb_print_error(err.message); zb_show_default_ad_view(); return; } zb_show_ad_view(data.ad, data.ga_category); }); }); }); } catch (e) { _zb_print_error(e.message); zb_show_default_ad_view(); } })(); |
さっき省略した広告等のロード処理。
twitterのIDが@zbcfか@zbcf2のツイート内容を出力している?
ロードに失敗したときでも、zb_show_default_ad_view()でデフォルトの広告を出そうとしている所は良い感じ(作り手側の視点として)。
…と、ざっくり全処理を見てみました。
個人的に、気になった事や、後でもう少し勉強しておきたい箇所を纏めておきます。
- zb_load_script()の非同期処理(コールバックあり)は汎用性がありそう
- 各ボタンの、クリックログをとる仕組み
- google analysticsの、_gaq.pushに関する仕様を押さえておく
- _zb_print_error()は、console.logではなくってajaxでサーバサイドに投げておくと便利かも。
- zb_ga_track_xxx()関数郡のつくりは明らかにおかしいよね??(共通関数化して欲しい)
あと、ソーシャルブックマーク系ボタンの処理を調べてるときに見つけたサイトで、以下のページが勉強になりそうでした。
はてなダイアリーにいいねボタンを置く方法
【図解】iGoogleガジェットをブログパーツとして活用する方法。
関連記事
コメントを残す