chiro-canto/public/scripts/wavesurfer/example/angular-material/wavesurfer.directive.js

464 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* global angular */
/**
* Created by intelWorx on 19/11/2015.
*/
(function() {
'use strict';
/**
* Main module, your application should depend on this
* @module {mdWavesurfer}
*/
let app = angular.module('mdWavesurfer', ['ngMaterial']);
/**
* @ngdoc service
* @name $mdWavesurferUtils
*
* @description
*
* Utility service for this directive, exposes method:
* - getLength(url), which returns a promise for the length of the audio specified by URL
*
* ```js
* app.directive('myFancyDirective', function(mdWavesurferUtils) {
* return {
* restrict: 'e',
* link: function(scope, el, attrs) {
* mdWavesurferUtils(attrs.url)
* .then(function(l){
* scope.length = l;
* }, function(){
* someErrorhandler()
* })
* ;
* }
* };
* });
* ```
*/
app.factory('mdWavesurferUtils', [
'$q',
'$document',
'$timeout',
function($q, $document, $timeout) {
return {
getLength: function(object) {
let deferred = $q.defer();
let estimateLength = function(url) {
let audio = $document[0].createElement('audio');
audio.src = url;
audio.addEventListener(
'loadeddata',
function listener() {
deferred.resolve(this.duration);
audio.removeEventListener(
'loadeddata',
listener
);
audio.src = 'data:audio/mpeg,0'; //destroy loading.
}
);
audio.addEventListener('error', function(e) {
deferred.resolve(e.target.error);
});
};
if (typeof object === 'string') {
//this is a URL
estimateLength(object);
} else {
$timeout(function() {
deferred.reject(
new DOMError(
'NotSupportedError',
'Specified argument is not supported'
)
);
});
}
return deferred.promise;
}
};
}
]);
/**
* @ngdoc filter
* @name mdWavesurferTimeFormat
*
* Simple filter to convert value in seconds to MM:SS format
*
* @param Number duration in seconds
*/
app.filter('mdWavesurferTimeFormat', function() {
return function(input) {
if (!input) {
return '00:00';
}
const minutes = Math.floor(input / 60);
const seconds = Math.floor(input) % 60;
return (
(minutes < 10 ? '0' : '') +
minutes +
':' +
(seconds < 10 ? '0' : '') +
seconds
);
};
});
app.controller('mdWavesurferAudioController', [
'$attrs',
'$element',
function(attributes, $element) {
let audio = this;
audio.tracks = [];
audio.selectedIndex = audio.selectedIndex || 0;
audio.currentTrack = null;
//adds to an audio track
audio.addTrack = function(trackScope) {
if (audio.tracks.indexOf(trackScope) < 0) {
audio.tracks.push(trackScope);
}
if (!audio.currentTrack) {
audio.currentTrack = audio.tracks[audio.selectedIndex];
}
};
//remove audio track
audio.removeTrack = function(trackScope) {
const idx = audio.tracks.indexOf(trackScope);
if (idx >= 0) {
audio.tracks.splice(idx, 1);
}
};
audio.playerProperties = {};
let nKey;
for (let attr in attributes) {
if (attr.match(/^player/)) {
nKey = attr.replace(/^player([A-Z])/, function(m, $1) {
return $1.toLowerCase();
});
audio.playerProperties[nKey] = attributes[attr];
}
}
let getPlayer = function() {
return $element
.find('md-wavesurfer-player')
.controller('mdWavesurferPlayer');
};
let setAutoPlay = function(forcePlay) {
let controller = getPlayer();
if (
controller &&
(forcePlay || controller.surfer.isPlaying())
) {
controller.autoPlay = true;
}
};
audio.setTrack = function(idx, forcePlay) {
if (audio.tracks.length > idx) {
if (audio.selectedIndex === idx) {
let ctrl = getPlayer();
ctrl.surfer.playPause();
} else {
setAutoPlay(forcePlay);
audio.currentTrack = audio.tracks[idx];
audio.selectedIndex = idx;
}
}
};
audio.extraButtons = [
{
icon: 'zmdi zmdi-skip-previous',
title: 'Previous',
action: function($event) {
if (audio.selectedIndex > 0) {
audio.setTrack(audio.selectedIndex - 1);
}
},
class: ''
},
{
icon: 'zmdi zmdi-skip-next',
title: 'Next',
action: function($event) {
if (audio.selectedIndex < audio.tracks.length - 1) {
audio.setTrack(audio.selectedIndex + 1);
}
},
class: ''
}
];
}
]);
/**
* @ngdoc directive
* @name md-wavesurfer-audio
*
* Directive for playing a set of audio files. This directive is analogous to `<audio>` HTML tag.
* The audio files, should be specified using the `md-wavesurfer-source`
*
* WaveSurfer properties can be passed in using the prefix : player-* for attributes, e.g. `player-wave-color` is
* equivalent to WaveSurfer's waveColor option.
*
* Must be used as an element.
*
* @usage
* ```html
* <md-wavesurfer-audio player-wave-color="gray" player-progress-color="black" player-backend="MediaElement">
* <md-wavesurfer-source src="source1" title="Title-1"></md-wavesurfer-source>
* <md-wavesurfer-source src="source2" title="Title-2"></md-wavesurfer-source>
* <md-wavesurfer-source src="source3" title="Title-3"></md-wavesurfer-source>
* ...
* <md-wavesurfer-source src="sourceN" title="Рассказы о сновидениях"></md-wavesurfer-source>
* </md-wavesurfer-audio>
* ```
*
* @param string player-* specifies WaveSurfer properties.
*
*/
app.directive('mdWavesurferAudio', [
function() {
return {
restrict: 'E',
templateUrl: 'md-player-audio.partial.html',
transclude: true,
controller: 'mdWavesurferAudioController',
controllerAs: 'audio'
};
}
]);
/**
* @ngdoc directive
*
* @name md-wavesurfer-source
*
* This directive is used within the `md-wavesurfer-audio` directive to specify an audio file source, it is
* synonymous to `<source>` tag in HTML
*
* The directive cannot be used as standalone.
*
* @usage
*
* ```html
* <md-wavesurfer-source src="source3" title="Title-3" album-art="Album-Art-Url" duration=""></md-wavesurfer-source>
* ```
* @param String src the URL to the audio file, this is required.
* @param String title track title
* @param String album-art the album art URL
* @param Number duration the length of the audio file in seconds, will be auto-detected if not specified.
*
*/
app.directive('mdWavesurferSource', [
'mdWavesurferUtils',
function(mdWavesurferUtils) {
return {
restrict: 'E',
require: '^mdWavesurferAudio',
scope: {
src: '@',
albumArt: '@',
title: '@',
duration: '='
},
link: function(scope, element, attrs, audio) {
audio.addTrack(scope);
if (!scope.duration) {
mdWavesurferUtils.getLength(scope.src).then(
function(dur) {
scope.duration = dur;
},
function(e) {
scope.duration = 0;
console.log(
'Failed to get audio length, reason: ',
e.message
);
}
);
}
element.on('$destroy', function() {
audio.removeTrack(audio);
});
}
};
}
]);
app.controller('mdWavesurferPlayerController', [
'$element',
'$scope',
'$attrs',
'$interval',
'$mdTheming',
function($element, $scope, attributes, $interval, $mdTheme) {
let control = this,
timeInterval;
control.themeClass = 'md-' + $mdTheme.defaultTheme() + '-theme';
control.isReady = false;
control.surfer = null;
control.toggleMute = function() {
if (control.surfer) {
control.surfer.toggleMute();
control.isMute = !control.isMute;
}
};
let initWaveSurfer = function() {
control.isReady = false;
control.currentTime = 0;
if (!control.surfer) {
let options = {
container: $element[0].querySelector(
'.waveSurferWave'
)
},
defaults = {
scrollParent: true,
waveColor: 'violet',
progressColor: 'purple'
};
options = angular.extend(
defaults,
attributes,
control.properties || {},
options
);
control.surfer = WaveSurfer.create(options);
control.surfer.on('ready', function() {
control.isReady = true;
if (control.autoPlay) {
control.surfer.play();
}
$scope.$apply();
});
control.surfer.on('pause', function() {
stopInterval();
});
control.surfer.on('finish', function() {
stopInterval();
});
control.surfer.on('play', function() {
startInterval();
});
}
control.title = control.title || control.src.split('/').pop();
control.surfer.load(control.src);
};
let startInterval = function() {
timeInterval = $interval(function() {
control.currentTime = control.isReady
? control.surfer.getCurrentTime()
: 0;
}, 1000);
},
stopInterval = function() {
$interval.cancel(timeInterval);
};
initWaveSurfer();
$scope.$watch('control.src', function(src1, src2) {
if (src1 != src2) {
initWaveSurfer();
}
});
$element.on('$destroy', function() {
if (control.surfer) {
control.surfer.destroy();
}
stopInterval();
});
$scope.$watch(
function() {
let div = $element[0].querySelector('.audioPlayerWrapper');
return div ? div.offsetWidth : 0;
},
function(width) {
if (width < 1) {
//hidden
control.surfer.pause();
}
}
);
}
]);
/**
* @ngdoc directive
*
* @name md-wavesurfer-player
*
* @usage
* This directive can be used as a stand-alone directive to display Audio WaveSurfer with a few controls, by default
* this will only display play/pause, fast-forward, rewind and mute toggle buttons, however, you can add extra
* buttons using the `extra-buttons` parameters.
*
* ```html
* <md-wavesurfer-player url="trackUrl" title="Track Title"
* extra-buttons="extraButtons" properties="properties">
* </md-wavesurfer-player>
* ```
*
* @param {string} url the URL of the audio file
* @param {string} title title of the audio track
* @param {object} properties an object specifying init options for WaveSurfer
* @param {boolean} auto-play specifies if the player should start as soon as it's loaded.
* @param {object[]} extra-buttons a list of extra buttons to add to the control panel
* each button should be an object with the following properties:
* {
* title: "button title"
* action: "call back to call when button is clicked, executed in parent scope",
* icon: "md-font-icon parameter for the button"
* class: "extra classes to add to the button."
* }
*
* Every other attribute passed to this directive is assumed to a WaveSurver init parameter.
*/
app.directive('mdWavesurferPlayer', function() {
return {
restrict: 'E',
templateUrl: 'md-player.partial.html',
scope: {
src: '@url',
title: '@',
extraButtons: '=',
toolbarClass: '@',
autoPlay: '=',
properties: '='
},
controller: 'mdWavesurferPlayerController',
controllerAs: 'control',
bindToController: true
};
});
})();