diff --git a/public/webshims/shims/url.js b/public/webshims/shims/url.js new file mode 100644 index 0000000000000000000000000000000000000000..0e980c790ed1d7bd8d2bf127a6b395b3c06672cb --- /dev/null +++ b/public/webshims/shims/url.js @@ -0,0 +1,316 @@ +webshim.register('url', function($, webshims, window, document, undefined, options){ +'use strict'; + +// URL Polyfill +// Draft specification: http://url.spec.whatwg.org + +// Notes: +// - Primarily useful for parsing URLs and modifying query parameters +// - Should work in IE8+ and everything more modern + + (function (global) { + // Browsers may have: + // * No global URL object + // * URL with static methods only - may have a dummy constructor + // * URL with members except searchParams + // * Full URL API support + var origURL = global.URL; + var nativeURL; + try { + if (origURL) { + nativeURL = new global.URL('http://example.com'); + if ('searchParams' in nativeURL) + return; + if (!('href' in nativeURL)) + nativeURL = undefined; + } + } catch (_) {} + + function URLUtils(url) { + if (nativeURL) + return new origURL(url); + var anchor = document.createElement('a'); + anchor.href = url; + return anchor; + } + + global.URL = function URL(url, base) { + if (!(this instanceof global.URL)) + throw new TypeError("Failed to construct 'URL': Please use the 'new' operator."); + + if (base) { + url = (function () { + if (nativeURL) return new origURL(url, base).href; + + var doc; + // Use another document/base tag/anchor for relative URL resolution, if possible + if (document.implementation && document.implementation.createHTMLDocument) { + doc = document.implementation.createHTMLDocument(''); + } else if (document.implementation && document.implementation.createDocument) { + doc = document.implementation.createElement('http://www.w3.org/1999/xhtml', 'html', null); + doc.documentElement.appendChild(doc.createElement('head')); + doc.documentElement.appendChild(doc.createElement('body')); + } else if (window.ActiveXObject) { + doc = new window.ActiveXObject('htmlfile'); + doc.write('<head></head><body></body>'); + doc.close(); + } + + if (!doc) throw Error('base not supported'); + + var baseTag = doc.createElement('base'); + baseTag.href = base; + doc.getElementsByTagName('head')[0].appendChild(baseTag); + var anchor = doc.createElement('a'); + anchor.href = url; + return anchor.href; + }()); + } + + // An inner object implementing URLUtils (either a native URL + // object or an HTMLAnchorElement instance) is used to perform the + // URL algorithms. With full ES5 getter/setter support, return a + // regular object For IE8's limited getter/setter support, a + // different HTMLAnchorElement is returned with properties + // overridden + + var instance = URLUtils(url || ''); + + // Detect for ES5 getter/setter support + var ES5_GET_SET = (Object.defineProperties && (function () { + var o = {}; Object.defineProperties(o, { p: { 'get': function () { return true; } } }); return o.p; + }())); + + var self = ES5_GET_SET ? this : document.createElement('a'); + + // NOTE: Doesn't do the encoding/decoding dance + function parse(input, isindex) { + var sequences = input.split('&'); + if (isindex && sequences[0].indexOf('=') === -1) + sequences[0] = '=' + sequences[0]; + var pairs = []; + sequences.forEach(function (bytes) { + if (bytes.length === 0) return; + var index = bytes.indexOf('='); + if (index !== -1) { + var name = bytes.substring(0, index); + var value = bytes.substring(index + 1); + } else { + name = bytes; + value = ''; + } + name = name.replace('+', ' '); + value = value.replace('+', ' '); + pairs.push({ name: name, value: value }); + }); + var output = []; + pairs.forEach(function (pair) { + output.push({ + name: decodeURIComponent(pair.name), + value: decodeURIComponent(pair.value) + }); + }); + return output; // Spec bug? + } + + function URLSearchParams(url_object, init) { + var pairs = []; + if (init) + pairs = parse(init); + + this._setPairs = function (list) { pairs = list; }; + this._updateSteps = function () { updateSteps(); }; + + var updating = false; + function updateSteps() { + if (updating) return; + updating = true; + + // TODO: For all associated url objects + url_object.search = serialize(pairs); + + updating = false; + } + + // NOTE: Doesn't do the encoding/decoding dance + function serialize(pairs) { + var output = '', first = true; + pairs.forEach(function (pair) { + var name = encodeURIComponent(pair.name); + var value = encodeURIComponent(pair.value); + if (!first) output += '&'; + output += name + '=' + value; + first = false; + }); + return output; + } + + webshim.defineProperties(this, { + append: { + value: function (name, value) { + pairs.push({ name: name, value: value }); + updateSteps(); + } + }, + + 'delete': { + value: function (name) { + for (var i = 0; i < pairs.length;) { + if (pairs[i].name === name) + pairs.splice(i, 1); + else + ++i; + } + updateSteps(); + } + }, + + get: { + value: function (name) { + for (var i = 0; i < pairs.length; ++i) { + if (pairs[i].name === name) + return pairs[i].value; + } + return null; + } + }, + + getAll: { + value: function (name) { + var result = []; + for (var i = 0; i < pairs.length; ++i) { + if (pairs[i].name === name) + result.push(pairs[i].value); + } + return result; + } + }, + + has: { + value: function (name) { + for (var i = 0; i < pairs.length; ++i) { + if (pairs[i].name === name) + return true; + } + return false; + } + }, + + set: { + value: function (name, value) { + var found = false; + for (var i = 0; i < pairs.length;) { + if (pairs[i].name === name) { + if (!found) { + pairs[i].value = value; + ++i; + } else { + pairs.splice(i, 1); + } + } else { + ++i; + } + } + updateSteps(); + } + }, + + toString: { + value: function () { + return serialize(pairs); + } + } + }); + }; + + var queryObject = new URLSearchParams( + self, instance.search ? instance.search.substring(1) : null); + + webshim.defineProperties(self, { + href: { + get: function () { return instance.href; }, + set: function (v) { instance.href = v; tidy_instance(); update_steps(); } + }, + origin: { + get: function () { + if ('origin' in instance) return instance.origin; + return this.protocol + '//' + this.host; + } + }, + protocol: { + get: function () { return instance.protocol; }, + set: function (v) { instance.protocol = v; } + }, + username: { + get: function () { return instance.username; }, + set: function (v) { instance.username = v; } + }, + password: { + get: function () { return instance.password; }, + set: function (v) { instance.password = v; } + }, + host: { + get: function () { + // IE returns default port in |host| + var re = {'http:': /:80$/, 'https:': /:443$/, 'ftp:': /:21$/}[instance.protocol]; + return re ? instance.host.replace(re, '') : instance.host; + }, + set: function (v) { instance.host = v; } + }, + hostname: { + get: function () { return instance.hostname; }, + set: function (v) { instance.hostname = v; } + }, + port: { + get: function () { return instance.port; }, + set: function (v) { instance.port = v; } + }, + pathname: { + get: function () { + // IE does not include leading '/' in |pathname| + if (instance.pathname.charAt(0) !== '/') return '/' + instance.pathname; + return instance.pathname; + }, + set: function (v) { instance.pathname = v; } + }, + search: { + get: function () { return instance.search; }, + set: function (v) { + if (instance.search === v) return; + instance.search = v; tidy_instance(); update_steps(); + } + }, + searchParams: { + get: function () { return queryObject; } + // TODO: implement setter + }, + hash: { + get: function () { return instance.hash; }, + set: function (v) { instance.hash = v; tidy_instance(); } + } + }); + + function tidy_instance() { + var href = instance.href.replace(/#$|\?$|\?(?=#)/g, ''); + if (instance.href !== href) + instance.href = href; + } + + function update_steps() { + queryObject._setPairs(instance.search ? parse(instance.search.substring(1)) : []); + queryObject._updateSteps(); + } + + return self; + }; + + if (origURL) { + for (var i in origURL) { + if (origURL.hasOwnProperty(i)) + global.URL[i] = origURL[i]; + } + } + + }(window)); + +}); diff --git a/public/webshims/shims/usermedia-core.js b/public/webshims/shims/usermedia-core.js new file mode 100644 index 0000000000000000000000000000000000000000..22ab9137523aff5e25b9abe1a03c964c263a7b77 --- /dev/null +++ b/public/webshims/shims/usermedia-core.js @@ -0,0 +1,28 @@ +webshim.register('usermedia-core', function($, webshim, window, document, undefined, options){ + "use strict"; + + var srcObjectName = webshim.prefixed('srcObject', document.createElement('video')); + var addUnPrefixed = function(){ + navigator.getUserMedia = navigator[webshim.prefixed('getUserMedia', navigator)]; + }; + if(srcObjectName != 'srcObject'){ + var hasURL = !!(window.URL && URL.createObjectURL); + webshim.defineNodeNamesProperty(['audio', 'video'], 'srcObject', { + prop: { + get: function(){ + return this[srcObjectName] || null; + }, + set: function(stream){ + if(srcObjectName){ + $.prop(this, srcObjectName, stream); + } else { + $.prop(this, 'src', hasURL ? URL.createObjectURL(stream) : stream); + } + } + } + }); + } + + + webshim.ready(webshim.modules["usermedia-shim"].loaded ? 'usermedia-api' : 'usermedia-shim', addUnPrefixed); +}); diff --git a/public/webshims/shims/usermedia-shim.js b/public/webshims/shims/usermedia-shim.js new file mode 100644 index 0000000000000000000000000000000000000000..3cabe13ca9f506fe974d87ec124f7764136aa1bf --- /dev/null +++ b/public/webshims/shims/usermedia-shim.js @@ -0,0 +1,179 @@ +webshim.register('usermedia-shim', function($, webshim, window, document, undefined, options){ + "use strict"; + var addMediaAPI; + var streamUrlPrefix = 'webshimstream'; + var id = 0; + var streams = {}; + var streamCb = {}; + var hasSwf = swfmini.hasFlashPlayerVersion('11.3'); + var mediaOptions = webshim.cfg.mediaelement; + var mediaelement = webshim.mediaelement; + var flashEvents = { + NOT_SUPPORTED_ERROR: 1, + PERMISSION_DENIED: 1, + //not implemented yet + MANDATORY_UNSATISFIED_ERROR: 1, + onUserSuccess: 1 + }; + var noSource = function(){ + return !$.prop(this, 'currentSrc') && !mediaelement.srces(this).length; + }; + + function wsGetUserMedia(constraints, successCb, failCb){ + if(hasSwf){ + if(!webshim.mediaelement.createSWF){ + webshim.loader.loadList(['swfmini-embed']); + webshim.mediaelement.loadSwf = true; + webshim.reTest(['mediaelement-jaris'], true); + webshim.ready('mediaelement-jaris', function(){ + createMediaRequest(constraints, successCb, failCb); + }); + } else { + createMediaRequest(constraints, successCb, failCb); + } + } else { + failCb({name: 'NOT_SUPPORTED_ERROR'}); + } + } + + function createMediaRequest(constraints, successCb, failCb){ + var src; + var media = getMediaCandidate(); + if(!media){return;} + + id++; + src = 'webshimstream:stream'+id; + + streamCb[src] = { + src: src, + success: successCb, + fail: failCb + }; + + addMediaAPI(); + mediaelement.createSWF(media, {srcProp: src, streamrequest: true, type: 'jarisplayer/stream'}); + } + + + + function getMediaCandidate(){ + var $media = $('video'); + $media = $media.filter('.ws-usermedia'); + if(!$media.length){ + $media = $media.end(); + } + if($media.length != 1){ + $media = $media.filter(noSource); + } + if($media.length != 1){ + webshim.error('for getUserMedia an empty video element has to be already in the DOM. If you provide multiple empty videos. please mark your suggested video using the "ws-usermedia" class.'); + } + return $media[0]; + } + + + function LocalMediaStream(data, api, id){ + webshim.defineProperties(this, { + _swf: { + value: api, + enumerable: false + }, + _data: { + value: data, + enumerable: false + }, + _wsStreamId: { + value: id, + enumerable: false + } + }); + } + + + + LocalMediaStream.prototype = { + currentTime: 0, + stop: function(){ + mediaelement.queueSwfMethod(this._data._elem, 'api_detach', [], this._data); + }, + getAudioTracks: $.noop, + getVideoTracks: $.noop + }; + + + webshim.usermedia = { + attach: function(elem, canPlaySrc, data){ + if(data._usermedia == canPlaySrc.srcProp){ + mediaelement.queueSwfMethod(data._elem, 'api_attach', [], data); + $(data._elem).trigger('loadstart'); + } else { + webshim.error('something went wrong'); + } + }, + request: function(elem, canPlaySrc, data){ + data._usermedia = canPlaySrc.srcProp; + if(!options.inline && !$(elem).hasClass('ws-inlineusermedia')){ + $(data.api).css({position: 'fixed', top: 0, left: 0, width: '100%', height: 150, zIndex: '999999'}); + } else { + $(data.api).css({position: 'relative', zIndex: '999999'}); + } + } + }; + + URL._nativeCreateObjectURL = URL.createObjectURL; + URL._nativeRevokeObjectURL = URL.revokeObjectURL; + + URL.createObjectURL = function(stream){ + + var url = ''; + if(URL._nativeCreateObjectURL && !stream._wsStreamId){ + url = URL._nativeCreateObjectURL(stream); + } else if(stream._wsStreamId) { + url = stream._wsStreamId; + streams[url] = stream; + } + return url; + }; + + URL.revokeObjectURL = function(url){ + if(streams[url]){ + delete streams[url]; + } + if(URL._nativeRevokeObjectURL){ + return URL._nativeRevokeObjectURL(url); + } + }; + webshim.usermediastreams = streams; + + addMediaAPI = function(){ + if(!webshim.mediaelement.createSWF){return;} + addMediaAPI = $.noop; + var revert = function(data){ + setTimeout(function(){ + $(data.api).css({position: '', top: '', left: '', width: '', height: '', zIndex: ''}); + if($.prop(data._elem, 'controls')){ + $.prop(data._elem, 'controls', true); + } + }, 50); + }; + var fail = function(jaris, data){ + revert(data); + streamCb[data._usermedia].fail({name: jaris.type}); + }; + $.extend(mediaelement.onEvent, { + NOT_SUPPORTED_ERROR: fail, + PERMISSION_DENIED: fail, + //not implemented yet + MANDATORY_UNSATISFIED_ERROR: fail, + onUserSuccess: function(jaris, data){ + revert(data); + streamCb[data._usermedia].success(new LocalMediaStream(data, data.api, data._usermedia)); + } + }); + }; + webshim.ready('mediaelement-jaris', addMediaAPI); + + webshim.getUserMedia = wsGetUserMedia; + navigator.wsGetUserMedia = wsGetUserMedia; + webshim.isReady('usermedia-api', true); +});