前端开发环境的术介绍 notepad前端开发环境 前端开发要配置的环境
视频css文件:
css 代码
视频js文件:
javascript 代码
/*
VideoJS – HTML5 Video Player
v2.0.2
This file is part of VideoJS. Copyright 2010 Zencoder, Inc.
VideoJS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
VideoJS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with VideoJS. If not, see <http://www.gnu.org/licenses/>.
*/
// Self-executing function to prevent global vars and help with minification
;(function(window, undefined) {
var document = window.document
// Using jresig’s Class implementation http://ejohn.org/blog/simple-javascript-inheritance/
;(function() {
var initializing = false,
fnTest = /xyz/.test(function() {
xyz
})
? /\b_super\b/
: /.*/
this.JRClass = function() {}
JRClass.extend = function(prop) {
var _super = this.prototype
initializing = true
var prototype = new this()
initializing = false
for (var name in prop) {
prototype[name] =
typeof prop[name] == ‘function’ &&
typeof _super[name] == ‘function’ &&
fnTest.test(prop[name])
? (function(name, fn) {
return function() {
var tmp = this._super
this._super = _super[name]
var ret = fn.apply(this, arguments)
this._super = tmp
return ret
}
})(name, prop[name])
: prop[name]
}
function JRClass() {
if (!initializing && this.init) this.init.apply(this, arguments)
}
JRClass.prototype = prototype
JRClass.constructor = JRClass
JRClass.extend = arguments.callee
return JRClass
}
})()
// Video JS Player Class
var VideoJS = JRClass.extend({
// Initialize the player for the supplied video tag element
// element: video tag
init: function(element, setOptions) {
// Allow an ID string or an element
if (typeof element == ‘string’) {
this.video = document.getElementById(element)
} else {
this.video = element
}
// Store reference to player on the video element.
// So you can acess the player later: document.getElementById(“video_id”).player.play();
this.video.player = this
this.values = {} // Cache video values.
this.elements = {} // Store refs to controls elements.
// Default Options
this.options = {
autoplay: false,
preload: true,
useBuiltInControls: false, // Use the browser’s controls (iPhone)
controlsBelow: false, // Display control bar below video vs. in front of
controlsAtStart: false, // Make controls visible when page loads
controlsHiding: true, // Hide controls when not over the video
defaultVolume: 0.85, // Will be overridden by localStorage volume if available
playerFallbackOrder: [‘html5’, ‘flash’, ‘links’], // Players and order to use them
flashPlayer: ‘htmlObject’,
flashPlayerVersion: false, // Required flash version for fallback
}
// Override default options with global options
if (typeof VideoJS.options == ‘object’) {
_V_.merge(this.options, VideoJS.options)
}
// Override default & global options with options specific to this player
if (typeof setOptions == ‘object’) {
_V_.merge(this.options, setOptions)
}
// Override preload & autoplay with video attributes
if (this.getPreloadAttribute() !== undefined) {
this.options.preload = this.getPreloadAttribute()
}
if (this.getAutoplayAttribute() !== undefined) {
this.options.autoplay = this.getAutoplayAttribute()
}
// Store reference to embed code pieces
this.box = this.video.parentNode
this.linksFallback = this.getLinksFallback()
this.hideLinksFallback() // Will be shown again if “links” player is used
// Loop through the player names list in options, “html5″ etc.
// For each player name, initialize the player with that name under VideoJS.players
// If the player successfully initializes, we’re done
// If not, try the next player in the list
this.each(this.options.playerFallbackOrder, function(playerType) {
if (this[playerType + ‘Supported’]()) {
// Check if player type is supported
this[playerType + ‘Init’]() // Initialize player type
return true // Stop looping though players
}
})
// Start Global Listeners – API doesn’t exist before now
this.activateElement(this, ‘player’)
this.activateElement(this.box, ‘box’)
},
/* Behaviors
================================================================================ */
behaviors: {},
newBehavior: function(name, activate, functions) {
this.behaviors[name] = activate
this.extend(functions)
},
activateElement: function(element, behavior) {
// Allow passing and ID string
if (typeof element == ‘string’) {
element = document.getElementById(element)
}
this.behaviors[behavior].call(this, element)
},
/* Errors/Warnings
================================================================================ */
errors: [], // Array to track errors
warnings: [],
warning: function(warning) {
this.warnings.push(warning)
this.log(warning)
},
/* History of errors/events (not quite there yet)
================================================================================ */
history: [],
log: function(event) {
if (!event) {
return
}
if (typeof event == ‘string’) {
event = { type: event }
}
if (event.type) {
this.history.push(event.type)
}
if (this.history.length >= 50) {
this.history.shift()
}
try {
console.log(event.type)
} catch (e) {
try {
opera.postError(event.type)
} catch (e) {}
}
},
/* Local Storage
================================================================================ */
setLocalStorage: function(key, value) {
if (!localStorage) {
return
}
try {
localStorage[key] = value
} catch (e) {
if (e.code == 22 || e.code == 1014) {
// Webkit == 22 / Firefox == 1014
this.warning(VideoJS.warnings.localStorageFull)
}
}
},
/* Helpers
================================================================================ */
getPreloadAttribute: function() {
if (
typeof this.video.hasAttribute == ‘function’ &&
this.video.hasAttribute(‘preload’)
) {
var preload = this.video.getAttribute(‘preload’)
// Only included the attribute, thinking it was boolean
if (preload === ” || preload === ‘true’) {
return ‘auto’
}
if (preload === ‘false’) {
return ‘none’
}
return preload
}
},
getAutoplayAttribute: function() {
if (
typeof this.video.hasAttribute == ‘function’ &&
this.video.hasAttribute(‘autoplay’)
) {
var autoplay = this.video.getAttribute(‘autoplay’)
if (autoplay === ‘false’) {
return false
}
return true
}
},
// Calculates amoutn of buffer is full
bufferedPercent: function() {
return this.duration() ? this.buffered()[1] / this.duration() : 0
},
// Each that maintains player as context
// Break if true is returned
each: function(arr, fn) {
if (!arr || arr.length === 0) {
return
}
for (var i = 0, j = arr.length; i < j; i++) {
if (fn.call(this, arr[i], i)) {
break
}
}
},
extend: function(obj) {
for (var attrname in obj) {
if (obj.hasOwnProperty(attrname)) {
this[attrname] = obj[attrname]
}
}
},
})
VideoJS.player = VideoJS.prototype
////////////////////////////////////////////////////////////////////////////////
// Player Types
////////////////////////////////////////////////////////////////////////////////
/* Flash Object Fallback (Player Type)
================================================================================ */
VideoJS.player.extend({
flashSupported: function() {
if (!this.flashElement) {
this.flashElement = this.getFlashElement()
}
// Check if object exists & Flash Player version is supported
if (this.flashElement && this.flashPlayerVersionSupported()) {
return true
} else {
return false
}
},
flashInit: function() {
this.replaceWithFlash()
this.element = this.flashElement
this.video.src = ” // Stop video from downloading if HTML5 is still supported
var flashPlayerType = VideoJS.flashPlayers[this.options.flashPlayer]
this.extend(VideoJS.flashPlayers[this.options.flashPlayer].api)
flashPlayerType.init.context(this)()
},
// Get Flash Fallback object element from Embed Code
getFlashElement: function() {
var children = this.video.children
for (var i = 0, j = children.length; i < j; i++) {
if (children[i].className == ‘vjs-flash-fallback’) {
return children[i]
}
}
},
// Used to force a browser to fall back when it’s an HTML5 browser but there’s no supported sources
replaceWithFlash: function() {
// this.flashElement = this.video.removeChild(this.flashElement);
if (this.flashElement) {
this.box.insertBefore(this.flashElement, this.video)
this.video.style.display = ‘none’ // Removing it was breaking later players
}
},
// Check if browser can use this flash player
flashPlayerVersionSupported: function() {
var playerVersion = this.options.flashPlayerVersion
? this.options.flashPlayerVersion
: VideoJS.flashPlayers[this.options.flashPlayer].flashPlayerVersion
return VideoJS.getFlashVersion() >= playerVersion
},
})
VideoJS.flashPlayers = {}
VideoJS.flashPlayers.htmlObject = {
flashPlayerVersion: 9,
init: function() {
return true
},
api: {
// No video API available with HTML Object embed method
width: function(width) {
if (width !== undefined) {
this.element.width = width
this.box.style.width = width + ‘px’
this.triggerResizeListeners()
return this
}
return this.element.width
},
height: function(height) {
if (height !== undefined) {
this.element.height = height
this.box.style.height = height + ‘px’
this.triggerResizeListeners()
return this
}
return this.element.height
},
},
}
/* Download Links Fallback (Player Type)
================================================================================ */
VideoJS.player.extend({
linksSupported: function() {
return true
},
linksInit: function() {
this.showLinksFallback()
this.element = this.video
},
// Get the download links block element
getLinksFallback: function() {
return this.box.getElementsByTagName(‘P’)[0]
},
// Hide no-video download paragraph
hideLinksFallback: function() {
if (this.linksFallback) {
this.linksFallback.style.display = ‘none’
}
},
// Hide no-video download paragraph
showLinksFallback: function() {
if (this.linksFallback) {
this.linksFallback.style.display = ‘block’
}
},
})
////////////////////////////////////////////////////////////////////////////////
// Class Methods
// Functions that don’t apply to individual videos.
////////////////////////////////////////////////////////////////////////////////
// Combine Objects – Use “safe” to protect from overwriting existing items
VideoJS.merge = function(obj1, obj2, safe) {
for (var attrname in obj2) {
if (
obj2.hasOwnProperty(attrname) &&
(!safe || !obj1.hasOwnProperty(attrname))
) {
obj1[attrname] = obj2[attrname]
}
}
return obj1
}
VideoJS.extend = function(obj) {
this.merge(this, obj, true)
}
VideoJS.extend({
// Add VideoJS to all video tags with the video-js class when the DOM is ready
setupAllWhenReady: function(options) {
// Options is stored globally, and added ot any new player on init
VideoJS.options = options
VideoJS.DOMReady(VideoJS.setup)
},
// Run the supplied function when the DOM is ready
DOMReady: function(fn) {
VideoJS.addToDOMReady(fn)
},
// Set up a specific video or array of video elements
// “video” can be:
// false, undefined, or “All”: set up all videos with the video-js class
// A video tag ID or video tag element: set up one video and return one player
// An array of video tag elements/IDs: set up each and return an array of players
setup: function(videos, options) {
var returnSingular = false,
playerList = [],
videoElement
// If videos is undefined or “All”, set up all videos with the video-js class
if (!videos || videos == ‘All’) {
videos = VideoJS.getVideoJSTags()
// If videos is not an array, add to an array
} else if (typeof videos != ‘object’ || videos.nodeType == 1) {
videos = [videos]
returnSingular = true
}
// Loop through videos and create players for them
for (var i = 0; i < videos.length; i++) {
if (typeof videos[i] == ‘string’) {
videoElement = document.getElementById(videos[i])
} else {
// assume DOM object
videoElement = videos[i]
}
playerList.push(new VideoJS(videoElement, options))
}
// Return one or all depending on what was passed in
return returnSingular ? playerList[0] : playerList
},
// Find video tags with the video-js class
getVideoJSTags: function() {
var videoTags = document.getElementsByTagName(‘video’),
videoJSTags = [],
videoTag
for (var i = 0, j = videoTags.length; i < j; i++) {
videoTag = videoTags[i]
if (videoTag.className.indexOf(‘video-js’) != -1) {
videoJSTags.push(videoTag)
}
}
return videoJSTags
},
// Check if the browser supports video.
browserSupportsVideo: function() {
if (typeof VideoJS.videoSupport != ‘undefined’) {
return VideoJS.videoSupport
}
VideoJS.videoSupport = !!document.createElement(‘video’).canPlayType
return VideoJS.videoSupport
},
getFlashVersion: function() {
// Cache Version
if (typeof VideoJS.flashVersion != ‘undefined’) {
return VideoJS.flashVersion
}
var version = 0,
desc
if (
typeof navigator.plugins != ‘undefined’ &&
typeof navigator.plugins[‘Shockwave Flash’] == ‘object’
) {
desc = navigator.plugins[‘Shockwave Flash’].description
if (
desc &&
!(
typeof navigator.mimeTypes != ‘undefined’ &&
navigator.mimeTypes[‘application/x-shockwave-flash’] &&
!navigator.mimeTypes[‘application/x-shockwave-flash’].enabledPlugin
)
) {
version = parseInt(
desc.match(/^.*\s+([^\s]+)\.[^\s]+\s+[^\s]+$/)[1],
10,
)
}
} else if (typeof window.ActiveXObject != ‘undefined’) {
try {
var testObject = new ActiveXObject(‘ShockwaveFlash.ShockwaveFlash’)
if (testObject) {
version = parseInt(
testObject.GetVariable(‘$version’).match(/^[^\s]+\s(\d+)/)[1],
10,
)
}
} catch (e) {}
}
VideoJS.flashVersion = version
return VideoJS.flashVersion
},
// Browser & Device Checks
isIE: function() {
return !+’\v1′
},
isIPad: function() {
return navigator.userAgent.match(/iPad/i) !== null
},
isIPhone: function() {
return navigator.userAgent.match(/iPhone/i) !== null
},
isIOS: function() {
return VideoJS.isIPhone() || VideoJS.isIPad()
},
iOSVersion: function() {
var match = navigator.userAgent.match(/OS (\d+)_/i)
if (match && match[1]) {
return match[1]
}
},
isAndroid: function() {
return navigator.userAgent.match(/Android/i) !== null
},
androidVersion: function() {
var match = navigator.userAgent.match(/Android (\d+)\./i)
if (match && match[1]) {
return match[1]
}
},
warnings: {
// Safari errors if you call functions on a video that hasn’t loaded yet
videoNotReady: ‘Video is not ready yet (try playing the video first).’,
// Getting a QUOTA_EXCEEDED_ERR when setting local storage occasionally
localStorageFull: ‘Local Storage is Full’,
},
})
// Shim to make Video tag valid in IE
if (VideoJS.isIE()) {
document.createElement(‘video’)
}
// Expose to global
window.VideoJS = window._V_ = VideoJS
/* HTML5 Player Type
================================================================================ */
VideoJS.player.extend({
html5Supported: function() {
if (VideoJS.browserSupportsVideo() && this.canPlaySource()) {
return true
} else {
return false
}
},
html5Init: function() {
this.element = this.video
this.fixPreloading() // Support old browsers that used autobuffer
this.supportProgressEvents() // Support browsers that don’t use ‘buffered’
// Set to stored volume OR 85%
this.volume(
(localStorage && localStorage.volume) || this.options.defaultVolume,
)
// Update interface for device needs
if (VideoJS.isIOS()) {
this.options.useBuiltInControls = true
this.iOSInterface()
} else if (VideoJS.isAndroid()) {
this.options.useBuiltInControls = true
this.androidInterface()
}
// Add VideoJS Controls
if (!this.options.useBuiltInControls) {
this.video.controls = false
if (this.options.controlsBelow) {
_V_.addClass(this.box, ‘vjs-controls-below’)
}
// Make a click on th video act as a play button
this.activateElement(this.video, ‘playToggle’)
// Build Interface
this.buildStylesCheckDiv() // Used to check if style are loaded
this.buildAndActivatePoster()
this.buildBigPlayButton()
this.buildAndActivateSpinner()
this.buildAndActivateControlBar()
this.loadInterface() // Show everything once styles are loaded
this.getSubtitles()
}
},
/* Source Managemet
================================================================================ */
canPlaySource: function() {
// Cache Result
if (this.canPlaySourceResult) {
return this.canPlaySourceResult
}
// Loop through sources and check if any can play
var children = this.video.children
for (var i = 0, j = children.length; i < j; i++) {
if (children[i].tagName.toUpperCase() == ‘SOURCE’) {
var canPlay =
this.video.canPlayType(children[i].type) ||
this.canPlayExt(children[i].src)
if (canPlay == ‘probably’ || canPlay == ‘maybe’) {
this.firstPlayableSource = children[i]
this.canPlaySourceResult = true
return true
}
}
}
this.canPlaySourceResult = false
return false
},
// Check if the extention is compatible, for when type won’t work
canPlayExt: function(src) {
if (!src) {
return ”
}
var match = src.match(/\.([^\.]+)$/)
if (match && match[1]) {
var ext = match[1].toLowerCase()
// Android canPlayType doesn’t work
if (VideoJS.isAndroid()) {
if (ext == ‘mp4’ || ext == ‘m4v’) {
return ‘maybe’
}
// Allow Apple HTTP Streaming for iOS
} else if (VideoJS.isIOS()) {
if (ext == ‘m3u8’) {
return ‘maybe’
}
}
}
return ”
},
// Force the video source – Helps fix loading bugs in a handful of devices, like the iPad/iPhone poster bug
// And iPad/iPhone javascript include location bug. And Android type attribute bug
forceTheSource: function() {
this.video.src = this.firstPlayableSource.src // From canPlaySource()
this.video.load()
},
/* Device Fixes
================================================================================ */
// Support older browsers that used “autobuffer”
fixPreloading: function() {
if (
typeof this.video.hasAttribute == ‘function’ &&
this.video.hasAttribute(‘preload’) &&
this.video.preload != ‘none’
) {
this.video.autobuffer = true // Was a boolean
} else {
this.video.autobuffer = false
this.video.preload = ‘none’
}
},
// Listen for Video Load Progress (currently does not if html file is local)
// Buffered does’t work in all browsers, so watching progress as well
supportProgressEvents: function(e) {
_V_.addListener(
this.video,
‘progress’,
this.playerOnVideoProgress.context(this),
)
},
playerOnVideoProgress: function(event) {
this.setBufferedFromProgress(event)
},
setBufferedFromProgress: function(event) {
// HTML5 Only
if (event.total > 0) {
var newBufferEnd = (event.loaded / event.total) * this.duration()
if (newBufferEnd > this.values.bufferEnd) {
this.values.bufferEnd = newBufferEnd
}
}
},
iOSInterface: function() {
if (VideoJS.iOSVersion() < 4) {
this.forceTheSource()
} // Fix loading issues
if (VideoJS.isIPad()) {
// iPad could work with controlsBelow
this.buildAndActivateSpinner() // Spinner still works well on iPad, since iPad doesn’t have one
}
// 自己添加修改的用于苹果手机上显示中间的播放按钮
this.forceTheSource() // Fix loading issues
_V_.addListener(this.video, ‘click’, function() {
this.play()
}) // Required to play
this.buildBigPlayButton() // But don’t activate the normal way. Pause doesn’t work right on android.
_V_.addListener(
this.bigPlayButton,
‘click’,
function() {
this.play()
}.context(this),
)
this.positionBox()
this.showBigPlayButtons()
},
// Fix android specific quirks
// Use built-in controls, but add the big play button, since android doesn’t have one.
androidInterface: function() {
this.forceTheSource() // Fix loading issues
_V_.addListener(this.video, ‘click’, function() {
this.play()
}) // Required to play
this.buildBigPlayButton() // But don’t activate the normal way. Pause doesn’t work right on android.
_V_.addListener(
this.bigPlayButton,
‘click’,
function() {
this.play()
}.context(this),
)
this.positionBox()
this.showBigPlayButtons()
},
/* Wait for styles (TODO: move to _V_)
================================================================================ */
loadInterface: function() {
if (!this.stylesHaveLoaded()) {
// Don’t want to create an endless loop either.
if (!this.positionRetries) {
this.positionRetries = 1
}
if (this.positionRetries++ < 100) {
setTimeout(this.loadInterface.context(this), 10)
return
}
}
this.hideStylesCheckDiv()
this.showPoster()
if (this.video.paused !== false) {
this.showBigPlayButtons()
}
if (this.options.controlsAtStart) {
this.showControlBars()
}
this.positionAll()
},
/* Control Bar
================================================================================ */
buildAndActivateControlBar: function() {
/* Creating this HTML
<div class=”vjs-controls”>
<div class=”vjs-play-control”>
<span></span>
</div>
<div class=”vjs-progress-control”>
<div class=”vjs-progress-holder”>
<div class=”vjs-load-progress”></div>
<div class=”vjs-play-progress”></div>
</div>
</div>
<div class=”vjs-time-control”>
<span class=”vjs-current-time-display”>00:00</span><span> / </span><span class=”vjs-duration-display”>00:00</span>
</div>
<div class=”vjs-volume-control”>
<div>
<span></span><span></span><span></span><span></span><span></span><span></span>
</div>
</div>
<div class=”vjs-fullscreen-control”>
<div>
<span></span><span></span><span></span><span></span>
</div>
</div>
</div>
*/
// Create a div to hold the different controls
this.controls = _V_.createElement(‘div’, { className: ‘vjs-controls’ })
// Add the controls to the video’s container
this.box.appendChild(this.controls)
this.activateElement(this.controls, ‘controlBar’)
this.activateElement(this.controls, ‘mouseOverVideoReporter’)
// Build the play control
this.playControl = _V_.createElement(‘div’, {
className: ‘vjs-play-control’,
innerHTML: ‘<span></span>’,
})
this.controls.appendChild(this.playControl)
this.activateElement(this.playControl, ‘playToggle’)
// Build the progress control
this.progressControl = _V_.createElement(‘div’, {
className: ‘vjs-progress-control’,
})
this.controls.appendChild(this.progressControl)
// Create a holder for the progress bars
this.progressHolder = _V_.createElement(‘div’, {
className: ‘vjs-progress-holder’,
})
this.progressControl.appendChild(this.progressHolder)
this.activateElement(this.progressHolder, ‘currentTimeScrubber’)
// Create the loading progress display
this.loadProgressBar = _V_.createElement(‘div’, {
className: ‘vjs-load-progress’,
})
this.progressHolder.appendChild(this.loadProgressBar)
this.activateElement(this.loadProgressBar, ‘loadProgressBar’)
// Create the playing progress display
this.playProgressBar = _V_.createElement(‘div’, {
className: ‘vjs-play-progress’,
})
this.progressHolder.appendChild(this.playProgressBar)
this.activateElement(this.playProgressBar, ‘playProgressBar’)
// Create the progress time display (00:00 / 00:00)
this.timeControl = _V_.createElement(‘div’, {
className: ‘vjs-time-control’,
})
this.controls.appendChild(this.timeControl)
// Create the current play time display
this.currentTimeDisplay = _V_.createElement(‘span’, {
className: ‘vjs-current-time-display’,
innerHTML: ’00:00′,
})
this.timeControl.appendChild(this.currentTimeDisplay)
this.activateElement(this.currentTimeDisplay, ‘currentTimeDisplay’)
// Add time separator
this.timeSeparator = _V_.createElement(‘span’, { innerHTML: ‘ / ‘ })
this.timeControl.appendChild(this.timeSeparator)
// Create the total duration display
this.durationDisplay = _V_.createElement(‘span’, {
className: ‘vjs-duration-display’,
innerHTML: ’00:00′,
})
this.timeControl.appendChild(this.durationDisplay)
this.activateElement(this.durationDisplay, ‘durationDisplay’)
// Create the volumne control
this.volumeControl = _V_.createElement(‘div’, {
className: ‘vjs-volume-control’,
innerHTML:
‘<div><span></span><span></span><span></span><span></span><span></span><span></span></div>’,
})
this.controls.appendChild(this.volumeControl)
this.activateElement(this.volumeControl, ‘volumeScrubber’)
this.volumeDisplay = this.volumeControl.children[0]
this.activateElement(this.volumeDisplay, ‘volumeDisplay’)
// Crete the fullscreen control
this.fullscreenControl = _V_.createElement(‘div’, {
className: ‘vjs-fullscreen-control’,
innerHTML:
‘<div><span></span><span></span><span></span><span></span></div>’,
})
this.controls.appendChild(this.fullscreenControl)
this.activateElement(this.fullscreenControl, ‘fullscreenToggle’)
},
/* Poster Image
================================================================================ */
buildAndActivatePoster: function() {
this.updatePosterSource()
if (this.video.poster) {
this.poster = document.createElement(‘img’)
// Add poster to video box
this.box.appendChild(this.poster)
// Add poster image data
this.poster.src = this.video.poster
// Add poster styles
this.poster.className = ‘vjs-poster’
this.activateElement(this.poster, ‘poster’)
} else {
this.poster = false
}
},
/* Big Play Button
================================================================================ */
buildBigPlayButton: function() {
/* Creating this HTML
<div class=”vjs-big-play-button”><span></span></div>
*/
this.bigPlayButton = _V_.createElement(‘div’, {
className: ‘vjs-big-play-button’,
innerHTML: ‘<span></span>’,
})
this.box.appendChild(this.bigPlayButton)
this.activateElement(this.bigPlayButton, ‘bigPlayButton’)
},
/* Spinner (Loading)
================================================================================ */
buildAndActivateSpinner: function() {
this.spinner = _V_.createElement(‘div’, {
className: ‘vjs-spinner’,
innerHTML:
‘<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>’,
})
this.box.appendChild(this.spinner)
this.activateElement(this.spinner, ‘spinner’)
},
/* Styles Check – Check if styles are loaded (move ot _V_)
================================================================================ */
// Sometimes the CSS styles haven’t been applied to the controls yet
// when we’re trying to calculate the height and position them correctly.
// This causes a flicker where the controls are out of place.
buildStylesCheckDiv: function() {
this.stylesCheckDiv = _V_.createElement(‘div’, {
className: ‘vjs-styles-check’,
})
this.stylesCheckDiv.style.position = ‘absolute’
this.box.appendChild(this.stylesCheckDiv)
},
hideStylesCheckDiv: function() {
this.stylesCheckDiv.style.display = ‘none’
},
stylesHaveLoaded: function() {
if (this.stylesCheckDiv.offsetHeight != 5) {
return false
} else {
return true
}
},
/* VideoJS Box – Holds all elements
================================================================================ */
positionAll: function() {
this.positionBox()
this.positionControlBars()
this.positionPoster()
},
positionBox: function() {
// Set width based on fullscreen or not.
if (this.videoIsFullScreen) {
this.box.style.width = ”
this.element.style.height = ”
if (this.options.controlsBelow) {
this.box.style.height = ”
this.element.style.height =
this.box.offsetHeight – this.controls.offsetHeight + ‘px’
}
} else {
this.box.style.width = this.width() + ‘px’
this.element.style.height = this.height() + ‘px’
if (this.options.controlsBelow) {
this.element.style.height = ”
// this.box.style.height = this.video.offsetHeight + this.controls.offsetHeight + “px”;
}
}
},
/* Subtitles
================================================================================ */
getSubtitles: function() {
var tracks = this.video.getElementsByTagName(‘TRACK’)
for (var i = 0, j = tracks.length; i < j; i++) {
if (
tracks[i].getAttribute(‘kind’) == ‘subtitles’ &&
tracks[i].getAttribute(‘src’)
) {
this.subtitlesSource = tracks[i].getAttribute(‘src’)
this.loadSubtitles()
this.buildSubtitles()
}
}
},
loadSubtitles: function() {
_V_.get(this.subtitlesSource, this.parseSubtitles.context(this))
},
parseSubtitles: function(subText) {
var lines = subText.split(‘\n’),
line = ”,
subtitle,
time,
text
this.subtitles = []
this.currentSubtitle = false
this.lastSubtitleIndex = 0
for (var i = 0; i < lines.length; i++) {
line = _V_.trim(lines[i]) // Trim whitespace and linebreaks
if (line) {
// Loop until a line with content
// First line – Number
subtitle = {
id: line, // Subtitle Number
index: this.subtitles.length, // Position in Array
}
// Second line – Time
line = _V_.trim(lines[++i])
time = line.split(‘ –> ‘)
subtitle.start = this.parseSubtitleTime(time[0])
subtitle.end = this.parseSubtitleTime(time[1])
// Additional lines – Subtitle Text
text = []
for (var j = i; j < lines.length; j++) {
// Loop until a blank line or end of lines
line = _V_.trim(lines[++i])
if (!line) {
break
}
text.push(line)
}
subtitle.text = text.join(‘<br/>’)
// Add this subtitle
this.subtitles.push(subtitle)
}
}
},
parseSubtitleTime: function(timeText) {
var parts = timeText.split(‘:’),
time = 0
// hours => seconds
time += parseFloat(parts[0]) * 60 * 60
// minutes => seconds
time += parseFloat(parts[1]) * 60
// get seconds
var seconds = parts[2].split(/\.|,/) // Either . or ,
time += parseFloat(seconds[0])
// add miliseconds
ms = parseFloat(seconds[1])
if (ms) {
time += ms / 1000
}
return time
},
buildSubtitles: function() {
/* Creating this HTML
<div class=”vjs-subtitles”></div>
*/
this.subtitlesDisplay = _V_.createElement(‘div’, {
className: ‘vjs-subtitles’,
})
this.box.appendChild(this.subtitlesDisplay)
this.activateElement(this.subtitlesDisplay, ‘subtitlesDisplay’)
},
/* Player API – Translate functionality from player to video
================================================================================ */
addVideoListener: function(type, fn) {
_V_.addListener(this.video, type, fn.rEvtContext(this))
},
play: function() {
this.video.play()
return this
},
onPlay: function(fn) {
this.addVideoListener(‘play’, fn)
return this
},
pause: function() {
this.video.pause()
return this
},
onPause: function(fn) {
this.addVideoListener(‘pause’, fn)
return this
},
paused: function() {
return this.video.paused
},
currentTime: function(seconds) {
if (seconds !== undefined) {
try {
this.video.currentTime = seconds
} catch (e) {
this.warning(VideoJS.warnings.videoNotReady)
}
this.values.currentTime = seconds
return this
}
return this.video.currentTime
},
onCurrentTimeUpdate: function(fn) {
this.currentTimeListeners.push(fn)
},
duration: function() {
return this.video.duration
},
buffered: function() {
// Storing values allows them be overridden by setBufferedFromProgress
if (this.values.bufferStart === undefined) {
this.values.bufferStart = 0
this.values.bufferEnd = 0
}
if (this.video.buffered && this.video.buffered.length > 0) {
var newEnd = this.video.buffered.end(0)
if (newEnd > this.values.bufferEnd) {
this.values.bufferEnd = newEnd
}
}
return [this.values.bufferStart, this.values.bufferEnd]
},
volume: function(percentAsDecimal) {
if (percentAsDecimal !== undefined) {
// Force value to between 0 and 1
this.values.volume = Math.max(
0,
Math.min(1, parseFloat(percentAsDecimal)),
)
this.video.volume = this.values.volume
this.setLocalStorage(‘volume’, this.values.volume)
return this
}
if (this.values.volume) {
return this.values.volume
}
return this.video.volume
},
onVolumeChange: function(fn) {
_V_.addListener(this.video, ‘volumechange’, fn.rEvtContext(this))
},
width: function(width) {
if (width !== undefined) {
this.video.width = width // Not using style so it can be overridden on fullscreen.
this.box.style.width = width + ‘px’
this.triggerResizeListeners()
return this
}
return this.video.offsetWidth
},
height: function(height) {
if (height !== undefined) {
this.video.height = height
this.box.style.height = height + ‘px’
this.triggerResizeListeners()
return this
}
return this.video.offsetHeight
},
supportsFullScreen: function() {
if (typeof this.video.webkitEnterFullScreen == ‘function’) {
// Seems to be broken in Chromium/Chrome
if (
!navigator.userAgent.match(‘Chrome’) &&
!navigator.userAgent.match(‘Mac OS X 10.5’)
) {
return true
}
}
return false
},
html5EnterNativeFullScreen: function() {
try {
this.video.webkitEnterFullScreen()
} catch (e) {
if (e.code == 11) {
this.warning(VideoJS.warnings.videoNotReady)
}
}
return this
},
// Turn on fullscreen (window) mode
// Real fullscreen isn’t available in browsers quite yet.
enterFullScreen: function() {
if (this.supportsFullScreen()) {
this.html5EnterNativeFullScreen()
} else {
this.enterFullWindow()
}
},
exitFullScreen: function() {
if (this.supportsFullScreen()) {
// Shouldn’t be called
} else {
this.exitFullWindow()
}
},
enterFullWindow: function() {
this.videoIsFullScreen = true
// Storing original doc overflow value to return to when fullscreen is off
this.docOrigOverflow = document.documentElement.style.overflow
// Add listener for esc key to exit fullscreen
_V_.addListener(
document,
‘keydown’,
this.fullscreenOnEscKey.rEvtContext(this),
)
// Add listener for a window resize
_V_.addListener(
window,
‘resize’,
this.fullscreenOnWindowResize.rEvtContext(this),
)
// Hide any scroll bars
document.documentElement.style.overflow = ‘hidden’
// Apply fullscreen styles
_V_.addClass(this.box, ‘vjs-fullscreen’)
// Resize the box, controller, and poster
this.positionAll()
},
// Turn off fullscreen (window) mode
exitFullWindow: function() {
this.videoIsFullScreen = false
document.removeEventListener(‘keydown’, this.fullscreenOnEscKey, false)
window.removeEventListener(‘resize’, this.fullscreenOnWindowResize, false)
// Unhide scroll bars.
document.documentElement.style.overflow = this.docOrigOverflow
// Remove fullscreen styles
_V_.removeClass(this.box, ‘vjs-fullscreen’)
// Resize the box, controller, and poster to original sizes
this.positionAll()
},
onError: function(fn) {
this.addVideoListener(‘error’, fn)
return this
},
onEnded: function(fn) {
this.addVideoListener(‘ended’, fn)
return this
},
})
////////////////////////////////////////////////////////////////////////////////
// Element Behaviors
// Tell elements how to act or react
////////////////////////////////////////////////////////////////////////////////
/* Player Behaviors – How VideoJS reacts to what the video is doing.
================================================================================ */
VideoJS.player.newBehavior(
‘player’,
function(player) {
this.onError(this.playerOnVideoError)
// Listen for when the video is played
this.onPlay(this.playerOnVideoPlay)
this.onPlay(this.trackCurrentTime)
// Listen for when the video is paused
this.onPause(this.playerOnVideoPause)
this.onPause(this.stopTrackingCurrentTime)
// Listen for when the video ends
this.onEnded(this.playerOnVideoEnded)
// Set interval for load progress using buffer watching method
// this.trackCurrentTime();
this.trackBuffered()
// Buffer Full
this.onBufferedUpdate(this.isBufferFull)
},
{
playerOnVideoError: function(event) {
this.log(event)
this.log(this.video.error)
},
playerOnVideoPlay: function(event) {
this.hasPlayed = true
},
playerOnVideoPause: function(event) {},
playerOnVideoEnded: function(event) {
this.currentTime(0)
this.pause()
},
/* Load Tracking ————————————————————– */
// Buffer watching method for load progress.
// Used for browsers that don’t support the progress event
trackBuffered: function() {
this.bufferedInterval = setInterval(
this.triggerBufferedListeners.context(this),
500,
)
},
stopTrackingBuffered: function() {
clearInterval(this.bufferedInterval)
},
bufferedListeners: [],
onBufferedUpdate: function(fn) {
this.bufferedListeners.push(fn)
},
triggerBufferedListeners: function() {
this.isBufferFull()
this.each(this.bufferedListeners, function(listener) {
listener.context(this)()
})
},
isBufferFull: function() {
if (this.bufferedPercent() == 1) {
this.stopTrackingBuffered()
}
},
/* Time Tracking ————————————————————– */
trackCurrentTime: function() {
if (this.currentTimeInterval) {
clearInterval(this.currentTimeInterval)
}
this.currentTimeInterval = setInterval(
this.triggerCurrentTimeListeners.context(this),
100,
) // 42 = 24 fps
this.trackingCurrentTime = true
},
// Turn off play progress tracking (when paused or dragging)
stopTrackingCurrentTime: function() {
clearInterval(this.currentTimeInterval)
this.trackingCurrentTime = false
},
currentTimeListeners: [],
// onCurrentTimeUpdate is in API section now
triggerCurrentTimeListeners: function(late, newTime) {
// FF passes milliseconds late as the first argument
this.each(this.currentTimeListeners, function(listener) {
listener.context(this)(newTime || this.currentTime())
})
},
/* Resize Tracking ————————————————————– */
resizeListeners: [],
onResize: function(fn) {
this.resizeListeners.push(fn)
},
// Trigger anywhere the video/box size is changed.
triggerResizeListeners: function() {
this.each(this.resizeListeners, function(listener) {
listener.context(this)()
})
},
},
)
/* Mouse Over Video Reporter Behaviors – i.e. Controls hiding based on mouse location
================================================================================ */
VideoJS.player.newBehavior(
‘mouseOverVideoReporter’,
function(element) {
// Listen for the mouse move the video. Used to reveal the controller.
_V_.addListener(
element,
‘mousemove’,
this.mouseOverVideoReporterOnMouseMove.context(this),
)
// Listen for the mouse moving out of the video. Used to hide the controller.
_V_.addListener(
element,
‘mouseout’,
this.mouseOverVideoReporterOnMouseOut.context(this),
)
},
{
mouseOverVideoReporterOnMouseMove: function() {
this.showControlBars()
clearInterval(this.mouseMoveTimeout)
this.mouseMoveTimeout = setTimeout(
this.hideControlBars.context(this),
4000,
)
},
mouseOverVideoReporterOnMouseOut: function(event) {
// Prevent flicker by making sure mouse hasn’t left the video
var parent = event.relatedTarget
while (parent && parent !== this.box) {
parent = parent.parentNode
}
if (parent !== this.box) {
this.hideControlBars()
}
},
},
)
/* Mouse Over Video Reporter Behaviors – i.e. Controls hiding based on mouse location
================================================================================ */
VideoJS.player.newBehavior(
‘box’,
function(element) {
this.positionBox()
_V_.addClass(element, ‘vjs-paused’)
this.activateElement(element, ‘mouseOverVideoReporter’)
this.onPlay(this.boxOnVideoPlay)
this.onPause(this.boxOnVideoPause)
},
{
boxOnVideoPlay: function() {
_V_.removeClass(this.box, ‘vjs-paused’)
_V_.addClass(this.box, ‘vjs-playing’)
},
boxOnVideoPause: function() {
_V_.removeClass(this.box, ‘vjs-playing’)
_V_.addClass(this.box, ‘vjs-paused’)
},
},
)
/* Poster Image Overlay
================================================================================ */
VideoJS.player.newBehavior(
‘poster’,
function(element) {
this.activateElement(element, ‘mouseOverVideoReporter’)
this.activateElement(element, ‘playButton’)
this.onPlay(this.hidePoster)
this.onEnded(this.showPoster)
this.onResize(this.positionPoster)
},
{
showPoster: function() {
if (!this.poster) {
return
}
this.poster.style.display = ‘block’
this.positionPoster()
},
positionPoster: function() {
// Only if the poster is visible
if (!this.poster || this.poster.style.display == ‘none’) {
return
}
this.poster.style.height = this.height() + ‘px’ // Need incase controlsBelow
this.poster.style.width = this.width() + ‘px’ // Could probably do 100% of box
},
hidePoster: function() {
if (!this.poster) {
return
}
this.poster.style.display = ‘none’
},
// Update poster source from attribute or fallback image
// iPad breaks if you include a poster attribute, so this fixes that
updatePosterSource: function() {
if (!this.video.poster) {
var images = this.video.getElementsByTagName(‘img’)
if (images.length > 0) {
this.video.poster = images[0].src
}
}
},
},
)
/* Control Bar Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘controlBar’,
function(element) {
if (!this.controlBars) {
this.controlBars = []
this.onResize(this.positionControlBars)
}
this.controlBars.push(element)
_V_.addListener(
element,
‘mousemove’,
this.onControlBarsMouseMove.context(this),
)
_V_.addListener(
element,
‘mouseout’,
this.onControlBarsMouseOut.context(this),
)
},
{
showControlBars: function() {
if (!this.options.controlsAtStart && !this.hasPlayed) {
return
}
this.each(this.controlBars, function(bar) {
bar.style.display = ‘block’
})
},
// Place controller relative to the video’s position (now just resizing bars)
positionControlBars: function() {
this.updatePlayProgressBars()
this.updateLoadProgressBars()
},
hideControlBars: function() {
if (this.options.controlsHiding && !this.mouseIsOverControls) {
this.each(this.controlBars, function(bar) {
bar.style.display = ‘none’
})
}
},
// Block controls from hiding when mouse is over them.
onControlBarsMouseMove: function() {
this.mouseIsOverControls = true
},
onControlBarsMouseOut: function(event) {
this.mouseIsOverControls = false
},
},
)
/* PlayToggle, PlayButton, PauseButton Behaviors
================================================================================ */
// Play Toggle
VideoJS.player.newBehavior(
‘playToggle’,
function(element) {
if (!this.elements.playToggles) {
this.elements.playToggles = []
this.onPlay(this.playTogglesOnPlay)
this.onPause(this.playTogglesOnPause)
}
this.elements.playToggles.push(element)
_V_.addListener(element, ‘click’, this.onPlayToggleClick.context(this))
},
{
onPlayToggleClick: function(event) {
if (this.paused()) {
this.play()
} else {
this.pause()
}
},
playTogglesOnPlay: function(event) {
this.each(this.elements.playToggles, function(toggle) {
_V_.removeClass(toggle, ‘vjs-paused’)
_V_.addClass(toggle, ‘vjs-playing’)
})
},
playTogglesOnPause: function(event) {
this.each(this.elements.playToggles, function(toggle) {
_V_.removeClass(toggle, ‘vjs-playing’)
_V_.addClass(toggle, ‘vjs-paused’)
})
},
},
)
// Play
VideoJS.player.newBehavior(
‘playButton’,
function(element) {
_V_.addListener(element, ‘click’, this.onPlayButtonClick.context(this))
},
{
onPlayButtonClick: function(event) {
this.play()
},
},
)
// Pause
VideoJS.player.newBehavior(
‘pauseButton’,
function(element) {
_V_.addListener(element, ‘click’, this.onPauseButtonClick.context(this))
},
{
onPauseButtonClick: function(event) {
this.pause()
},
},
)
/* Play Progress Bar Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘playProgressBar’,
function(element) {
if (!this.playProgressBars) {
this.playProgressBars = []
this.onCurrentTimeUpdate(this.updatePlayProgressBars)
}
this.playProgressBars.push(element)
},
{
// Ajust the play progress bar’s width based on the current play time
updatePlayProgressBars: function(newTime) {
var progress =
newTime !== undefined
? newTime / this.duration()
: this.currentTime() / this.duration()
if (isNaN(progress)) {
progress = 0
}
this.each(this.playProgressBars, function(bar) {
if (bar.style) {
bar.style.width = _V_.round(progress * 100, 2) + ‘%’
}
})
},
},
)
/* Load Progress Bar Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘loadProgressBar’,
function(element) {
if (!this.loadProgressBars) {
this.loadProgressBars = []
}
this.loadProgressBars.push(element)
this.onBufferedUpdate(this.updateLoadProgressBars)
},
{
updateLoadProgressBars: function() {
this.each(this.loadProgressBars, function(bar) {
if (bar.style) {
bar.style.width = _V_.round(this.bufferedPercent() * 100, 2) + ‘%’
}
})
},
},
)
/* Current Time Display Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘currentTimeDisplay’,
function(element) {
if (!this.currentTimeDisplays) {
this.currentTimeDisplays = []
this.onCurrentTimeUpdate(this.updateCurrentTimeDisplays)
}
this.currentTimeDisplays.push(element)
},
{
// Update the displayed time (00:00)
updateCurrentTimeDisplays: function(newTime) {
if (!this.currentTimeDisplays) {
return
}
// Allows for smooth scrubbing, when player can’t keep up.
var time = newTime ? newTime : this.currentTime()
this.each(this.currentTimeDisplays, function(dis) {
dis.innerHTML = _V_.formatTime(time)
})
},
},
)
/* Duration Display Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘durationDisplay’,
function(element) {
if (!this.durationDisplays) {
this.durationDisplays = []
this.onCurrentTimeUpdate(this.updateDurationDisplays)
}
this.durationDisplays.push(element)
},
{
updateDurationDisplays: function() {
if (!this.durationDisplays) {
return
}
this.each(this.durationDisplays, function(dis) {
if (this.duration()) {
dis.innerHTML = _V_.formatTime(this.duration())
}
})
},
},
)
/* Current Time Scrubber Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘currentTimeScrubber’,
function(element) {
_V_.addListener(
element,
‘mousedown’,
this.onCurrentTimeScrubberMouseDown.rEvtContext(this),
)
},
{
// Adjust the play position when the user drags on the progress bar
onCurrentTimeScrubberMouseDown: function(event, scrubber) {
event.preventDefault()
this.currentScrubber = scrubber
this.stopTrackingCurrentTime() // Allows for smooth scrubbing
this.videoWasPlaying = !this.paused()
this.pause()
_V_.blockTextSelection()
this.setCurrentTimeWithScrubber(event)
_V_.addListener(
document,
‘mousemove’,
this.onCurrentTimeScrubberMouseMove.rEvtContext(this),
)
_V_.addListener(
document,
‘mouseup’,
this.onCurrentTimeScrubberMouseUp.rEvtContext(this),
)
},
onCurrentTimeScrubberMouseMove: function(event) {
// Removeable
this.setCurrentTimeWithScrubber(event)
},
onCurrentTimeScrubberMouseUp: function(event) {
// Removeable
_V_.unblockTextSelection()
document.removeEventListener(
‘mousemove’,
this.onCurrentTimeScrubberMouseMove,
false,
)
document.removeEventListener(
‘mouseup’,
this.onCurrentTimeScrubberMouseUp,
false,
)
if (this.videoWasPlaying) {
this.play()
this.trackCurrentTime()
}
},
setCurrentTimeWithScrubber: function(event) {
var newProgress = _V_.getRelativePosition(
event.pageX,
this.currentScrubber,
)
var newTime = newProgress * this.duration()
this.triggerCurrentTimeListeners(0, newTime) // Allows for smooth scrubbing
// Don’t let video end while scrubbing.
if (newTime == this.duration()) {
newTime = newTime – 0.1
}
this.currentTime(newTime)
},
},
)
/* Volume Display Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘volumeDisplay’,
function(element) {
if (!this.volumeDisplays) {
this.volumeDisplays = []
this.onVolumeChange(this.updateVolumeDisplays)
}
this.volumeDisplays.push(element)
this.updateVolumeDisplay(element) // Set the display to the initial volume
},
{
// Update the volume control display
// Unique to these default controls. Uses borders to create the look of bars.
updateVolumeDisplays: function() {
if (!this.volumeDisplays) {
return
}
this.each(this.volumeDisplays, function(dis) {
this.updateVolumeDisplay(dis)
})
},
updateVolumeDisplay: function(display) {
var volNum = Math.ceil(this.volume() * 6)
this.each(display.children, function(child, num) {
if (num < volNum) {
_V_.addClass(child, ‘vjs-volume-level-on’)
} else {
_V_.removeClass(child, ‘vjs-volume-level-on’)
}
})
},
},
)
/* Volume Scrubber Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘volumeScrubber’,
function(element) {
_V_.addListener(
element,
‘mousedown’,
this.onVolumeScrubberMouseDown.rEvtContext(this),
)
},
{
// Adjust the volume when the user drags on the volume control
onVolumeScrubberMouseDown: function(event, scrubber) {
// event.preventDefault();
_V_.blockTextSelection()
this.currentScrubber = scrubber
this.setVolumeWithScrubber(event)
_V_.addListener(
document,
‘mousemove’,
this.onVolumeScrubberMouseMove.rEvtContext(this),
)
_V_.addListener(
document,
‘mouseup’,
this.onVolumeScrubberMouseUp.rEvtContext(this),
)
},
onVolumeScrubberMouseMove: function(event) {
this.setVolumeWithScrubber(event)
},
onVolumeScrubberMouseUp: function(event) {
this.setVolumeWithScrubber(event)
_V_.unblockTextSelection()
document.removeEventListener(
‘mousemove’,
this.onVolumeScrubberMouseMove,
false,
)
document.removeEventListener(
‘mouseup’,
this.onVolumeScrubberMouseUp,
false,
)
},
setVolumeWithScrubber: function(event) {
var newVol = _V_.getRelativePosition(event.pageX, this.currentScrubber)
this.volume(newVol)
},
},
)
/* Fullscreen Toggle Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘fullscreenToggle’,
function(element) {
_V_.addListener(
element,
‘click’,
this.onFullscreenToggleClick.context(this),
)
},
{
// When the user clicks on the fullscreen button, update fullscreen setting
onFullscreenToggleClick: function(event) {
if (!this.videoIsFullScreen) {
this.enterFullScreen()
} else {
this.exitFullScreen()
}
},
fullscreenOnWindowResize: function(event) {
// Removeable
this.positionControlBars()
},
// Create listener for esc key while in full screen mode
fullscreenOnEscKey: function(event) {
// Removeable
if (event.keyCode == 27) {
this.exitFullScreen()
}
},
},
)
/* Big Play Button Behaviors
================================================================================ */
VideoJS.player.newBehavior(
‘bigPlayButton’,
function(element) {
if (!this.elements.bigPlayButtons) {
this.elements.bigPlayButtons = []
this.onPlay(this.bigPlayButtonsOnPlay)
this.onEnded(this.bigPlayButtonsOnEnded)
}
this.elements.bigPlayButtons.push(element)
this.activateElement(element, ‘playButton’)
},
{
bigPlayButtonsOnPlay: function(event) {
this.hideBigPlayButtons()
},
bigPlayButtonsOnEnded: function(event) {
this.showBigPlayButtons()
},
showBigPlayButtons: function() {
this.each(this.elements.bigPlayButtons, function(element) {
element.style.display = ‘block’
})
},
hideBigPlayButtons: function() {
this.each(this.elements.bigPlayButtons, function(element) {
element.style.display = ‘none’
})
},
},
)
/* Spinner
================================================================================ */
VideoJS.player.newBehavior(
‘spinner’,
function(element) {
if (!this.spinners) {
this.spinners = []
_V_.addListener(
this.video,
‘loadeddata’,
this.spinnersOnVideoLoadedData.context(this),
)
_V_.addListener(
this.video,
‘loadstart’,
this.spinnersOnVideoLoadStart.context(this),
)
_V_.addListener(
this.video,
‘seeking’,
this.spinnersOnVideoSeeking.context(this),
)
_V_.addListener(
this.video,
‘seeked’,
this.spinnersOnVideoSeeked.context(this),
)
_V_.addListener(
this.video,
‘canplay’,
this.spinnersOnVideoCanPlay.context(this),
)
_V_.addListener(
this.video,
‘canplaythrough’,
this.spinnersOnVideoCanPlayThrough.context(this),
)
_V_.addListener(
this.video,
‘waiting’,
this.spinnersOnVideoWaiting.context(this),
)
_V_.addListener(
this.video,
‘stalled’,
this.spinnersOnVideoStalled.context(this),
)
_V_.addListener(
this.video,
‘suspend’,
this.spinnersOnVideoSuspend.context(this),
)
_V_.addListener(
this.video,
‘playing’,
this.spinnersOnVideoPlaying.context(this),
)
_V_.addListener(
this.video,
‘timeupdate’,
this.spinnersOnVideoTimeUpdate.context(this),
)
}
this.spinners.push(element)
},
{
showSpinners: function() {
this.each(this.spinners, function(spinner) {
spinner.style.display = ‘block’
})
clearInterval(this.spinnerInterval)
this.spinnerInterval = setInterval(
this.rotateSpinners.context(this),
100,
)
},
hideSpinners: function() {
this.each(this.spinners, function(spinner) {
spinner.style.display = ‘none’
})
clearInterval(this.spinnerInterval)
},
spinnersRotated: 0,
rotateSpinners: function() {
this.each(this.spinners, function(spinner) {
// spinner.style.transform = ‘scale(0.5) rotate(‘+this.spinnersRotated+’deg)’;
spinner.style.WebkitTransform =
‘scale(0.5) rotate(‘ + this.spinnersRotated + ‘deg)’
spinner.style.MozTransform =
‘scale(0.5) rotate(‘ + this.spinnersRotated + ‘deg)’
})
if (this.spinnersRotated == 360) {
this.spinnersRotated = 0
}
this.spinnersRotated += 45
},
spinnersOnVideoLoadedData: function(event) {
this.hideSpinners()
},
spinnersOnVideoLoadStart: function(event) {
this.showSpinners()
},
spinnersOnVideoSeeking: function(event) {
/* this.showSpinners(); */
},
spinnersOnVideoSeeked: function(event) {
/* this.hideSpinners(); */
},
spinnersOnVideoCanPlay: function(event) {
/* this.hideSpinners(); */
},
spinnersOnVideoCanPlayThrough: function(event) {
this.hideSpinners()
},
spinnersOnVideoWaiting: function(event) {
// Safari sometimes triggers waiting inappropriately
// Like after video has played, any you play again.
this.showSpinners()
},
spinnersOnVideoStalled: function(event) {},
spinnersOnVideoSuspend: function(event) {},
spinnersOnVideoPlaying: function(event) {
this.hideSpinners()
},
spinnersOnVideoTimeUpdate: function(event) {
// Safari sometimes calls waiting and doesn’t recover
if (this.spinner.style.display == ‘block’) {
this.hideSpinners()
}
},
},
)
/* Subtitles
================================================================================ */
VideoJS.player.newBehavior(
‘subtitlesDisplay’,
function(element) {
if (!this.subtitleDisplays) {
this.subtitleDisplays = []
this.onCurrentTimeUpdate(this.subtitleDisplaysOnVideoTimeUpdate)
this.onEnded(
function() {
this.lastSubtitleIndex = 0
}.context(this),
)
}
this.subtitleDisplays.push(element)
},
{
subtitleDisplaysOnVideoTimeUpdate: function(time) {
// Assuming all subtitles are in order by time, and do not overlap
if (this.subtitles) {
// If current subtitle should stay showing, don’t do anything. Otherwise, find new subtitle.
if (
!this.currentSubtitle ||
this.currentSubtitle.start >= time ||
this.currentSubtitle.end < time
) {
var newSubIndex = false,
// Loop in reverse if lastSubtitle is after current time (optimization)
// Meaning the user is scrubbing in reverse or rewinding
reverse = this.subtitles[this.lastSubtitleIndex].start > time,
// If reverse, step back 1 becase we know it’s not the lastSubtitle
i = this.lastSubtitleIndex – reverse ? 1 : 0
while (true) {
// Loop until broken
if (reverse) {
// Looping in reverse
// Stop if no more, or this subtitle ends before the current time (no earlier subtitles should apply)
if (i < 0 || this.subtitles[i].end < time) {
break
}
// End is greater than time, so if start is less, show this subtitle
if (this.subtitles[i].start < time) {
newSubIndex = i
break
}
i–
} else {
// Looping forward
// Stop if no more, or this subtitle starts after time (no later subtitles should apply)
if (
i >= this.subtitles.length ||
this.subtitles[i].start > time
) {
break
}
// Start is less than time, so if end is later, show this subtitle
if (this.subtitles[i].end > time) {
newSubIndex = i
break
}
i++
}
}
// Set or clear current subtitle
if (newSubIndex !== false) {
this.currentSubtitle = this.subtitles[newSubIndex]
this.lastSubtitleIndex = newSubIndex
this.updateSubtitleDisplays(this.currentSubtitle.text)
} else if (this.currentSubtitle) {
this.currentSubtitle = false
this.updateSubtitleDisplays(”)
}
}
}
},
updateSubtitleDisplays: function(val) {
this.each(this.subtitleDisplays, function(disp) {
disp.innerHTML = val
})
},
},
)
////////////////////////////////////////////////////////////////////////////////
// Convenience Functions (mini library)
// Functions not specific to video or VideoJS and could probably be replaced with a library like jquery
////////////////////////////////////////////////////////////////////////////////
VideoJS.extend({
addClass: function(element, classToAdd) {
if (
(‘ ‘ + element.className + ‘ ‘).indexOf(‘ ‘ + classToAdd + ‘ ‘) == -1
) {
element.className =
element.className === ”
? classToAdd
: element.className + ‘ ‘ + classToAdd
}
},
removeClass: function(element, classToRemove) {
if (element.className.indexOf(classToRemove) == -1) {
return
}
var classNames = element.className.split(/\s+/)
classNames.splice(classNames.lastIndexOf(classToRemove), 1)
element.className = classNames.join(‘ ‘)
},
createElement: function(tagName, attributes) {
return this.merge(document.createElement(tagName), attributes)
},
// Attempt to block the ability to select text while dragging controls
blockTextSelection: function() {
document.body.focus()
document.onselectstart = function() {
return false
}
},
// Turn off text selection blocking
unblockTextSelection: function() {
document.onselectstart = function() {
return true
}
},
// Return seconds as MM:SS
formatTime: function(secs) {
var seconds = Math.round(secs)
var minutes = Math.floor(seconds / 60)
minutes = minutes >= 10 ? minutes : ‘0’ + minutes
seconds = Math.floor(seconds % 60)
seconds = seconds >= 10 ? seconds : ‘0’ + seconds
return minutes + ‘:’ + seconds
},
// Return the relative horizonal position of an event as a value from 0-1
getRelativePosition: function(x, relativeElement) {
return Math.max(
0,
Math.min(
1,
(x – this.findPosX(relativeElement)) / relativeElement.offsetWidth,
),
)
},
// Get an objects position on the page
findPosX: function(obj) {
var curleft = obj.offsetLeft
while ((obj = obj.offsetParent)) {
curleft += obj.offsetLeft
}
return curleft
},
getComputedStyleValue: function(element, style) {
return window.getComputedStyle(element, null).getPropertyValue(style)
},
round: function(num, dec) {
if (!dec) {
dec = 0
}
return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec)
},
addListener: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false)
} else if (element.attachEvent) {
element.attachEvent(‘on’ + type, handler)
}
},
removeListener: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false)
} else if (element.attachEvent) {
element.detachEvent(‘on’ + type, handler)
}
},
get: function(url, onSuccess) {
if (typeof XMLHttpRequest == ‘undefined’) {
XMLHttpRequest = function() {
try {
return new ActiveXObject(‘Msxml2.XMLHTTP.6.0’)
} catch (e) {}
try {
return new ActiveXObject(‘Msxml2.XMLHTTP.3.0’)
} catch (f) {}
try {
return new ActiveXObject(‘Msxml2.XMLHTTP’)
} catch (g) {}
//Microsoft.XMLHTTP points to Msxml2.XMLHTTP.3.0 and is redundant
throw new Error(‘This browser does not support XMLHttpRequest.’)
}
}
var request = new XMLHttpRequest()
request.open(‘GET’, url)
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
onSuccess(request.responseText)
}
}.context(this)
request.send()
},
trim: function(string) {
return string
.toString()
.replace(/^\s+/, ”)
.replace(/\s+$/, ”)
},
// DOM Ready functionality adapted from jquery. http://jquery.com/
bindDOMReady: function() {
if (document.readyState === ‘complete’) {
return VideoJS.onDOMReady()
}
if (document.addEventListener) {
document.addEventListener(
‘DOMContentLoaded’,
VideoJS.DOMContentLoaded,
false,
)
window.addEventListener(‘load’, VideoJS.onDOMReady, false)
} else if (document.attachEvent) {
document.attachEvent(‘onreadystatechange’, VideoJS.DOMContentLoaded)
window.attachEvent(‘onload’, VideoJS.onDOMReady)
}
},
DOMContentLoaded: function() {
if (document.addEventListener) {
document.removeEventListener(
‘DOMContentLoaded’,
VideoJS.DOMContentLoaded,
false,
)
VideoJS.onDOMReady()
} else if (document.attachEvent) {
if (document.readyState === ‘complete’) {
document.detachEvent(‘onreadystatechange’, VideoJS.DOMContentLoaded)
VideoJS.onDOMReady()
}
}
},
// Functions to be run once the DOM is loaded
DOMReadyList: [],
addToDOMReady: function(fn) {
if (VideoJS.DOMIsReady) {
fn.call(document)
} else {
VideoJS.DOMReadyList.push(fn)
}
},
DOMIsReady: false,
onDOMReady: function() {
if (VideoJS.DOMIsReady) {
return
}
if (!document.body) {
return setTimeout(VideoJS.onDOMReady, 13)
}
VideoJS.DOMIsReady = true
if (VideoJS.DOMReadyList) {
for (var i = 0; i < VideoJS.DOMReadyList.length; i++) {
VideoJS.DOMReadyList[i].call(document)
}
VideoJS.DOMReadyList = null
}
},
})
VideoJS.bindDOMReady()
// Allows for binding context to functions
// when using in event listeners and timeouts
Function.prototype.context = function(obj) {
var method = this,
temp = function() {
return method.apply(obj, arguments)
}
return temp
}
// Like context, in that it creates a closure
// But insteaad keep “this” intact, and passes the var as the second argument of the function
// Need for event listeners where you need to know what called the event
// Only use with event callbacks
Function.prototype.evtContext = function(obj) {
var method = this,
temp = function() {
var origContext = this
return method.call(obj, arguments[0], origContext)
}
return temp
}
// Removeable Event listener with Context
// Replaces the original function with a version that has context
// So it can be removed using the original function name.
// In order to work, a version of the function must already exist in the player/prototype
Function.prototype.rEvtContext = function(obj, funcParent) {
if (this.hasContext === true) {
return this
}
if (!funcParent) {
funcParent = obj
}
for (var attrname in funcParent) {
if (funcParent[attrname] == this) {
funcParent[attrname] = this.evtContext(obj)
funcParent[attrname].hasContext = true
return funcParent[attrname]
}
}
return this.evtContext(obj)
}
// jquery Plugin
if (window.jquery) {
;(function($) {
$.fn.VideoJS = function(options) {
this.each(function() {
VideoJS.setup(this, options)
})
return this
}
$.fn.player = function() {
return this[0].player
}
})(jquery)
}
// Expose to global
window.VideoJS = window._V_ = VideoJS
// End self-executing function
})(window)
ieda搭建前端开发环境 gulp前端开发环境搭建 pycharm 前端开发环境
评论前必须登录!
注册