351 lines
8.5 KiB
JavaScript
351 lines
8.5 KiB
JavaScript
|
|
function createPluginReplacement(root, parent, host, attributeNames, attributeValues)
|
|
{
|
|
return new Replacement(root, parent, host, attributeNames, attributeValues);
|
|
};
|
|
|
|
function Replacement(root, parent, host, attributeNames, attributeValues)
|
|
{
|
|
this.root = root;
|
|
this.parent = parent;
|
|
this.host = host;
|
|
this.listeners = {};
|
|
this.scriptObject = {};
|
|
|
|
this.autoExitFullScreen = true;
|
|
this.postEvents = false;
|
|
this.height = 0;
|
|
this.width = 0;
|
|
this.src = "";
|
|
this.autohref = false;
|
|
this.href = "";
|
|
this.qtsrc = "";
|
|
this.baseUrl = "";
|
|
this.target = "";
|
|
|
|
this.createVideoElement(attributeNames, attributeValues);
|
|
this.createScriptInterface();
|
|
};
|
|
|
|
Replacement.prototype = {
|
|
|
|
HandledVideoEvents: {
|
|
loadstart: 'handleLoadStart',
|
|
error: 'handleError',
|
|
loadedmetadata: 'handleLoadedMetaData',
|
|
canplay: 'qt_canplay',
|
|
canplaythrough: 'qt_canplaythrough',
|
|
play: 'qt_play',
|
|
pause: 'qt_pause',
|
|
ended: 'handleEnded',
|
|
webkitfullscreenchange: 'handleFullscreenChange',
|
|
},
|
|
|
|
AttributeMap: {
|
|
autoexitfullscreen: 'autoExitFullScreen',
|
|
postdomevents: 'postEvents',
|
|
height: 'height',
|
|
width: 'width',
|
|
qtsrc: 'qtsrc',
|
|
src: 'src',
|
|
airplay: 'x-webkit-airplay=',
|
|
href: 'href',
|
|
target: 'target',
|
|
},
|
|
|
|
MethodMap: {
|
|
SetURL : 'setURL',
|
|
GetURL : 'url',
|
|
Play : 'play',
|
|
Stop : 'pause',
|
|
GetRate : 'rate',
|
|
SetRate : 'setRate',
|
|
IsFullScreen : 'isFullScreen',
|
|
ExitFullScreen : 'exitFullScreen',
|
|
GetPluginStatus : 'pluginStatus',
|
|
GetTime : 'currentTime',
|
|
SetTime : 'setCurrentTime',
|
|
SeekToDate : 'seekToDate',
|
|
GetDate : 'date',
|
|
GetDuration : 'duration',
|
|
GetTimeScale : 'timeScale',
|
|
GetMaxTimeLoaded : 'maxTimeLoaded',
|
|
GetMaxBytesLoaded : 'maxBytesLoaded',
|
|
GetMovieSize : 'movieSize',
|
|
GetTimedMetadataUpdates : 'timedMetadataUpdates',
|
|
GetAccessLog : 'accessLog',
|
|
GetErrorLog : 'errorLog',
|
|
},
|
|
|
|
TimeScale: 30000,
|
|
|
|
createVideoElement: function(attributeNames, attributeValues)
|
|
{
|
|
var video = this.video = document.createElement('video');
|
|
|
|
for (name in this.HandledVideoEvents)
|
|
video.addEventListener(name, this, false);
|
|
|
|
for (i = 0; i < attributeNames.length; i++) {
|
|
var property = this.AttributeMap[attributeNames[i]];
|
|
if (this[property] != undefined)
|
|
this[property] = attributeValues[i];
|
|
}
|
|
|
|
video.setAttribute('pseudo', '-webkit-plugin-replacement');
|
|
video.setAttribute('controls', 'controls');
|
|
this.setStatus('Waiting');
|
|
|
|
var src = this.resolveRelativeToUrl(this.src, "");
|
|
this.baseUrl = src;
|
|
|
|
// The 'qtsrc' attribute is used when a page author wanted to always use the QuickTime plug-in
|
|
// to load a media type even if another plug-in was registered for that type. It tells the
|
|
// plug-in to ignore the 'src' url, and to load the 'qtsrc' url instead.
|
|
if (this.qtsrc)
|
|
src = this.resolveRelativeToUrl(this.qtsrc, this.src);
|
|
if (this.href && this.target) {
|
|
src = this.resolveRelativeToUrl(this.href, this.src);
|
|
video.poster = this.src;
|
|
video.setAttribute('preload', 'none');
|
|
}
|
|
|
|
if (src.length) {
|
|
this.setStatus('Validating');
|
|
this.video.src = src;
|
|
}
|
|
|
|
this.root.appendChild(video);
|
|
},
|
|
|
|
resolveRelativeToUrl: function(url, baseUrl)
|
|
{
|
|
if (url.indexOf('://') != -1)
|
|
return url;
|
|
if (baseUrl.indexOf('://') == -1)
|
|
baseUrl = this.resolveRelativeToUrl(baseUrl, document.baseURI);
|
|
|
|
var base = document.createElement('base');
|
|
base.href = baseUrl;
|
|
document.head.appendChild(base);
|
|
|
|
var resolver = document.createElement('a');
|
|
resolver.href = url;
|
|
url = resolver.href;
|
|
|
|
document.head.removeChild(base);
|
|
base = null;
|
|
|
|
return url;
|
|
},
|
|
|
|
createScriptInterface: function()
|
|
{
|
|
for (name in this.MethodMap) {
|
|
var methodName = this.MethodMap[name];
|
|
this.scriptObject[name] = this[methodName].bind(this);
|
|
}
|
|
},
|
|
|
|
handleEvent: function(event)
|
|
{
|
|
if (event.target !== this.video)
|
|
return;
|
|
|
|
try {
|
|
var eventData = this.HandledVideoEvents[event.type];
|
|
if (!eventData)
|
|
return;
|
|
|
|
if (this[eventData] && typeof this[eventData] === "function")
|
|
this[eventData].call(this, event);
|
|
else
|
|
this.postEvent(eventData);
|
|
} catch(e) {
|
|
if (window.console)
|
|
console.error(e);
|
|
}
|
|
},
|
|
|
|
postEvent: function(eventName)
|
|
{
|
|
try {
|
|
if (this.postEvents)
|
|
this.host.postEvent(eventName);
|
|
} catch(e) { }
|
|
},
|
|
|
|
setStatus: function(status)
|
|
{
|
|
this.status = status;
|
|
},
|
|
|
|
handleLoadedMetaData: function(event)
|
|
{
|
|
this.setStatus('Playable');
|
|
this.postEvent('qt_validated');
|
|
this.postEvent('qt_loadedfirstframe');
|
|
this.postEvent('qt_loadedmetadata');
|
|
},
|
|
|
|
handleFullscreenChange: function(event)
|
|
{
|
|
this.postEvent(this.isFullScreen() ? 'qt_enterfullscreen' : 'qt_exitfullscreen');
|
|
},
|
|
|
|
handleError: function(event)
|
|
{
|
|
this.setStatus('Error');
|
|
this.postEvent('qt_error');
|
|
},
|
|
|
|
handleLoadStart:function(event)
|
|
{
|
|
if (this.video.poster)
|
|
this.setStatus('Waiting');
|
|
else
|
|
this.setStatus('Loading');
|
|
this.postEvent('qt_begin');
|
|
},
|
|
|
|
handleEnded: function(event)
|
|
{
|
|
this.postEvent('qt_ended');
|
|
if (this.isFullScreen() && this.autoExitFullScreen)
|
|
document.webkitExitFullscreen();
|
|
},
|
|
|
|
isFullScreen: function()
|
|
{
|
|
return document.webkitCurrentFullScreenElement === this.video;
|
|
},
|
|
|
|
setURL: function(url)
|
|
{
|
|
this.setStatus('Validating');
|
|
if (url.length)
|
|
url = this.resolveRelativeToUrl(url, this.baseUrl);
|
|
this.video.src = url;
|
|
},
|
|
|
|
url: function()
|
|
{
|
|
return this.video.currentSrc;
|
|
},
|
|
|
|
play: function()
|
|
{
|
|
this.video.play();
|
|
},
|
|
|
|
pause: function()
|
|
{
|
|
this.video.playbackRate = 0;
|
|
this.video.pause();
|
|
},
|
|
|
|
rate: function()
|
|
{
|
|
return this.video.paused ? 0 : 1;
|
|
},
|
|
|
|
setRate: function(rate)
|
|
{
|
|
if (rate)
|
|
this.video.play();
|
|
else
|
|
this.video.pause();
|
|
},
|
|
|
|
exitFullScreen: function()
|
|
{
|
|
document.webkitExitFullscreen();
|
|
},
|
|
|
|
pluginStatus: function()
|
|
{
|
|
return this.status;
|
|
},
|
|
|
|
currentTime: function()
|
|
{
|
|
return this.video.currentTime * this.TimeScale;
|
|
},
|
|
|
|
setCurrentTime: function(time)
|
|
{
|
|
this.video.currentTime = time / this.TimeScale;
|
|
},
|
|
|
|
seekToDate: function()
|
|
{
|
|
// FIXME: not implemented yet.
|
|
},
|
|
|
|
date: function()
|
|
{
|
|
return new Date();
|
|
},
|
|
|
|
duration: function()
|
|
{
|
|
return this.video.duration * this.TimeScale;
|
|
},
|
|
|
|
timeScale: function()
|
|
{
|
|
// Note: QuickTime movies and MPEG-4 files have a timescale, but it is not exposed by all media engines.
|
|
// 30000 works well with common frame rates, eg. 29.97 NTSC can be represented accurately as a time
|
|
// scale of 30000 and frame duration of 1001.
|
|
return 30000;
|
|
},
|
|
|
|
maxTimeLoaded: function()
|
|
{
|
|
return this.video.duration * this.TimeScale;
|
|
},
|
|
|
|
maxBytesLoaded: function()
|
|
{
|
|
var percentLoaded = this.video.buffered.end(0) / this.video.duration;
|
|
return percentLoaded * this.movieSize();
|
|
},
|
|
|
|
movieSize: function()
|
|
{
|
|
try {
|
|
return this.host.movieSize;
|
|
} catch(e) { }
|
|
|
|
return 0;
|
|
},
|
|
|
|
timedMetadataUpdates: function()
|
|
{
|
|
try {
|
|
return this.host.timedMetaData;
|
|
} catch(e) { }
|
|
|
|
return null;
|
|
},
|
|
|
|
accessLog: function()
|
|
{
|
|
try {
|
|
return this.host.accessLog;
|
|
} catch(e) { }
|
|
|
|
return null;
|
|
},
|
|
|
|
errorLog: function()
|
|
{
|
|
try {
|
|
return this.host.errorLog;
|
|
} catch(e) { }
|
|
|
|
return null;
|
|
},
|
|
};
|
|
|