encodeURI Быть переопределенным в сафари
обзор
Поэтому я написал плагин Video.js, который отправляет отчеты в Google Analytics и в наши собственные отчеты.
Каждый запрос JSONP, который мы отправляем обратно на нашу страницу, кодируется с использованием encodeURIComponent с использованием этого метода. Первые несколько правильно сработали. Затем начинается ошибка с TypeError: '[object Object]' is not a function (evaluating 'encodeURIComponent(p)')
, Это происходит только в Safari. (Я на сафари 7.0.1 на OSX Mavericks)
Я даже пытался сделать всю строку 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(опция)
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
теперь последний объект, с которым он был вызван.
Есть идеи?
1 ответ
В каждом из слушателей отслеживания событий есть / было videoData = getVideoData()
как только я добавил var
в videoData
проблема прекратилась Кто-нибудь видит, почему это может быть причиной? Я понимаю, что это было установлено в глобальную переменную, но как encodeURIComponent устанавливается в объект?