概要
そこで、Google アナリティクスとカスタム レポートに報告する Video.js プラグインを作成しました。
ページに送り返す各 JSONP リクエストは、このメソッドを使用して、encodeURIComponent を使用してエンコードされます。最初のいくつかは正しく起動します。その後、エラーが発生し始めますTypeError: '[object Object]' is not a function (evaluating 'encodeURIComponent(p)')
。これは Safari でのみ発生します。(OSX Mavericks で safari 7.0.1 を使用しています)
を使用して URL 文字列全体を実行しようとしましたencodeURI
が、その関数にも同じことが起こります。
問題を示すために [JS FIDDLE][2] を作成しました。サンプルコードだけで再作成できなかったので、関連するすべてのファイルを外部リソースに含めました。実行されない場合は、約 85% の確率でページを再実行してください。
関数のステップスルー
最初に追跡するイベントを追加します
this.on('play',onPlay);
this.on('pause',onPause);
イベントが発生すると、これらの関数によってキャッチされます
function onPlay( e ) {
videoData = getVideoData();
doTracking({
'category': videoData.cid,
'action': videoData.vid,
'label': 'Play',
'value': null
});
}
function onPause( e ) {
videoData = getVideoData();
doTracking({
'category': videoData.cid,
'action': videoData.vid,
'label': 'Pause',
'value': getTime()
});
}
ビデオデータを取得するもの
function getVideoData() {
var src = videojsRef.player().currentSrc();
var srcSplit = src.split('/');
var filename = srcSplit[srcSplit.length-1];
var filenameSplit = filename.split('.');
var cid = filenameSplit[0];
var vid = filenameSplit[1];
var type = filenameSplit[2];
var returnObj = {
'cid': cid,
'vid': vid,
'filename': filename
};
return returnObj;
}
そして、両方のトラッキング関数を呼び出す単なるヘルパー関数である「doTracking」を呼び出します。
function doTracking( opt ) {
if ( gaType && bvReady ) { // Are both tracking types initialized
// Send to google
googleTrack( opt );
// Send to BetterVideo
bvTrack( opt );
} else {
queue.push( opt );
}
}
bvTrack( opt ) を呼び出すもの
function bvTrack( opt ) {
var args = {
pid: playerid,
cid: opt.category,
vcd: opt.action,
a: opt.label,
callback: '{callback}'
};
if ( opt.value !== null ) {
args.val = opt.value;
}
// Heres where the trouble starts
new videojs.JSONP('http://jsfiddle.net/echo/jsonp/?'+serializeToQuery(args), function( response ) {
console.log('[BV Reporting] Tracking Response: ', arguments );
})
}
データはここでシリアル化されます
function serializeToQuery( obj ) {
var str = [];
console.log( "serializeToQuery", obj );
for(var p in obj) {
if ( obj.hasOwnProperty(p) ) {
console.log( ' property', p, obj[p]);
console.log( ' encodeURIComponent', typeof encodeURIComponent == 'function' ? 'function' : encodeURIComponent );
console.log( ' encoded property', encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
return str.join("&");
}
そして、d3.js にインスパイアされた JSONPに渡されます (SO でここで見つけたと思います)。
videojs.JSONP = function (url, callback) {
var docHead = document.getElementsByTagName('head')[0];
function rand() {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
c = '', i = -1;
while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
return c;
}
function create(url) {
var e = url.match(/callback=jsonp.(\w+)/),
c = e ? e[1] : rand();
videojs.JSONP[c] = function(data) {
callback(data);
delete videojs.JSONP[c];
docHead.removeChild(script);
};
return 'videojs.JSONP.' + c;
}
var cb = create(url),
script = document.createElement('script');
script.type = 'text/javascript';
script.src = url.replace(/(\{|%7B)callback(\}|%7D)/, cb);
docHead.appendChild(script)
};
出力
serializeToQuery Object {
a: "Pause"
callback: "{callback}"
cid: "oceans"
pid: "885FA551-A873-4BB9-891A-ABC08CD47D36"
val: 6
vcd: "mp4"
}
property pid 885FA551-A873-4BB9-891A-ABC08CD47D36
encodeURIComponent function
encoded property pid=885FA551-A873-4BB9-891A-ABC08CD47D36
property cid oceans
encodeURIComponent function
encoded property cid=oceans
property vcd mp4
encodeURIComponent function
encoded property vcd=mp4
property a Pause
encodeURIComponent function
encoded property a=Pause
property callback {callback}
encodeURIComponent function
encoded property callback=%7Bcallback%7D
property val 6
encodeURIComponent function
encoded property val=6
しかし、2 ~ 3 回の JSONP 呼び出しの後、次のように出力されます。
serializeToQuery Object {
a: "Play"
callback: "{callback}"
cid: "oceans"
pid: "885FA551-A873-4BB9-891A-ABC08CD47D36"
vcd: "mp4"
}
property pid 885FA551-A873-4BB9-891A-ABC08CD47D36
encodeURIComponent Object {
cid: "oceans"
filename: "oceans.mp4"
vid: "mp4"
}
[Error] TypeError: '[object Object]' is not a function (evaluating 'encodeURIComponent(p)')
serializeToQuery (videojs.bvReporting.js, line 531)
bvTrack (videojs.bvReporting.js, line 481)
doTracking (videojs.bvReporting.js, line 329)
onPlay (videojs.bvReporting.js, line 113)
ret (video.dev.js, line 769)
dispatcher (video.dev.js, line 295)
trigger (video.dev.js, line 529)
trigger (video.dev.js, line 1868)
eventHandler (video.dev.js, line 5376)
ret (video.dev.js, line 769)
dispatcher (video.dev.js, line 295)
ご覧のとおりencodeURIComponent
、最後に呼び出されたオブジェクトです。
何か案は?