Embed rework
This commit is contained in:
parent
98054f268f
commit
ac7659614a
58 changed files with 8278 additions and 49187 deletions
954
embed/util.js
Normal file
954
embed/util.js
Normal file
|
@ -0,0 +1,954 @@
|
|||
var MistUtil = {
|
||||
format: {
|
||||
time: function(secs,options){
|
||||
if (isNaN(secs) || !isFinite(secs)) { return secs; }
|
||||
if (!options) { options = {}; }
|
||||
|
||||
var ago = (secs < 0 ? " ago" : "");
|
||||
secs = Math.abs(secs);
|
||||
|
||||
var days = Math.floor(secs / 86400)
|
||||
secs = secs - days * 86400;
|
||||
var hours = Math.floor(secs / 3600);
|
||||
secs = secs - hours * 3600;
|
||||
var mins = Math.floor(secs / 60);
|
||||
var ms = Math.round((secs % 1)*1e3);
|
||||
secs = Math.floor(secs - mins * 60);
|
||||
var str = [];
|
||||
if (days) {
|
||||
days = days+" day"+(days > 1 ? "s" : "")+", ";
|
||||
}
|
||||
if ((hours) || (days)) {
|
||||
str.push(hours);
|
||||
str.push(("0"+mins).slice(-2));
|
||||
}
|
||||
else {
|
||||
str.push(mins); //don't use 0 padding if there are no hours in front
|
||||
}
|
||||
str.push(("0"+Math.floor(secs)).slice(-2));
|
||||
|
||||
if (options.ms) {
|
||||
str[str.length-1] += "."+("000"+ms).slice(-3);
|
||||
}
|
||||
|
||||
return (days ? days : "")+str.join(":")+ago;
|
||||
},
|
||||
ucFirst: function(string){
|
||||
return string.charAt(0).toUpperCase()+string.slice(1);
|
||||
},
|
||||
number: function(num) {
|
||||
if ((isNaN(Number(num))) || (num == 0)) { return num; }
|
||||
|
||||
//rounding
|
||||
//use a significance of three, but don't round "visible" digits
|
||||
var sig = Math.max(3,Math.ceil(Math.log(num)/Math.LN10));
|
||||
var mult = Math.pow(10,sig - Math.floor(Math.log(num)/Math.LN10) - 1);
|
||||
num = Math.round(num * mult) / mult;
|
||||
|
||||
//thousand seperation
|
||||
if (num >= 1e4) {
|
||||
var seperator = " ";
|
||||
number = num.toString().split(".");
|
||||
var regex = /(\d+)(\d{3})/;
|
||||
while (regex.test(number[0])) {
|
||||
number[0] = number[0].replace(regex,"$1"+seperator+"$2");
|
||||
}
|
||||
num = number.join(".");
|
||||
}
|
||||
|
||||
return num;
|
||||
},
|
||||
bytes: function(val){
|
||||
if (isNaN(Number(val))) { return val; }
|
||||
|
||||
var suffix = ["bytes","KB","MB","GB","TB","PB"];
|
||||
if (val == 0) {
|
||||
unit = suffix[0];
|
||||
}
|
||||
else {
|
||||
var exponent = Math.floor(Math.log(Math.abs(val)) / Math.log(1024));
|
||||
if (exponent < 0) {
|
||||
unit = suffix[0];
|
||||
}
|
||||
else {
|
||||
val = val / Math.pow(1024,exponent);
|
||||
unit = suffix[exponent];
|
||||
}
|
||||
}
|
||||
return this.number(val)+unit;
|
||||
},
|
||||
mime2human: function(mime){
|
||||
switch (mime) {
|
||||
case "html5/video/webm": {
|
||||
return "WebM";
|
||||
break;
|
||||
}
|
||||
case "html5/application/vnd.apple.mpegurl": {
|
||||
return "HLS";
|
||||
break;
|
||||
}
|
||||
case "flash/10": {
|
||||
return "Flash (RTMP)";
|
||||
break;
|
||||
}
|
||||
case "flash/11": {
|
||||
return "Flash (HDS)";
|
||||
break;
|
||||
}
|
||||
case "flash/7": {
|
||||
return "Flash (Progressive)";
|
||||
break;
|
||||
}
|
||||
case "html5/video/mpeg": {
|
||||
return "TS";
|
||||
break;
|
||||
}
|
||||
case "html5/application/vnd.ms-ss": {
|
||||
return "Smooth streaming";
|
||||
break;
|
||||
}
|
||||
case "dash/video/mp4": {
|
||||
return "DASH";
|
||||
break;
|
||||
}
|
||||
case "webrtc": {
|
||||
return "WebRTC";
|
||||
break;
|
||||
}
|
||||
case "silverlight": {
|
||||
return "Smooth streaming (Silverlight)";
|
||||
break;
|
||||
}
|
||||
case "html5/text/vtt": {
|
||||
return "VTT subtitles";
|
||||
break;
|
||||
}
|
||||
case "html5/text/plain": {
|
||||
return "SRT subtitles";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return mime.replace("html5/","").replace("video/","").replace("audio/","").toLocaleUpperCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
class: {
|
||||
//reroute classList functionalities if not supported; also avoid indexOf
|
||||
add: function(DOMelement,item){
|
||||
if ("classList" in DOMelement) {
|
||||
DOMelement.classList.add(item);
|
||||
}
|
||||
else {
|
||||
var classes = this.get(DOMelement);
|
||||
|
||||
classes.push(item);
|
||||
this.set(DOMelement,classes);
|
||||
}
|
||||
},
|
||||
remove: function(DOMelement,item){
|
||||
if ("classList" in DOMelement) {
|
||||
DOMelement.classList.remove(item);
|
||||
}
|
||||
else {
|
||||
var classes = this.get(DOMelement);
|
||||
|
||||
for (var i = classes.length-1; i >= 0; i--) {
|
||||
if (classes[i] == item) {
|
||||
classes.splice(i);
|
||||
}
|
||||
}
|
||||
this.set(DOMelement,classes);
|
||||
}
|
||||
},
|
||||
get: function(DOMelement) {
|
||||
var classes;
|
||||
var className = DOMelement.getAttribute("class"); //DOMelement.className does not work on svg elements
|
||||
|
||||
if ((!className) || (className == "")) { classes = []; }
|
||||
else { classes = className.split(" "); }
|
||||
|
||||
return classes;
|
||||
},
|
||||
set: function(DOMelement,classes) {
|
||||
DOMelement.setAttribute("class",classes.join(" "));
|
||||
},
|
||||
has: function(DOMelement,hasClass){
|
||||
return (DOMelement.className.split(" ").indexOf(hasClass) >= 0)
|
||||
}
|
||||
},
|
||||
|
||||
object: {
|
||||
//extend object1 with object2
|
||||
extend: function(object1,object2,deep) {
|
||||
for (var i in object2) {
|
||||
if (deep && (typeof object2[i] == "object") && (!("nodeType" in object2[i]))) {
|
||||
if (!(i in object1)) {
|
||||
if (MistUtil.array.is(object2[i])) {
|
||||
object1[i] = [];
|
||||
}
|
||||
else {
|
||||
object1[i] = {};
|
||||
}
|
||||
}
|
||||
this.extend(object1[i],object2[i],true);
|
||||
}
|
||||
else {
|
||||
object1[i] = object2[i];
|
||||
}
|
||||
}
|
||||
|
||||
return object1;
|
||||
},
|
||||
//replace Object.keys
|
||||
//if sorting: sort the keys alphabetically or use passed sorting function
|
||||
//sorting gets these arguments: keya,keyb,valuea,valueb
|
||||
keys: function(obj,sorting){
|
||||
|
||||
var keys = [];
|
||||
for (var i in obj) {
|
||||
keys.push(i);
|
||||
}
|
||||
|
||||
if (sorting) {
|
||||
if (typeof sorting != "function") {
|
||||
sorting = function(keya,keyb){
|
||||
if (keya > keyb) { return 1; }
|
||||
if (keya < keyb) { return -1; }
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
keys.sort(function(keya,keyb){
|
||||
return sorting(keya,keyb,obj[keya],obj[keyb]);
|
||||
});
|
||||
}
|
||||
|
||||
return keys;
|
||||
},
|
||||
//replace Object.values
|
||||
//if sorting: sort the keys alphabetically or use passed sorting function
|
||||
//sorting gets these arguments: keya,keyb,valuea,valueb
|
||||
values: function(obj,sorting){
|
||||
|
||||
var keys = this.keys(obj,sorting);
|
||||
|
||||
values = [];
|
||||
for (var i in keys) {
|
||||
values.push(obj[keys[i]]);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
},
|
||||
array: {
|
||||
//replace [].indexOf
|
||||
indexOf: function(array,entry) {
|
||||
if (!(array instanceof Array)) { throw "Tried to use indexOf on something that is not an array"; }
|
||||
if ("indexOf" in array) { return array.indexOf(entry); }
|
||||
|
||||
for (var i; i < array.length; i++) {
|
||||
if (array[i] == entry) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
//replace isArray
|
||||
is: function(array) {
|
||||
if ("isArray" in Array) {
|
||||
return Array.isArray(array);
|
||||
}
|
||||
return Object.prototype.toString.call(array) === '[object Array]';
|
||||
},
|
||||
multiSort: function (array,sortby) {
|
||||
/*
|
||||
MistUtil.array.multiSort([].concat(video.info.source),[
|
||||
{type: ["html5/video/webm","silverlight"]} or ["type",["html5/video/webm","silverlight"]]
|
||||
,{simul_tracks:-1} or ["simul_tracks",-1]
|
||||
,function(a){ return a.priority * -1; }
|
||||
,"url"
|
||||
]);
|
||||
*/
|
||||
|
||||
var sortfunc = function(a,b){
|
||||
if (isNaN(a) || isNaN(b)) {
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
return Math.sign(a-b);
|
||||
};
|
||||
|
||||
if (!sortby.length) { return array.sort(sortfunc); }
|
||||
|
||||
function getValue(key,a) {
|
||||
|
||||
function parseIt(item,key,sortvalue){
|
||||
if (!(key in item)) {
|
||||
throw "Invalid sorting rule: "+JSON.stringify([key,sortvalue])+". \""+key+"\" is not a key of "+JSON.stringify(item);
|
||||
}
|
||||
|
||||
if (typeof sortvalue == "number") {
|
||||
//deals with something like {priority: -1}
|
||||
if (key in item) {
|
||||
return item[key] * sortvalue;
|
||||
}
|
||||
}
|
||||
|
||||
//deals with something like {type:["webrtc"]}
|
||||
var i = sortvalue.indexOf(item[key])
|
||||
return (i >= 0 ? i : sortvalue.length);
|
||||
}
|
||||
|
||||
//deals with something like function(a){ return a.foo + a.bar; }
|
||||
if (typeof key == "function") { return key(a); }
|
||||
|
||||
if (typeof key == "object") {
|
||||
if (key instanceof Array) {
|
||||
//it's an array
|
||||
return parseIt(a,key[0],key[1]);
|
||||
}
|
||||
//it's an object
|
||||
for (var j in key) { //only listen to a single key
|
||||
return parseIt(a,j,key[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if (key in a) {
|
||||
return a[key];
|
||||
}
|
||||
|
||||
throw "Invalid sorting rule: "+key+". This should be a function, object or key of "+JSON.stringify(a)+".";
|
||||
}
|
||||
|
||||
array.sort(function(a,b){
|
||||
var output = 0;
|
||||
for (var i in sortby) {
|
||||
var key = sortby[i];
|
||||
output = sortfunc(getValue(key,a),getValue(key,b));
|
||||
if (output != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
},
|
||||
|
||||
createUnique: function() {
|
||||
var i = "uid"+Math.random().toString().replace("0.","");
|
||||
if (document.querySelector("."+i)) {
|
||||
//if this is already used, try again
|
||||
return createUnique();
|
||||
}
|
||||
return i;
|
||||
},
|
||||
|
||||
http: {
|
||||
getpost: function(type,url,data,callback,errorCallback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open(type, url, true);
|
||||
if (type == "POST") { xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); }
|
||||
|
||||
if (errorCallback) { xhr.timeout = 8e3; } //go to timeout function after 8 seconds
|
||||
|
||||
xhr.onload = function() {
|
||||
var status = xhr.status;
|
||||
if ((status >= 200) && (status < 300)) {
|
||||
callback(xhr.response);
|
||||
}
|
||||
else if (errorCallback) {
|
||||
xhr.onerror = function() {
|
||||
errorCallback(xhr);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (errorCallback) {
|
||||
xhr.onerror = function() {
|
||||
errorCallback(xhr);
|
||||
}
|
||||
xhr.ontimeout = xhr.onerror;
|
||||
}
|
||||
if (type == "POST") {
|
||||
var poststr;
|
||||
var post = [];
|
||||
for (var i in data) {
|
||||
post.push(i+"="+encodeURIComponent(data[i]));
|
||||
}
|
||||
if (post.length) { poststr = post.join("&"); }
|
||||
xhr.send(poststr);
|
||||
}
|
||||
else {
|
||||
xhr.send();
|
||||
}
|
||||
},
|
||||
get: function(url,callback,errorCallback){
|
||||
this.getpost("GET",url,null,callback,errorCallback);
|
||||
},
|
||||
post: function(url,data,callback,errorCallback){
|
||||
this.getpost("POST",url,data,callback,errorCallback);
|
||||
},
|
||||
url: {
|
||||
addParam: function(url,params){
|
||||
var spliturl = url.split("?");
|
||||
var ret = [spliturl.shift()];
|
||||
var splitparams = [];
|
||||
if (spliturl.length) {
|
||||
splitparams = spliturl[0].split("&");
|
||||
}
|
||||
for (var i in params) {
|
||||
splitparams.push(i+"="+params[i]);
|
||||
}
|
||||
if (splitparams.length) { ret.push(splitparams.join("&")); }
|
||||
return ret.join("?");
|
||||
},
|
||||
split: function(url){
|
||||
var a = document.createElement("a");
|
||||
a.href = url;
|
||||
return {
|
||||
protocol: a.protocol,
|
||||
host: a.hostname,
|
||||
hash: a.hash,
|
||||
port: a.port,
|
||||
path: a.pathname.replace(/\/*$/,"")
|
||||
};
|
||||
},
|
||||
sanitizeHost: function(host){
|
||||
var split = MistUtil.http.url.split(host);
|
||||
return split.protocol + "//" + split.host + (split.port && (split.port != "") ? ":"+split.port : "") + (split.hash && (split.hash != "") ? "#"+split.hash : "") + (split.path ? split.path : "");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
css: {
|
||||
cache: {},
|
||||
load: function(url,colors,callback){
|
||||
var style = document.createElement("style");
|
||||
style.type = "text/css";
|
||||
style.setAttribute("data-source",url);
|
||||
if (callback) { style.callback = callback; }
|
||||
var cache = this.cache;
|
||||
|
||||
function onCSSLoad(d) {
|
||||
//parse rules and replace variables; expected syntax $abc[.abc]
|
||||
var css = MistUtil.css.applyColors(d,colors);
|
||||
|
||||
if ("callback" in style) { style.callback(css); }
|
||||
else { style.textContent = css; }
|
||||
}
|
||||
|
||||
if (url in cache) {
|
||||
if (cache[url] instanceof Array) {
|
||||
cache[url].push(onCSSLoad);
|
||||
}
|
||||
else {
|
||||
onCSSLoad(cache[url]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//retrieve file contents
|
||||
cache[url] = [onCSSLoad];
|
||||
MistUtil.http.get(url,function(d){
|
||||
for (var i in cache[url]) {
|
||||
cache[url][i](d);
|
||||
}
|
||||
cache[url] = d;
|
||||
},function(){
|
||||
throw "Failed to load CSS from "+url;
|
||||
});
|
||||
}
|
||||
|
||||
return style; //its empty now, but will be filled on load
|
||||
},
|
||||
applyColors: function(css,colors) {
|
||||
return css.replace(/\$([^\s^;^}]*)/g,function(str,variable){
|
||||
var index = variable.split(".");
|
||||
var val = colors;
|
||||
for (var j in index) {
|
||||
val = val[index[j]];
|
||||
}
|
||||
return val;
|
||||
});
|
||||
},
|
||||
createStyle: function(css,prepend,applyToChildren){
|
||||
var style = document.createElement("style");
|
||||
style.type = "text/css";
|
||||
|
||||
if (css) {
|
||||
if (prepend) {
|
||||
css = this.prependClass(css,prepend,applyToChildren);
|
||||
}
|
||||
style.textContent = css;
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
prependClass: function (css,prepend,applyToChildren) {
|
||||
var style = false;
|
||||
if (typeof css != "string") {
|
||||
style = css;
|
||||
if (!("unprepended" in style)) {
|
||||
style.unprepended = style.textContent;
|
||||
}
|
||||
css = style.unprepended;
|
||||
}
|
||||
//remove all block comments
|
||||
css = css.replace(/\/\*.*?\*\//g,"");
|
||||
|
||||
//save all @{} blocks
|
||||
var save = css.match(/@.*?{.*}/g);
|
||||
for (var i in save) {
|
||||
css = css.replace(save[i],"@@@@");
|
||||
}
|
||||
|
||||
//find and replace selectors
|
||||
css = css.replace(/[^@]*?{[^]*?}/g,function(match){
|
||||
var split = match.split("{")
|
||||
var selectors = split[0].split(",");
|
||||
var properties = "{"+split.slice(1).join("}");
|
||||
|
||||
for (var i in selectors) {
|
||||
selectors[i] = selectors[i].trim();
|
||||
var str = "."+prepend+selectors[i];
|
||||
if (applyToChildren) {
|
||||
str += ",\n."+prepend+" "+selectors[i];
|
||||
}
|
||||
selectors[i] = str;
|
||||
}
|
||||
|
||||
|
||||
return "\n"+selectors+" "+properties;
|
||||
});
|
||||
|
||||
//reinsert saved blocks
|
||||
for (var i in save) {
|
||||
css = css.replace(/@@@@/,save[i]);
|
||||
}
|
||||
|
||||
if (style) {
|
||||
style.textContent = css;
|
||||
return;
|
||||
}
|
||||
|
||||
return css;
|
||||
}
|
||||
},
|
||||
|
||||
empty: function(DOMelement) {
|
||||
while (DOMelement.lastChild){
|
||||
if (DOMelement.lastChild.lastChild) {
|
||||
//also empty this child
|
||||
this.empty(DOMelement.lastChild);
|
||||
}
|
||||
if ("attachedListeners" in DOMelement.lastChild) {
|
||||
//remove attached event listeners
|
||||
for (var i in DOMelement.lastChild.attachedListeners) {
|
||||
MistUtil.event.removeListener(DOMelement.lastChild.attachedListeners[i]);
|
||||
}
|
||||
}
|
||||
DOMelement.removeChild(DOMelement.lastChild);
|
||||
}
|
||||
},
|
||||
|
||||
event: {
|
||||
send: function(type,message,target){
|
||||
try {
|
||||
var event = new Event(type,{
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
event.message = message;
|
||||
target.dispatchEvent(event);
|
||||
}
|
||||
catch (e) {
|
||||
try {
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent(type,true,true);
|
||||
event.message = message;
|
||||
target.dispatchEvent(event);
|
||||
}
|
||||
catch (e) { return false; }
|
||||
}
|
||||
return true;
|
||||
},
|
||||
addListener: function(DOMelement,type,callback,storeOnElement) {
|
||||
//add an event listener and store the handles, so they can be cleared
|
||||
|
||||
DOMelement.addEventListener(type,callback);
|
||||
|
||||
if (!storeOnElement) { storeOnElement = DOMelement; }
|
||||
if (!("attachedListeners" in storeOnElement)) {
|
||||
storeOnElement.attachedListeners = [];
|
||||
}
|
||||
var output = {
|
||||
element: DOMelement,
|
||||
type: type,
|
||||
callback: callback
|
||||
};
|
||||
|
||||
storeOnElement.attachedListeners.push(output);
|
||||
return output;
|
||||
},
|
||||
removeListener: function(data) {
|
||||
data.element.removeEventListener(data.type, data.callback);
|
||||
}
|
||||
},
|
||||
|
||||
scripts: {
|
||||
list: {},
|
||||
insert: function(src,onevent,MistVideo){
|
||||
var scripts = this;
|
||||
|
||||
if (MistVideo) {
|
||||
//register so we can remove it on unload
|
||||
MistVideo.errorListeners.push({
|
||||
src: src,
|
||||
onevent: onevent
|
||||
});
|
||||
}
|
||||
if (src in this.list) {
|
||||
//already present
|
||||
//register to error listening
|
||||
this.list[src].subscribers.push(onevent.onerror);
|
||||
//execute onload
|
||||
if ("onload" in onevent) {
|
||||
if (this.hasLoaded) {
|
||||
onevent.onload();
|
||||
}
|
||||
else {
|
||||
MistUtil.event.addListener(this.list[src].tag,"load",onevent.onload);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var scripttag = document.createElement("script");
|
||||
scripttag.hasLoaded = false;
|
||||
scripttag.setAttribute("src",src);
|
||||
scripttag.setAttribute("crossorigin","anonymous"); //must be set to get info about errors thrown
|
||||
document.head.appendChild(scripttag);
|
||||
scripttag.onerror = function(e){
|
||||
onevent.onerror(e);
|
||||
}
|
||||
scripttag.onload = function(e){
|
||||
this.hasLoaded = true;
|
||||
if (!MistVideo.destroyed) { onevent.onload(e); }
|
||||
}
|
||||
scripttag.addEventListener("error",function(e){
|
||||
onevent.onerror(e);
|
||||
});
|
||||
|
||||
|
||||
//error catching
|
||||
var oldonerror = false;
|
||||
if (window.onerror) {
|
||||
oldonerror = window.onerror;
|
||||
}
|
||||
window.onerror = function(message,source,line,column,error){
|
||||
if (oldonerror) {
|
||||
oldonerror.apply(this,arguments);
|
||||
}
|
||||
if (source == src) {
|
||||
onevent.onerror(error);
|
||||
for (var i in scripts.list[src].subscribers) {
|
||||
scripts.list[src].subscribers[i](error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.list[src] = {
|
||||
subscribers: [onevent.onerror],
|
||||
tag: scripttag
|
||||
};
|
||||
|
||||
return scripttag;
|
||||
}
|
||||
},
|
||||
|
||||
tracks: {
|
||||
parse: function(metaTracks){
|
||||
var output = {};
|
||||
for (var i in metaTracks) {
|
||||
var track = MistUtil.object.extend({},metaTracks[i]);
|
||||
if (track.type == "meta") {
|
||||
track.type = track.codec;
|
||||
track.codec = "meta";
|
||||
}
|
||||
|
||||
if (!(track.type in output)) { output[track.type] = {}; }
|
||||
output[track.type][track.trackid] = track;
|
||||
|
||||
//make up something logical for the track displayname
|
||||
var name = {};
|
||||
|
||||
for (var j in track) {
|
||||
switch (j) {
|
||||
case "width":
|
||||
name[j] = track.width+"×"+track.height;
|
||||
break;
|
||||
case "bps":
|
||||
if (track.codec == "meta") { continue; }
|
||||
if (track.bps > 0) {
|
||||
var val;
|
||||
if (track.bps > 1024*1024/8) {
|
||||
val = Math.round(track.bps/1024/1024*8)+"mbps";
|
||||
}
|
||||
else {
|
||||
val = Math.round(track.bps/1024*8)+"kbps";
|
||||
}
|
||||
name[j] = val;
|
||||
}
|
||||
break;
|
||||
case "fpks":
|
||||
if (track.fpks > 0) {
|
||||
name[j] = track.fpks/1e3+"fps";
|
||||
}
|
||||
break;
|
||||
case "channels":
|
||||
if (track.channels > 0) {
|
||||
name[j] = (track.channels == 1 ? "Mono" : (track.channels == 2 ? "Stereo" : "Surround ("+track.channels+"ch)"));
|
||||
}
|
||||
break;
|
||||
case "rate":
|
||||
name[j] = Math.round(track.rate)+"Khz";
|
||||
break;
|
||||
case "language":
|
||||
if (track[j] != "Undetermined") { name[j] = track[j]; }
|
||||
break;
|
||||
case "codec":
|
||||
if (track.codec == "meta") { continue; }
|
||||
name[j] = track[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
track.describe = name;
|
||||
|
||||
}
|
||||
|
||||
//filter what to display based on what is different
|
||||
for (var type in output) {
|
||||
var equal = false;
|
||||
for (var i in output[type]) {
|
||||
if (!equal) {
|
||||
//fill equal with all the keys and values of the first track of this type
|
||||
equal = MistUtil.object.extend({},output[type][i].describe);
|
||||
continue;
|
||||
}
|
||||
if (MistUtil.object.keys(output[type]).length > 1) {
|
||||
//if there is more than one track of this type
|
||||
for (var j in output[type][i].describe) {
|
||||
if (equal[j] != output[type][i].describe[j]) {
|
||||
//remove key from equal if not equal
|
||||
delete equal[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//apply
|
||||
for (var i in output[type]) {
|
||||
var different = {};
|
||||
var same = {};
|
||||
for (var j in output[type][i].describe) {
|
||||
if (!(j in equal)){
|
||||
different[j] = output[type][i].describe[j];
|
||||
}
|
||||
else {
|
||||
same[j] = output[type][i].describe[j];
|
||||
}
|
||||
}
|
||||
output[type][i].different = different;
|
||||
output[type][i].same = same;
|
||||
var d = MistUtil.object.values(different);
|
||||
output[type][i].displayName = (d.length ? d.join(", ") : MistUtil.object.values(output[type][i].describe).join(" "));
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
},
|
||||
isTouchDevice: function(){
|
||||
return (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
|
||||
//return true;
|
||||
},
|
||||
getPos: function(element,cursorLocation){
|
||||
var style = element.currentStyle || window.getComputedStyle(element, null);
|
||||
|
||||
var zoom = 1;
|
||||
var node = element;
|
||||
while (node) {
|
||||
if ((node.style.zoom) && (node.style.zoom != "")) {
|
||||
zoom *= parseFloat(node.style.zoom,10);
|
||||
}
|
||||
node = node.parentElement;
|
||||
}
|
||||
|
||||
var pos0 = element.getBoundingClientRect().left - (parseInt(element.borderLeftWidth,10) || 0);
|
||||
|
||||
var width = element.getBoundingClientRect().width;;
|
||||
var perc = Math.max(0,((cursorLocation.clientX/zoom) - pos0) / width);
|
||||
perc = Math.min(perc,1);
|
||||
|
||||
return perc;
|
||||
},
|
||||
|
||||
createGraph: function(data,options){
|
||||
var ns = "http://www.w3.org/2000/svg";
|
||||
|
||||
var svg = document.createElementNS(ns,"svg");
|
||||
svg.setAttributeNS(null,"height","100%");
|
||||
svg.setAttributeNS(null,"width","100%");
|
||||
svg.setAttributeNS(null,"class","mist icon graph");
|
||||
svg.setAttributeNS(null,"preserveAspectRatio","none");
|
||||
|
||||
var x_correction = data.x[0];
|
||||
var lasty = data.y[0];
|
||||
if (options.differentiate) {
|
||||
for (var i = 1; i < data.y.length; i++) {
|
||||
var diff = data.y[i] - lasty;
|
||||
lasty = data.y[i];
|
||||
data.y[i] = diff;
|
||||
}
|
||||
}
|
||||
|
||||
var path = [];
|
||||
var area = {
|
||||
x: {
|
||||
min: data.x[0] - x_correction,
|
||||
max: data.x[0] - x_correction
|
||||
},
|
||||
y: {
|
||||
min: data.y[0]*-1,
|
||||
max: data.y[0]*-1
|
||||
}
|
||||
};
|
||||
|
||||
function updateMinMax(x,y) {
|
||||
if (arguments.length) {
|
||||
area.x.min = Math.min(area.x.min,x);
|
||||
area.x.max = Math.max(area.x.max,x);
|
||||
area.y.min = Math.min(area.y.min,y*-1);
|
||||
area.y.max = Math.max(area.y.max,y*-1);
|
||||
}
|
||||
else {
|
||||
//reprocess the entire path
|
||||
var d = path[0].split(",");
|
||||
area = {
|
||||
x: {
|
||||
min: d[0],
|
||||
max: d[0]
|
||||
},
|
||||
y: {
|
||||
min: d[1],
|
||||
max: d[1]
|
||||
}
|
||||
};
|
||||
for (var i = 1; i < path.length; i++) {
|
||||
var d = path[i].split(",");
|
||||
updateMinMax(d[0],d[1]*-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.push([data.x[0] - x_correction,data.y[0]*-1].join(","));
|
||||
for (var i = 1; i < data.y.length; i++) {
|
||||
updateMinMax(data.x[i] - x_correction,data.y[i]*-1);
|
||||
path.push("L "+[data.x[i] - x_correction,data.y[i]*-1].join(","));
|
||||
}
|
||||
|
||||
//define gradient
|
||||
var defs = document.createElementNS(ns,"defs");
|
||||
svg.appendChild(defs);
|
||||
var gradient = document.createElementNS(ns,"linearGradient");
|
||||
defs.appendChild(gradient);
|
||||
gradient.setAttributeNS(null,"id",MistUtil.createUnique());
|
||||
gradient.setAttributeNS(null,"gradientUnits","userSpaceOnUse");
|
||||
gradient.innerHTML += '<stop offset="0" stop-color="green"/>';
|
||||
gradient.innerHTML += '<stop offset="0.33" stop-color="yellow"/>';
|
||||
gradient.innerHTML += '<stop offset="0.66" stop-color="orange"/>';
|
||||
gradient.innerHTML += '<stop offset="1" stop-color="red"/>';
|
||||
|
||||
function updateViewBox() {
|
||||
if ("x" in options) {
|
||||
if ("min" in options.x) { area.x.min = options.x.min; }
|
||||
if ("max" in options.x) { area.x.max = options.x.max; }
|
||||
if ("count" in options.x) { area.x.min = area.x.max - options.x.count; }
|
||||
}
|
||||
if ("y" in options) {
|
||||
if ("min" in options.y) { area.y.min = options.y.max*-1; }
|
||||
if ("max" in options.y) { area.y.max = options.y.min*-1; }
|
||||
}
|
||||
svg.setAttributeNS(null,"viewBox",[area.x.min,area.y.min,area.x.max - area.x.min,area.y.max - area.y.min].join(" "));
|
||||
|
||||
gradient.setAttributeNS(null,"x1",0);
|
||||
gradient.setAttributeNS(null,"x2",0);
|
||||
if (options.reverseGradient) {
|
||||
gradient.setAttributeNS(null,"y1",area.y.max);
|
||||
gradient.setAttributeNS(null,"y2",area.y.min);
|
||||
}
|
||||
else {
|
||||
gradient.setAttributeNS(null,"y1",area.y.min);
|
||||
gradient.setAttributeNS(null,"y2",area.y.max);
|
||||
}
|
||||
}
|
||||
updateViewBox();
|
||||
|
||||
var line = document.createElementNS(ns,"path");
|
||||
svg.appendChild(line);
|
||||
//line.setAttributeNS(null,"vector-effect","non-scaling-stroke");
|
||||
line.setAttributeNS(null,"stroke-width","0.1");
|
||||
line.setAttributeNS(null,"fill","none");
|
||||
line.setAttributeNS(null,"stroke","url(#"+gradient.getAttribute("id")+")");
|
||||
line.setAttributeNS(null,"d","M"+path.join(" L"));
|
||||
|
||||
line.addData = function(newData) {
|
||||
|
||||
if (options.differentiate) {
|
||||
var diff = newData.y - lasty;
|
||||
lasty = newData.y;
|
||||
newData.y = diff;
|
||||
}
|
||||
|
||||
path.push([newData.x - x_correction,newData.y*-1].join(","));
|
||||
if (options.x && options.x.count) {
|
||||
if (path.length > options.x.count) {
|
||||
path.shift();
|
||||
updateMinMax();
|
||||
}
|
||||
}
|
||||
updateMinMax(newData.x - x_correction,newData.y*-1);
|
||||
this.setAttributeNS(null,"d","M"+path.join(" L"));
|
||||
updateViewBox();
|
||||
};
|
||||
svg.addData = function(newData){
|
||||
line.addData(newData);
|
||||
};
|
||||
|
||||
return svg;
|
||||
},
|
||||
getBrowser: function(){
|
||||
var ua = window.navigator.userAgent;
|
||||
|
||||
if ((ua.indexOf("MSIE ") >= 0) || (ua.indexOf("Trident/") >= 0)) {
|
||||
return "ie";
|
||||
}
|
||||
if (ua.indexOf("Edge/") >= 0) {
|
||||
return "edge";
|
||||
}
|
||||
if ((ua.indexOf("Opera") >= 0) || (ua.indexOf('OPR') >= 0)) {
|
||||
return "opera";
|
||||
}
|
||||
if (ua.indexOf("Chrome") >= 0) {
|
||||
return "chrome";
|
||||
}
|
||||
if (ua.indexOf("Safari") >= 0) {
|
||||
return "safari";
|
||||
}
|
||||
if (ua.indexOf("Firefox") >= 0) {
|
||||
return "firefox";
|
||||
}
|
||||
return false; //unknown
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue