348 lines
8.1 KiB
JavaScript
348 lines
8.1 KiB
JavaScript
/**
|
|
* Provides a base class for audio/visual controls. Should not be used directly.
|
|
*
|
|
* Please see the {@link Ext.Audio} and {@link Ext.Video} classes for more information.
|
|
* @private
|
|
*/
|
|
Ext.define('Ext.Media', {
|
|
extend: 'Ext.Component',
|
|
xtype: 'media',
|
|
|
|
/**
|
|
* @event play
|
|
* Fires whenever the media is played.
|
|
* @param {Ext.Media} this
|
|
*/
|
|
|
|
/**
|
|
* @event pause
|
|
* Fires whenever the media is paused.
|
|
* @param {Ext.Media} this
|
|
* @param {Number} time The time at which the media was paused at in seconds.
|
|
*/
|
|
|
|
/**
|
|
* @event ended
|
|
* Fires whenever the media playback has ended.
|
|
* @param {Ext.Media} this
|
|
* @param {Number} time The time at which the media ended at in seconds.
|
|
*/
|
|
|
|
/**
|
|
* @event stop
|
|
* Fires whenever the media is stopped.
|
|
* The `pause` event will also fire after the `stop` event if the media is currently playing.
|
|
* The `timeupdate` event will also fire after the `stop` event regardless of playing status.
|
|
* @param {Ext.Media} this
|
|
*/
|
|
|
|
/**
|
|
* @event volumechange
|
|
* Fires whenever the volume is changed.
|
|
* @param {Ext.Media} this
|
|
* @param {Number} volume The volume level from 0 to 1.
|
|
*/
|
|
|
|
/**
|
|
* @event mutedchange
|
|
* Fires whenever the muted status is changed.
|
|
* The volumechange event will also fire after the `mutedchange` event fires.
|
|
* @param {Ext.Media} this
|
|
* @param {Boolean} muted The muted status.
|
|
*/
|
|
|
|
/**
|
|
* @event timeupdate
|
|
* Fires when the media is playing every 15 to 250ms.
|
|
* @param {Ext.Media} this
|
|
* @param {Number} time The current time in seconds.
|
|
*/
|
|
|
|
config: {
|
|
/**
|
|
* @cfg {String} url
|
|
* Location of the media to play.
|
|
* @accessor
|
|
*/
|
|
url: '',
|
|
|
|
/**
|
|
* @cfg {Boolean} enableControls
|
|
* Set this to `false` to turn off the native media controls.
|
|
* Defaults to `false` when you are on Android, as it doesn't support controls.
|
|
* @accessor
|
|
*/
|
|
enableControls: Ext.os.is.Android ? false : true,
|
|
|
|
/**
|
|
* @cfg {Boolean} autoResume
|
|
* Will automatically start playing the media when the container is activated.
|
|
* @accessor
|
|
*/
|
|
autoResume: false,
|
|
|
|
/**
|
|
* @cfg {Boolean} autoPause
|
|
* Will automatically pause the media when the container is deactivated.
|
|
* @accessor
|
|
*/
|
|
autoPause: true,
|
|
|
|
/**
|
|
* @cfg {Boolean} preload
|
|
* Will begin preloading the media immediately.
|
|
* @accessor
|
|
*/
|
|
preload: true,
|
|
|
|
/**
|
|
* @cfg {Boolean} loop
|
|
* Will loop the media forever.
|
|
* @accessor
|
|
*/
|
|
loop: false,
|
|
|
|
/**
|
|
* @cfg {Ext.Element} media
|
|
* A reference to the underlying audio/video element.
|
|
* @accessor
|
|
*/
|
|
media: null,
|
|
|
|
/**
|
|
* @cfg {Number} volume
|
|
* The volume of the media from 0.0 to 1.0.
|
|
* @accessor
|
|
*/
|
|
volume: 1,
|
|
|
|
/**
|
|
* @cfg {Boolean} muted
|
|
* Whether or not the media is muted. This will also set the volume to zero.
|
|
* @accessor
|
|
*/
|
|
muted: false
|
|
},
|
|
|
|
constructor: function() {
|
|
this.mediaEvents = {};
|
|
this.callSuper(arguments);
|
|
},
|
|
|
|
initialize: function() {
|
|
var me = this;
|
|
me.callParent();
|
|
|
|
me.on({
|
|
scope: me,
|
|
|
|
activate : me.onActivate,
|
|
deactivate: me.onDeactivate
|
|
});
|
|
|
|
me.addMediaListener({
|
|
canplay: 'onCanPlay',
|
|
play: 'onPlay',
|
|
pause: 'onPause',
|
|
ended: 'onEnd',
|
|
volumechange: 'onVolumeChange',
|
|
timeupdate: 'onTimeUpdate'
|
|
});
|
|
},
|
|
|
|
addMediaListener: function(event, fn) {
|
|
var me = this,
|
|
dom = me.media.dom,
|
|
bind = Ext.Function.bind;
|
|
|
|
Ext.Object.each(event, function(e, fn) {
|
|
fn = bind(me[fn], me);
|
|
me.mediaEvents[e] = fn;
|
|
dom.addEventListener(e, fn);
|
|
});
|
|
},
|
|
|
|
onPlay: function() {
|
|
this.fireEvent('play', this);
|
|
},
|
|
|
|
onCanPlay: function() {
|
|
this.fireEvent('canplay', this);
|
|
},
|
|
|
|
onPause: function() {
|
|
this.fireEvent('pause', this, this.getCurrentTime());
|
|
},
|
|
|
|
onEnd: function() {
|
|
this.fireEvent('ended', this, this.getCurrentTime());
|
|
},
|
|
|
|
onVolumeChange: function() {
|
|
this.fireEvent('volumechange', this, this.media.dom.volume);
|
|
},
|
|
|
|
onTimeUpdate: function() {
|
|
this.fireEvent('timeupdate', this, this.getCurrentTime());
|
|
},
|
|
|
|
/**
|
|
* Returns if the media is currently playing.
|
|
* @return {Boolean} playing `true` if the media is playing.
|
|
*/
|
|
isPlaying: function() {
|
|
return !Boolean(this.media.dom.paused);
|
|
},
|
|
|
|
// @private
|
|
onActivate: function() {
|
|
var me = this;
|
|
|
|
if (me.getAutoResume() && !me.isPlaying()) {
|
|
me.play();
|
|
}
|
|
},
|
|
|
|
// @private
|
|
onDeactivate: function() {
|
|
var me = this;
|
|
|
|
if (me.getAutoPause() && me.isPlaying()) {
|
|
me.pause();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Sets the URL of the media element. If the media element already exists, it is update the src attribute of the
|
|
* element. If it is currently playing, it will start the new video.
|
|
*/
|
|
updateUrl: function(newUrl) {
|
|
var dom = this.media.dom;
|
|
|
|
//when changing the src, we must call load:
|
|
//http://developer.apple.com/library/safari/#documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/ControllingMediaWithJavaScript/ControllingMediaWithJavaScript.html
|
|
|
|
dom.src = newUrl;
|
|
|
|
if ('load' in dom) {
|
|
dom.load();
|
|
}
|
|
|
|
if (this.isPlaying()) {
|
|
this.play();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Updates the controls of the video element.
|
|
*/
|
|
updateEnableControls: function(enableControls) {
|
|
this.media.dom.controls = enableControls ? 'controls' : false;
|
|
},
|
|
|
|
/**
|
|
* Updates the loop setting of the media element.
|
|
*/
|
|
updateLoop: function(loop) {
|
|
this.media.dom.loop = loop ? 'loop' : false;
|
|
},
|
|
|
|
/**
|
|
* Starts or resumes media playback.
|
|
*/
|
|
play: function() {
|
|
var dom = this.media.dom;
|
|
|
|
if ('play' in dom) {
|
|
dom.play();
|
|
setTimeout(function() {
|
|
dom.play();
|
|
}, 10);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Pauses media playback.
|
|
*/
|
|
pause: function() {
|
|
var dom = this.media.dom;
|
|
|
|
if ('pause' in dom) {
|
|
dom.pause();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Toggles the media playback state.
|
|
*/
|
|
toggle: function() {
|
|
if (this.isPlaying()) {
|
|
this.pause();
|
|
} else {
|
|
this.play();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Stops media playback and returns to the beginning.
|
|
*/
|
|
stop: function() {
|
|
var me = this;
|
|
|
|
me.setCurrentTime(0);
|
|
me.fireEvent('stop', me);
|
|
me.pause();
|
|
},
|
|
|
|
//@private
|
|
updateVolume: function(volume) {
|
|
this.media.dom.volume = volume;
|
|
},
|
|
|
|
//@private
|
|
updateMuted: function(muted) {
|
|
this.fireEvent('mutedchange', this, muted);
|
|
|
|
this.media.dom.muted = muted;
|
|
},
|
|
|
|
/**
|
|
* Returns the current time of the media, in seconds.
|
|
* @return {Number}
|
|
*/
|
|
getCurrentTime: function() {
|
|
return this.media.dom.currentTime;
|
|
},
|
|
|
|
/*
|
|
* Set the current time of the media.
|
|
* @param {Number} time The time, in seconds.
|
|
* @return {Number}
|
|
*/
|
|
setCurrentTime: function(time) {
|
|
this.media.dom.currentTime = time;
|
|
|
|
return time;
|
|
},
|
|
|
|
/**
|
|
* Returns the duration of the media, in seconds.
|
|
* @return {Number}
|
|
*/
|
|
getDuration: function() {
|
|
return this.media.dom.duration;
|
|
},
|
|
|
|
destroy: function() {
|
|
var me = this,
|
|
dom = me.media.dom,
|
|
mediaEvents = me.mediaEvents;
|
|
|
|
Ext.Object.each(mediaEvents, function(event, fn) {
|
|
dom.removeEventListener(event, fn);
|
|
});
|
|
|
|
this.callSuper();
|
|
}
|
|
});
|