diff --git a/Disco.Web/ClientSource/Scripts/Core.min.js b/Disco.Web/ClientSource/Scripts/Core.min.js index 09e532fc..654ffa10 100644 --- a/Disco.Web/ClientSource/Scripts/Core.min.js +++ b/Disco.Web/ClientSource/Scripts/Core.min.js @@ -23,7 +23,7 @@ return function(n,t){function p(n,t){var i=n.createElement("p"),r=n.getElementsB * * Date: 2014-05-01T17:11Z */ -(function(n,t){typeof module=="object"&&typeof module.exports=="object"?module.exports=n.document?t(n,!0):function(n){if(!n.document)throw new Error("jQuery requires a window with a document");return t(n)}:t(n)})(typeof window!="undefined"?window:this,function(n,t){function ui(n){var t=n.length,r=i.type(n);return r==="function"||i.isWindow(n)?!1:n.nodeType===1&&t?!0:r==="array"||t===0||typeof t=="number"&&t>0&&t-1 in n}function fi(n,t,r){if(i.isFunction(t))return i.grep(n,function(n,i){return!!t.call(n,i,n)!==r});if(t.nodeType)return i.grep(n,function(n){return n===t!==r});if(typeof t=="string"){if(ef.test(t))return i.filter(t,n,r);t=i.filter(t,n)}return i.grep(n,function(n){return et.call(t,n)>=0!==r})}function ur(n,t){while((n=n[t])&&n.nodeType!==1);return n}function of(n){var t=ei[n]={};return i.each(n.match(c)||[],function(n,i){t[i]=!0}),t}function ct(){u.removeEventListener("DOMContentLoaded",ct,!1);n.removeEventListener("load",ct,!1);i.ready()}function p(){Object.defineProperty(this.cache={},0,{get:function(){return{}}});this.expando=i.expando+Math.random()}function fr(n,t,r){var u;if(r===undefined&&n.nodeType===1)if(u="data-"+t.replace(hf,"-$1").toLowerCase(),r=n.getAttribute(u),typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:sf.test(r)?i.parseJSON(r):r}catch(f){}e.set(n,t,r)}else r=undefined;return r}function at(){return!0}function g(){return!1}function hr(){try{return u.activeElement}catch(n){}}function vr(n,t){return i.nodeName(n,"table")&&i.nodeName(t.nodeType!==11?t:t.firstChild,"tr")?n.getElementsByTagName("tbody")[0]||n.appendChild(n.ownerDocument.createElement("tbody")):n}function bf(n){return n.type=(n.getAttribute("type")!==null)+"/"+n.type,n}function kf(n){var t=pf.exec(n.type);return t?n.type=t[1]:n.removeAttribute("type"),n}function oi(n,t){for(var i=0,u=n.length;i")).appendTo(r.documentElement),r=vt[0].contentDocument,r.write(),r.close(),t=pr(n,r),vt.detach()),si[n]=t),t}function rt(n,t,r){var e,o,s,u,f=n.style;return r=r||yt(n),r&&(u=r.getPropertyValue(t)||r[t]),r&&(u!==""||i.contains(n.ownerDocument,n)||(u=i.style(n,t)),ci.test(u)&&wr.test(t)&&(e=f.width,o=f.minWidth,s=f.maxWidth,f.minWidth=f.maxWidth=f.width=u,u=r.width,f.width=e,f.minWidth=o,f.maxWidth=s)),u!==undefined?u+"":u}function br(n,t){return{get:function(){if(n()){delete this.get;return}return(this.get=t).apply(this,arguments)}}}function gr(n,t){if(t in n)return t;for(var r=t[0].toUpperCase()+t.slice(1),u=t,i=dr.length;i--;)if(t=dr[i]+r,t in n)return t;return u}function nu(n,t,i){var r=ne.exec(t);return r?Math.max(0,r[1]-(i||0))+(r[2]||"px"):t}function tu(n,t,r,u,f){for(var e=r===(u?"border":"content")?4:t==="width"?1:0,o=0;e<4;e+=2)r==="margin"&&(o+=i.css(n,r+w[e],!0,f)),u?(r==="content"&&(o-=i.css(n,"padding"+w[e],!0,f)),r!=="margin"&&(o-=i.css(n,"border"+w[e]+"Width",!0,f))):(o+=i.css(n,"padding"+w[e],!0,f),r!=="padding"&&(o+=i.css(n,"border"+w[e]+"Width",!0,f)));return o}function iu(n,t,r){var o=!0,u=t==="width"?n.offsetWidth:n.offsetHeight,e=yt(n),s=i.css(n,"boxSizing",!1,e)==="border-box";if(u<=0||u==null){if(u=rt(n,t,e),(u<0||u==null)&&(u=n.style[t]),ci.test(u))return u;o=s&&(f.boxSizingReliable()||u===n.style[t]);u=parseFloat(u)||0}return u+tu(n,t,r||(s?"border":"content"),o,e)+"px"}function ru(n,t){for(var e,u,s,o=[],f=0,h=n.length;f=0&&t=0},isPlainObject:function(n){return i.type(n)!=="object"||n.nodeType||i.isWindow(n)?!1:n.constructor&&!ri.call(n.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(n){for(var t in n)return!1;return!0},type:function(n){return n==null?n+"":typeof n=="object"||typeof n=="function"?ot[nf.call(n)]||"object":typeof n},globalEval:function(n){var t,r=eval;n=i.trim(n);n&&(n.indexOf("use strict")===1?(t=u.createElement("script"),t.text=n,u.head.appendChild(t).parentNode.removeChild(t)):r(n))},camelCase:function(n){return n.replace(rf,"ms-").replace(uf,ff)},nodeName:function(n,t){return n.nodeName&&n.nodeName.toLowerCase()===t.toLowerCase()},each:function(n,t,i){var u,r=0,f=n.length,e=ui(n);if(i){if(e){for(;rt.cacheLength&&delete n[i.shift()],n[r+" "]=u}var i=[];return n}function h(n){return n[f]=!0,n}function c(n){var t=e.createElement("div");try{return!!n(t)}catch(i){return!1}finally{t.parentNode&&t.parentNode.removeChild(t);t=null}}function ti(n,i){for(var u=n.split("|"),r=n.length;r--;)t.attrHandle[u[r]]=i}function wi(n,t){var i=t&&n,r=i&&n.nodeType===1&&t.nodeType===1&&(~t.sourceIndex||ai)-(~n.sourceIndex||ai);if(r)return r;if(i)while(i=i.nextSibling)if(i===t)return-1;return n?1:-1}function cr(n){return function(t){var i=t.nodeName.toLowerCase();return i==="input"&&t.type===n}}function lr(n){return function(t){var i=t.nodeName.toLowerCase();return(i==="input"||i==="button")&&t.type===n}}function tt(n){return h(function(t){return t=+t,h(function(i,r){for(var u,f=n([],i.length,t),e=f.length;e--;)i[u=f[e]]&&(i[u]=!(r[u]=i[u]))})})}function ii(n){return n&&typeof n.getElementsByTagName!==ut&&n}function bi(){}function yt(n){for(var t=0,r=n.length,i="";t1?function(t,i,r){for(var u=n.length;u--;)if(!n[u](t,i,r))return!1;return!0}:n[0]}function ar(n,t,i){for(var u=0,f=t.length;u-1&&(f[l]=!(e[l]=a))}}else h=pt(h===e?h.splice(w,h.length):h),u?u(null,e,h,s):b.apply(e,h)})}function ei(n){for(var s,u,r,o=n.length,h=t.relative[n[0].type],c=h||t.relative[" "],i=h?1:0,l=ri(function(n){return n===s},c,!0),a=ri(function(n){return nt.call(s,n)>-1},c,!0),e=[function(n,t,i){return!h&&(i||t!==ct)||((s=t).nodeType?l(n,t,i):a(n,t,i))}];i1&&ui(e),i>1&&yt(n.slice(0,i-1).concat({value:n[i-2].type===" "?"*":""})).replace(at,"$1"),u,i0,f=n.length>0,o=function(o,s,h,c,l){var y,d,w,k=0,a="0",g=o&&[],p=[],nt=ct,tt=o||f&&t.find.TAG("*",l),it=v+=nt==null?1:Math.random()||.1,rt=tt.length;for(l&&(ct=s!==e&&s);a!==rt&&(y=tt[a])!=null;a++){if(f&&y){for(d=0;w=n[d++];)if(w(y,s,h)){c.push(y);break}l&&(v=it)}u&&((y=!w&&y)&&k--,o&&g.push(y))}if(k+=a,u&&a!==k){for(d=0;w=i[d++];)w(g,p,s,h);if(o){if(k>0)while(a--)g[a]||p[a]||(p[a]=gi.call(c));p=pt(p)}b.apply(c,p);l&&!o&&p.length>0&&k+i.length>1&&r.uniqueSort(c)}return l&&(v=it,ct=nt),g};return u?h(o):o}var it,u,t,ht,oi,et,wt,si,ct,y,rt,p,e,l,a,o,g,lt,ot,f="sizzle"+-new Date,s=n.document,v=0,ki=0,hi=ni(),ci=ni(),li=ni(),bt=function(n,t){return n===t&&(rt=!0),0},ut=typeof undefined,ai=-2147483648,di={}.hasOwnProperty,w=[],gi=w.pop,nr=w.push,b=w.push,vi=w.slice,nt=w.indexOf||function(n){for(var t=0,i=this.length;t+~]|"+i+")"+i+"*"),rr=new RegExp("="+i+"*([^\\]'\"]*?)"+i+"*\\]","g"),ur=new RegExp(dt),fr=new RegExp("^"+yi+"$"),vt={ID:new RegExp("^#("+ft+")"),CLASS:new RegExp("^\\.("+ft+")"),TAG:new RegExp("^("+ft.replace("w","w*")+")"),ATTR:new RegExp("^"+pi),PSEUDO:new RegExp("^"+dt),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+i+"*(even|odd|(([+-]|)(\\d*)n|)"+i+"*(?:([+-]|)"+i+"*(\\d+)|))"+i+"*\\)|)","i"),bool:new RegExp("^(?:"+kt+")$","i"),needsContext:new RegExp("^"+i+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+i+"*((?:-\\d)?\\d*)"+i+"*\\)|)(?=[^-]|$)","i")},er=/^(?:input|select|textarea|button)$/i,or=/^h\d$/i,st=/^[^{]+\{\s*\[native \w/,sr=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,gt=/[+~]/,hr=/'|\\/g,k=new RegExp("\\\\([\\da-f]{1,6}"+i+"?|("+i+")|.)","ig"),d=function(n,t,i){var r="0x"+t-65536;return r!==r||i?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,r&1023|56320)};try{b.apply(w=vi.call(s.childNodes),s.childNodes);w[s.childNodes.length].nodeType}catch(yr){b={apply:w.length?function(n,t){nr.apply(n,vi.call(t))}:function(n,t){for(var i=n.length,r=0;n[i++]=t[r++];);n.length=i-1}}}u=r.support={};oi=r.isXML=function(n){var t=n&&(n.ownerDocument||n).documentElement;return t?t.nodeName!=="HTML":!1};p=r.setDocument=function(n){var v,r=n?n.ownerDocument||n:s,h=r.defaultView;return r===e||r.nodeType!==9||!r.documentElement?e:(e=r,l=r.documentElement,a=!oi(r),h&&h!==h.top&&(h.addEventListener?h.addEventListener("unload",function(){p()},!1):h.attachEvent&&h.attachEvent("onunload",function(){p()})),u.attributes=c(function(n){return n.className="i",!n.getAttribute("className")}),u.getElementsByTagName=c(function(n){return n.appendChild(r.createComment("")),!n.getElementsByTagName("*").length}),u.getElementsByClassName=st.test(r.getElementsByClassName)&&c(function(n){return n.innerHTML="
<\/div>
<\/div>",n.firstChild.className="i",n.getElementsByClassName("i").length===2}),u.getById=c(function(n){return l.appendChild(n).id=f,!r.getElementsByName||!r.getElementsByName(f).length}),u.getById?(t.find.ID=function(n,t){if(typeof t.getElementById!==ut&&a){var i=t.getElementById(n);return i&&i.parentNode?[i]:[]}},t.filter.ID=function(n){var t=n.replace(k,d);return function(n){return n.getAttribute("id")===t}}):(delete t.find.ID,t.filter.ID=function(n){var t=n.replace(k,d);return function(n){var i=typeof n.getAttributeNode!==ut&&n.getAttributeNode("id");return i&&i.value===t}}),t.find.TAG=u.getElementsByTagName?function(n,t){if(typeof t.getElementsByTagName!==ut)return t.getElementsByTagName(n)}:function(n,t){var i,r=[],f=0,u=t.getElementsByTagName(n);if(n==="*"){while(i=u[f++])i.nodeType===1&&r.push(i);return r}return u},t.find.CLASS=u.getElementsByClassName&&function(n,t){if(typeof t.getElementsByClassName!==ut&&a)return t.getElementsByClassName(n)},g=[],o=[],(u.qsa=st.test(r.querySelectorAll))&&(c(function(n){n.innerHTML="",n.firstChild.setAttribute("value",""),n.firstChild.getAttribute("value")===""})||ti("value",function(n,t,i){if(!i&&n.nodeName.toLowerCase()==="input")return n.defaultValue}),c(function(n){return n.getAttribute("disabled")==null})||ti(kt,function(n,t,i){var r;if(!i)return n[t]===!0?t.toLowerCase():(r=n.getAttributeNode(t))&&r.specified?r.value:null}),r}(n);i.find=y;i.expr=y.selectors;i.expr[":"]=i.expr.pseudos;i.unique=y.uniqueSort;i.text=y.getText;i.isXMLDoc=y.isXML;i.contains=y.contains;var di=i.expr.match.needsContext,gi=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,ef=/^.[^:#\[\.,]*$/;i.filter=function(n,t,r){var u=t[0];return r&&(n=":not("+n+")"),t.length===1&&u.nodeType===1?i.find.matchesSelector(u,n)?[u]:[]:i.find.matches(n,i.grep(t,function(n){return n.nodeType===1}))};i.fn.extend({find:function(n){var t,u=this.length,r=[],f=this;if(typeof n!="string")return this.pushStack(i(n).filter(function(){for(t=0;t1?i.unique(r):r),r.selector=this.selector?this.selector+" "+n:n,r},filter:function(n){return this.pushStack(fi(this,n||[],!1))},not:function(n){return this.pushStack(fi(this,n||[],!0))},is:function(n){return!!fi(this,typeof n=="string"&&di.test(n)?i(n):n||[],!1).length}});nr=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;tr=i.fn.init=function(n,t){var r,f;if(!n)return this;if(typeof n=="string"){if(r=n[0]==="<"&&n[n.length-1]===">"&&n.length>=3?[null,n,null]:nr.exec(n),r&&(r[1]||!t)){if(r[1]){if(t=t instanceof i?t[0]:t,i.merge(this,i.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:u,!0)),gi.test(r[1])&&i.isPlainObject(t))for(r in t)i.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return f=u.getElementById(r[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=u,this.selector=n,this}return!t||t.jquery?(t||st).find(n):this.constructor(t).find(n)}return n.nodeType?(this.context=this[0]=n,this.length=1,this):i.isFunction(n)?typeof st.ready!="undefined"?st.ready(n):n(i):(n.selector!==undefined&&(this.selector=n.selector,this.context=n.context),i.makeArray(n,this))};tr.prototype=i.fn;st=i(u);ir=/^(?:parents|prev(?:Until|All))/;rr={children:!0,contents:!0,next:!0,prev:!0};i.extend({dir:function(n,t,r){for(var u=[],f=r!==undefined;(n=n[t])&&n.nodeType!==9;)if(n.nodeType===1){if(f&&i(n).is(r))break;u.push(n)}return u},sibling:function(n,t){for(var i=[];n;n=n.nextSibling)n.nodeType===1&&n!==t&&i.push(n);return i}});i.fn.extend({has:function(n){var t=i(n,this),r=t.length;return this.filter(function(){for(var n=0;n-1:r.nodeType===1&&i.find.matchesSelector(r,n))){u.push(r);break}return this.pushStack(u.length>1?i.unique(u):u)},index:function(n){return n?typeof n=="string"?et.call(i(n),this[0]):et.call(this,n.jquery?n[0]:n):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(n,t){return this.pushStack(i.unique(i.merge(this.get(),i(n,t))))},addBack:function(n){return this.add(n==null?this.prevObject:this.prevObject.filter(n))}});i.each({parent:function(n){var t=n.parentNode;return t&&t.nodeType!==11?t:null},parents:function(n){return i.dir(n,"parentNode")},parentsUntil:function(n,t,r){return i.dir(n,"parentNode",r)},next:function(n){return ur(n,"nextSibling")},prev:function(n){return ur(n,"previousSibling")},nextAll:function(n){return i.dir(n,"nextSibling")},prevAll:function(n){return i.dir(n,"previousSibling")},nextUntil:function(n,t,r){return i.dir(n,"nextSibling",r)},prevUntil:function(n,t,r){return i.dir(n,"previousSibling",r)},siblings:function(n){return i.sibling((n.parentNode||{}).firstChild,n)},children:function(n){return i.sibling(n.firstChild)},contents:function(n){return n.contentDocument||i.merge([],n.childNodes)}},function(n,t){i.fn[n]=function(r,u){var f=i.map(this,t,r);return n.slice(-5)!=="Until"&&(u=r),u&&typeof u=="string"&&(f=i.filter(u,f)),this.length>1&&(rr[n]||i.unique(f),ir.test(n)&&f.reverse()),this.pushStack(f)}});c=/\S+/g;ei={};i.Callbacks=function(n){n=typeof n=="string"?ei[n]||of(n):i.extend({},n);var u,h,o,c,f,e,t=[],r=!n.once&&[],l=function(i){for(u=n.memory&&i,h=!0,e=c||0,c=0,f=t.length,o=!0;t&&e-1;)t.splice(u,1),o&&(u<=f&&f--,u<=e&&e--)}),this},has:function(n){return n?i.inArray(n,t)>-1:!!(t&&t.length)},empty:function(){return t=[],f=0,this},disable:function(){return t=r=u=undefined,this},disabled:function(){return!t},lock:function(){return r=undefined,u||s.disable(),this},locked:function(){return!r},fireWith:function(n,i){return t&&(!h||r)&&(i=i||[],i=[n,i.slice?i.slice():i],o?r.push(i):l(i)),this},fire:function(){return s.fireWith(this,arguments),this},fired:function(){return!!h}};return s};i.extend({Deferred:function(n){var u=[["resolve","done",i.Callbacks("once memory"),"resolved"],["reject","fail",i.Callbacks("once memory"),"rejected"],["notify","progress",i.Callbacks("memory")]],f="pending",r={state:function(){return f},always:function(){return t.done(arguments).fail(arguments),this},then:function(){var n=arguments;return i.Deferred(function(f){i.each(u,function(u,e){var o=i.isFunction(n[u])&&n[u];t[e[1]](function(){var n=o&&o.apply(this,arguments);n&&i.isFunction(n.promise)?n.promise().done(f.resolve).fail(f.reject).progress(f.notify):f[e[0]+"With"](this===r?f.promise():this,o?[n]:arguments)})});n=null}).promise()},promise:function(n){return n!=null?i.extend(n,r):r}},t={};return r.pipe=r.then,i.each(u,function(n,i){var e=i[2],o=i[3];r[i[1]]=e.add;o&&e.add(function(){f=o},u[n^1][2].disable,u[2][2].lock);t[i[0]]=function(){return t[i[0]+"With"](this===t?r:this,arguments),this};t[i[0]+"With"]=e.fireWith}),r.promise(t),n&&n.call(t,t),t},when:function(n){var t=0,u=a.call(arguments),r=u.length,e=r!==1||n&&i.isFunction(n.promise)?r:0,f=e===1?n:i.Deferred(),h=function(n,t,i){return function(r){t[n]=this;i[n]=arguments.length>1?a.call(arguments):r;i===o?f.notifyWith(t,i):--e||f.resolveWith(t,i)}},o,c,s;if(r>1)for(o=new Array(r),c=new Array(r),s=new Array(r);t0)||(ht.resolveWith(u,[i]),i.fn.triggerHandler&&(i(u).triggerHandler("ready"),i(u).off("ready")))}});i.ready.promise=function(t){return ht||(ht=i.Deferred(),u.readyState==="complete"?setTimeout(i.ready):(u.addEventListener("DOMContentLoaded",ct,!1),n.addEventListener("load",ct,!1))),ht.promise(t)};i.ready.promise();l=i.access=function(n,t,r,u,f,e,o){var s=0,c=n.length,h=r==null;if(i.type(r)==="object"){f=!0;for(s in r)i.access(n,t,s,r[s],!0,e,o)}else if(u!==undefined&&(f=!0,i.isFunction(u)||(o=!0),h&&(o?(t.call(n,u),t=null):(h=t,t=function(n,t,r){return h.call(i(n),r)})),t))for(;s1,null,!0)},removeData:function(n){return this.each(function(){e.remove(this,n)})}});i.extend({queue:function(n,t,u){var f;if(n)return t=(t||"fx")+"queue",f=r.get(n,t),u&&(!f||i.isArray(u)?f=r.access(n,t,i.makeArray(u)):f.push(u)),f||[]},dequeue:function(n,t){t=t||"fx";var r=i.queue(n,t),e=r.length,u=r.shift(),f=i._queueHooks(n,t),o=function(){i.dequeue(n,t)};u==="inprogress"&&(u=r.shift(),e--);u&&(t==="fx"&&r.unshift("inprogress"),delete f.stop,u.call(n,o,f));!e&&f&&f.empty.fire()},_queueHooks:function(n,t){var u=t+"queueHooks";return r.get(n,u)||r.access(n,u,{empty:i.Callbacks("once memory").add(function(){r.remove(n,[t+"queue",u])})})}});i.fn.extend({queue:function(n,t){var r=2;return(typeof n!="string"&&(t=n,n="fx",r--),arguments.lengthx<\/textarea>";f.noCloneChecked=!!n.cloneNode(!0).lastChild.defaultValue})();d=typeof undefined;f.focusinBubbles="onfocusin"in n;var cf=/^key/,lf=/^(?:mouse|pointer|contextmenu)|click/,or=/^(?:focusinfocus|focusoutblur)$/,sr=/^([^.]*)(?:\.(.+)|)$/;i.event={global:{},add:function(n,t,u,f,e){var v,y,w,p,b,h,s,l,o,k,g,a=r.get(n);if(a)for(u.handler&&(v=u,u=v.handler,e=v.selector),u.guid||(u.guid=i.guid++),(p=a.events)||(p=a.events={}),(y=a.handle)||(y=a.handle=function(t){return typeof i!==d&&i.event.triggered!==t.type?i.event.dispatch.apply(n,arguments):undefined}),t=(t||"").match(c)||[""],b=t.length;b--;)(w=sr.exec(t[b])||[],o=g=w[1],k=(w[2]||"").split(".").sort(),o)&&(s=i.event.special[o]||{},o=(e?s.delegateType:s.bindType)||o,s=i.event.special[o]||{},h=i.extend({type:o,origType:g,data:f,handler:u,guid:u.guid,selector:e,needsContext:e&&i.expr.match.needsContext.test(e),namespace:k.join(".")},v),(l=p[o])||(l=p[o]=[],l.delegateCount=0,s.setup&&s.setup.call(n,f,k,y)!==!1||n.addEventListener&&n.addEventListener(o,y,!1)),s.add&&(s.add.call(n,h),h.handler.guid||(h.handler.guid=u.guid)),e?l.splice(l.delegateCount++,0,h):l.push(h),i.event.global[o]=!0)},remove:function(n,t,u,f,e){var p,k,h,v,w,s,l,a,o,b,d,y=r.hasData(n)&&r.get(n);if(y&&(v=y.events)){for(t=(t||"").match(c)||[""],w=t.length;w--;){if(h=sr.exec(t[w])||[],o=d=h[1],b=(h[2]||"").split(".").sort(),!o){for(o in v)i.event.remove(n,o+t[w],u,f,!0);continue}for(l=i.event.special[o]||{},o=(f?l.delegateType:l.bindType)||o,a=v[o]||[],h=h[2]&&new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"),k=p=a.length;p--;)s=a[p],(e||d===s.origType)&&(!u||u.guid===s.guid)&&(!h||h.test(s.namespace))&&(!f||f===s.selector||f==="**"&&s.selector)&&(a.splice(p,1),s.selector&&a.delegateCount--,l.remove&&l.remove.call(n,s));k&&!a.length&&(l.teardown&&l.teardown.call(n,b,y.handle)!==!1||i.removeEvent(n,o,y.handle),delete v[o])}i.isEmptyObject(v)&&(delete y.handle,r.remove(n,"events"))}},trigger:function(t,f,e,o){var w,s,c,b,a,v,l,p=[e||u],h=ri.call(t,"type")?t.type:t,y=ri.call(t,"namespace")?t.namespace.split("."):[];if((s=c=e=e||u,e.nodeType!==3&&e.nodeType!==8)&&!or.test(h+i.event.triggered)&&(h.indexOf(".")>=0&&(y=h.split("."),h=y.shift(),y.sort()),a=h.indexOf(":")<0&&"on"+h,t=t[i.expando]?t:new i.Event(h,typeof t=="object"&&t),t.isTrigger=o?2:3,t.namespace=y.join("."),t.namespace_re=t.namespace?new RegExp("(^|\\.)"+y.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=e),f=f==null?[t]:i.makeArray(f,[t]),l=i.event.special[h]||{},o||!l.trigger||l.trigger.apply(e,f)!==!1)){if(!o&&!l.noBubble&&!i.isWindow(e)){for(b=l.delegateType||h,or.test(b+h)||(s=s.parentNode);s;s=s.parentNode)p.push(s),c=s;c===(e.ownerDocument||u)&&p.push(c.defaultView||c.parentWindow||n)}for(w=0;(s=p[w++])&&!t.isPropagationStopped();)t.type=w>1?b:l.bindType||h,v=(r.get(s,"events")||{})[t.type]&&r.get(s,"handle"),v&&v.apply(s,f),v=a&&s[a],v&&v.apply&&i.acceptData(s)&&(t.result=v.apply(s,f),t.result===!1&&t.preventDefault());return t.type=h,o||t.isDefaultPrevented()||(!l._default||l._default.apply(p.pop(),f)===!1)&&i.acceptData(e)&&a&&i.isFunction(e[h])&&!i.isWindow(e)&&(c=e[a],c&&(e[a]=null),i.event.triggered=h,e[h](),i.event.triggered=undefined,c&&(e[a]=c)),t.result}},dispatch:function(n){n=i.event.fix(n);var o,s,e,u,t,h=[],c=a.call(arguments),l=(r.get(this,"events")||{})[n.type]||[],f=i.event.special[n.type]||{};if(c[0]=n,n.delegateTarget=this,!f.preDispatch||f.preDispatch.call(this,n)!==!1){for(h=i.event.handlers.call(this,n,l),o=0;(u=h[o++])&&!n.isPropagationStopped();)for(n.currentTarget=u.elem,s=0;(t=u.handlers[s++])&&!n.isImmediatePropagationStopped();)(!n.namespace_re||n.namespace_re.test(t.namespace))&&(n.handleObj=t,n.data=t.data,e=((i.event.special[t.origType]||{}).handle||t.handler).apply(u.elem,c),e!==undefined&&(n.result=e)===!1&&(n.preventDefault(),n.stopPropagation()));return f.postDispatch&&f.postDispatch.call(this,n),n.result}},handlers:function(n,t){var e,u,f,o,h=[],s=t.delegateCount,r=n.target;if(s&&r.nodeType&&(!n.button||n.type!=="click"))for(;r!==this;r=r.parentNode||this)if(r.disabled!==!0||n.type!=="click"){for(u=[],e=0;e=0:i.find(f,this,null,[r]).length),u[f]&&u.push(o);u.length&&h.push({elem:r,handlers:u})}return s]*)\/>/gi,lr=/<([\w:]+)/,af=/<|&#?\w+;/,vf=/<(?:script|style|link)/i,yf=/checked\s*(?:[^=]|=\s*.checked.)/i,ar=/^$|\/(?:java|ecma)script/i,pf=/^true\/(.*)/,wf=/^\s*\s*$/g,h={option:[1,"");o._uploadFilesInput.attr({type:"file",multiple:"multiple",title:"Disco File Uploading"}).hide().change(function(n){var t=n.target.files;!!t&&t.length>0&&o._uploadFiles(t);o._uploadFilesInput.remove()}).appendTo(o.uploadProgressContainer).click()},!!o.dropTarget){var c=i(t),s=!1,h=null;c.on("dragover",function(){o.dropTarget.addClass("dragHighlight");o.dropTarget.removeClass("dragHover");s=!1});c.on("dragleave",function(){!h||n.clearInterval(h);s=!0;n.setTimeout(function(){s&&o.dropTarget.removeClass("dragHighlight");h=null},200)});o.dropTarget.on("dragover",function(n){n.stopPropagation();n.preventDefault();o.dropTarget.addClass("dragHover");s=!1;n.originalEvent.dataTransfer.dropEffect="copy"});o.dropTarget.on("drop",function(n){n.stopPropagation();n.preventDefault();s=!0;o.dropTarget.removeClass("dragHighlight");var t=n.originalEvent.dataTransfer.files;o._uploadFiles(t)})}return o.uploadImage=function(){function s(){var n=r.snap();o._uploadImage(n)}var u=720,f=540,t=i("
").attr({id:"Disco_AttachmentUpload_ImageDialog",title:"Upload Image","class":"dialog Disco-AttachmentUpload-ImageDialog"}),e;t.dialog({autoOpen:!0,draggable:!1,modal:!0,resizable:!1,width:u,height:f,close:function(){r.reset();n.setTimeout(function(){t.dialog("destroy")},1)}}).closest(".ui-dialog").children(".ui-dialog-titlebar").css("border-bottom","none");e=[{text:"Capture",click:s}];r.set({width:u,height:f,dest_width:u*1.5,dest_height:f*1.5,jpeg_quality:95});r.setSWFLocation("/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf");r.on("error",function(n){alert(n);t.dialog("close")});r.on("live",function(){t.dialog("option","buttons",e);t.closest(".ui-dialog").children(".ui-dialog-buttonpane").css("margin-top",0).find(".ui-button:first").focus()});r.attach(t.attr("id"))},o.getFileComments=function(t,r,u){var o=!1,f=i("
").attr({title:"Upload File","class":"dialog Disco-AttachmentUpload-CommentDialog"}),s,h,e;f.html('
File Name:<\/th><\/td><\/tr>
Comments:<\/th><\/input><\/td><\/tr>
<\/td><\/tr><\/table>');!r||(s=f.find("td.thumbnail"),h=s.find("img"),r(h)&&s.show());f.find("td.filename").text(t).attr("title",t);e=f.find("input.comments").keypress(function(n){n.which===13&&(!e.val()||(o=!0,f.dialog("close")))});f.dialog({resizable:!1,width:400,modal:!0,autoOpen:!0,buttons:{Upload:function(){e.val()?(o=!0,f.dialog("close"),n.setTimeout(function(){e.focus()},1)):alert("Please provide a comment for this attachment.")},Cancel:function(){f.dialog("close")}},close:function(){var n=e.val();f.dialog("destroy").remove();u(o,n)}})},o._uploadImage=function(n){o._hideFlashVideoOverlay()&&i("#webcam_movie_obj, #webcam_movie_embed").css("display","none");var u=n.replace(/^data\:image\/\w+\;base64\,/,""),f=new Blob([r.base64DecToArr(u)],{type:"image/jpeg"}),t="CapturedImage-"+moment().format("YYYYMMDD-HHmmss")+".jpg";o.getFileComments(t,function(t){return t.attr("src",n),!0},function(n,r){(o._hideFlashVideoOverlay()&&i("#webcam_movie_obj, #webcam_movie_embed").css("display",""),n)&&o._uploadFile(f,t,r)})},o._uploadFiles=function(n){var t=i.makeArray(n),r=function(){if(t&&t.length!==0){var n=t.shift();o.getFileComments(n.name,function(t){if(!!n.type&&n.type.indexOf("image/")===0){var i=new FileReader;return i.onload=function(n){t.attr("src",n.target.result)},i.readAsDataURL(n),!0}return!1},function(t,i){t&&(o._uploadFile(n,n.name,i),r())})}};r()},o._uploadFile=function(n,t,r){var f=new FormData,u=new XMLHttpRequest,e=i("
").append(i("").addClass("fa fa-cog fa-spin")).append(i("").text("Uploading: "+t)).appendTo(o.uploadProgressContainer);f.append("Comments",r);f.append("File",n,t);u.open("POST",o.uploadUrl,!0);u.onreadystatechange=function(){u.readyState===4&&(u.status!==200&&alert("Error Uploading ["+t+"]: "+u.statusText),e.slideUp(400,function(){e.remove()}))};u.send(f)},o.__hideFlashVideoOverlay=null,o._hideFlashVideoOverlay=function(){if(o.__hideFlashVideoOverlay===null){o.__hideFlashVideoOverlay=!1;try{var n=/(windows nt) ([\w.]+)/.exec(navigator.userAgent.toLowerCase());!!n&&parseFloat(n[2])<=6.2&&(o.__hideFlashVideoOverlay=!0)}catch(t){}}return o.__hideFlashVideoOverlay},o};t.Disco||(t.Disco={});t.Disco.AttachmentUploader=u}(this,document,$,Webcam); \ No newline at end of file +(function(t){function i(){var n=Error.apply(this,arguments);n.name=this.name="FlashError";this.stack=n.stack;this.message=n.message}function r(){var n=Error.apply(this,arguments);n.name=this.name="WebcamError";this.stack=n.stack;this.message=n.message}var f,e=function(){},u;e.prototype=Error.prototype;i.prototype=new e;r.prototype=new e;u={version:"1.0.26",protocol:location.protocol.match(/https/i)?"https":"http",loaded:!1,live:!1,userMedia:!0,iOS:/iPad|iPhone|iPod/.test(navigator.userAgent)&&!t.MSStream,params:{width:0,height:0,dest_width:0,dest_height:0,image_format:"jpeg",jpeg_quality:90,enable_flash:!0,force_flash:!1,flip_horiz:!1,fps:30,upload_name:"webcam",constraints:null,swfURL:"",flashNotDetectedText:"ERROR: No Adobe Flash Player detected. Webcam.js relies on Flash for browsers that do not support getUserMedia (like yours).",noInterfaceFoundText:"No supported webcam interface found.",unfreeze_snap:!0,iosPlaceholderText:"Click here to open camera.",user_callback:null,user_canvas:null},errors:{FlashError:i,WebcamError:r},hooks:{},init:function(){var n=this;this.mediaDevices=navigator.mediaDevices&&navigator.mediaDevices.getUserMedia?navigator.mediaDevices:navigator.mozGetUserMedia||navigator.webkitGetUserMedia?{getUserMedia:function(n){return new Promise(function(t,i){(navigator.mozGetUserMedia||navigator.webkitGetUserMedia).call(navigator,n,t,i)})}}:null;t.URL=t.URL||t.webkitURL||t.mozURL||t.msURL;this.userMedia=this.userMedia&&!!this.mediaDevices&&!!t.URL;navigator.userAgent.match(/Firefox\D+(\d+)/)&&parseInt(RegExp.$1,10)<21&&(this.userMedia=null);this.userMedia&&t.addEventListener("beforeunload",function(){n.reset()})},exifOrientation:function(t){var i=new DataView(t),r,s,h,u,c,l,y,o,f,a,v,e;if(i.getUint8(0)!=255||i.getUint8(1)!=216)return console.log("Not a valid JPEG file"),0;for(r=2,s=null;r8)?(console.log("Invalid EXIF orientation value ("+e+")"),0):e}else r+=2+i.getUint16(r+2)}return 0},fixOrientation:function(n,t,i){var r=new Image;r.addEventListener("load",function(){var u=document.createElement("canvas"),n=u.getContext("2d");t<5?(u.width=r.width,u.height=r.height):(u.width=r.height,u.height=r.width);switch(t){case 2:n.transform(-1,0,0,1,r.width,0);break;case 3:n.transform(-1,0,0,-1,r.width,r.height);break;case 4:n.transform(1,0,0,-1,0,r.height);break;case 5:n.transform(0,1,1,0,0,0);break;case 6:n.transform(0,1,-1,0,r.height,0);break;case 7:n.transform(0,-1,-1,0,r.height,r.width);break;case 8:n.transform(0,-1,1,0,0,r.width)}n.drawImage(r,0,0);i.src=u.toDataURL()},!1);r.src=n},attach:function(n){var y,c,l,i,v,a,s,o,h,e,p,w;if(typeof n=="string"&&(n=document.getElementById(n)||document.querySelector(n)),!n)return this.dispatch("error",new r("Could not locate DOM element to attach to."));if(this.container=n,n.innerHTML="",y=document.createElement("div"),n.appendChild(y),this.peg=y,this.params.width||(this.params.width=n.offsetWidth),this.params.height||(this.params.height=n.offsetHeight),!this.params.width||!this.params.height)return this.dispatch("error",new r("No width and/or height for webcam. Please call set() first, or attach to a visible element."));this.params.dest_width||(this.params.dest_width=this.params.width);this.params.dest_height||(this.params.dest_height=this.params.height);this.userMedia=f===undefined?this.userMedia:f;this.params.force_flash&&(f=this.userMedia,this.userMedia=null);typeof this.params.fps!="number"&&(this.params.fps=30);c=this.params.width/this.params.dest_width;l=this.params.height/this.params.dest_height;this.userMedia?(i=document.createElement("video"),i.setAttribute("autoplay","autoplay"),i.setAttribute("playsinline","playsinline"),i.style.width=""+this.params.dest_width+"px",i.style.height=""+this.params.dest_height+"px",(c!=1||l!=1)&&(n.style.overflow="hidden",i.style.webkitTransformOrigin="0px 0px",i.style.mozTransformOrigin="0px 0px",i.style.msTransformOrigin="0px 0px",i.style.oTransformOrigin="0px 0px",i.style.transformOrigin="0px 0px",i.style.webkitTransform="scaleX("+c+") scaleY("+l+")",i.style.mozTransform="scaleX("+c+") scaleY("+l+")",i.style.msTransform="scaleX("+c+") scaleY("+l+")",i.style.oTransform="scaleX("+c+") scaleY("+l+")",i.style.transform="scaleX("+c+") scaleY("+l+")"),n.appendChild(i),this.video=i,o=this,this.mediaDevices.getUserMedia({audio:!1,video:this.params.constraints||{mandatory:{minWidth:this.params.dest_width,minHeight:this.params.dest_height}}}).then(function(n){i.onloadedmetadata=function(){o.stream=n;o.loaded=!0;o.live=!0;o.dispatch("load");o.dispatch("live");o.flip()};"srcObject"in i?i.srcObject=n:i.src=t.URL.createObjectURL(n)}).catch(function(t){o.params.enable_flash&&o.detectFlash()?setTimeout(function(){o.params.force_flash=1;o.attach(n)},1):o.dispatch("error",t)})):this.iOS?(e=document.createElement("div"),e.id=this.container.id+"-ios_div",e.className="webcamjs-ios-placeholder",e.style.width=""+this.params.width+"px",e.style.height=""+this.params.height+"px",e.style.textAlign="center",e.style.display="table-cell",e.style.verticalAlign="middle",e.style.backgroundRepeat="no-repeat",e.style.backgroundSize="contain",e.style.backgroundPosition="center",v=document.createElement("span"),v.className="webcamjs-ios-text",v.innerHTML=this.params.iosPlaceholderText,e.appendChild(v),a=document.createElement("img"),a.id=this.container.id+"-ios_img",a.style.width=""+this.params.dest_width+"px",a.style.height=""+this.params.dest_height+"px",a.style.display="none",e.appendChild(a),s=document.createElement("input"),s.id=this.container.id+"-ios_input",s.setAttribute("type","file"),s.setAttribute("accept","image/*"),s.setAttribute("capture","camera"),o=this,h=this.params,s.addEventListener("change",function(n){var r,t,u,i;n.target.files.length>0&&n.target.files[0].type.indexOf("image/")==0&&(r=URL.createObjectURL(n.target.files[0]),t=new Image,t.addEventListener("load",function(){var n=document.createElement("canvas"),r,i;n.width=h.dest_width;n.height=h.dest_height;r=n.getContext("2d");ratio=Math.min(t.width/h.dest_width,t.height/h.dest_height);var u=h.dest_width*ratio,f=h.dest_height*ratio,o=(t.width-u)/2,s=(t.height-f)/2;r.drawImage(t,o,s,u,f,0,0,h.dest_width,h.dest_height);i=n.toDataURL();a.src=i;e.style.backgroundImage="url('"+i+"')"},!1),u=new FileReader,u.addEventListener("load",function(n){var i=o.exifOrientation(n.target.result);i>1?o.fixOrientation(r,i,t):t.src=r},!1),i=new XMLHttpRequest,i.open("GET",r,!0),i.responseType="blob",i.onload=function(){(this.status==200||this.status===0)&&u.readAsArrayBuffer(this.response)},i.send())},!1),s.style.display="none",n.appendChild(s),e.addEventListener("click",function(){h.user_callback?o.snap(h.user_callback,h.user_canvas):(s.style.display="block",s.focus(),s.click(),s.style.display="none")},!1),n.appendChild(e),this.loaded=!0,this.live=!0):this.params.enable_flash&&this.detectFlash()?(t.Webcam=u,e=document.createElement("div"),e.innerHTML=this.getSWFHTML(),n.appendChild(e)):this.dispatch("error",new r(this.params.noInterfaceFoundText));this.params.crop_width&&this.params.crop_height?(p=Math.floor(this.params.crop_width*c),w=Math.floor(this.params.crop_height*l),n.style.width=""+p+"px",n.style.height=""+w+"px",n.style.overflow="hidden",n.scrollLeft=Math.floor(this.params.width/2-p/2),n.scrollTop=Math.floor(this.params.height/2-w/2)):(n.style.width=""+this.params.width+"px",n.style.height=""+this.params.height+"px")},reset:function(){var n,t;this.preview_active&&this.unfreeze();this.unflip();this.userMedia&&(this.stream&&(this.stream.getVideoTracks?(n=this.stream.getVideoTracks(),n&&n[0]&&n[0].stop&&n[0].stop()):this.stream.stop&&this.stream.stop()),delete this.stream,delete this.video);this.userMedia!==!0&&this.loaded&&!this.iOS&&(t=this.getMovie(),t&&t._releaseCamera&&t._releaseCamera());this.container&&(this.container.innerHTML="",delete this.container);this.loaded=!1;this.live=!1},set:function(){if(arguments.length==1)for(var n in arguments[0])this.params[n]=arguments[0][n];else this.params[arguments[0]]=arguments[1]},on:function(n,t){n=n.replace(/^on/i,"").toLowerCase();this.hooks[n]||(this.hooks[n]=[]);this.hooks[n].push(t)},off:function(n,t){if(n=n.replace(/^on/i,"").toLowerCase(),this.hooks[n])if(t){var i=this.hooks[n].indexOf(t);i>-1&&this.hooks[n].splice(i,1)}else this.hooks[n]=[]},dispatch:function(){var f=arguments[0].replace(/^on/i,"").toLowerCase(),u=Array.prototype.slice.call(arguments,1),e,o,n,s;if(this.hooks[f]&&this.hooks[f].length){for(e=0,o=this.hooks[f].length;eERROR: the Webcam.js Flash fallback does not work from local disk. Please run it from a web server.<\/h3>';if(!this.detectFlash())return this.dispatch("error",new i("Adobe Flash Player not found. Please install from get.adobe.com/flashplayer and try again.")),'

'+this.params.flashNotDetectedText+"<\/h3>";if(!u){for(f="",o=document.getElementsByTagName("script"),r=0,s=o.length;r<\/embed><\/object>')},getMovie:function(){if(!this.loaded)return this.dispatch("error",new i("Flash Movie is not loaded yet"));var n=document.getElementById("webcam_movie_obj");return n&&n._snap||(n=document.getElementById("webcam_movie_embed")),n||this.dispatch("error",new i("Cannot locate Flash movie in DOM")),n},freeze:function(){var r=this,u=this.params,t,i,f;this.preview_active&&this.unfreeze();t=this.params.width/this.params.dest_width;i=this.params.height/this.params.dest_height;this.unflip();var e=u.crop_width||u.dest_width,o=u.crop_height||u.dest_height,n=document.createElement("canvas");n.width=e;n.height=o;f=n.getContext("2d");this.preview_canvas=n;this.preview_context=f;(t!=1||i!=1)&&(n.style.webkitTransformOrigin="0px 0px",n.style.mozTransformOrigin="0px 0px",n.style.msTransformOrigin="0px 0px",n.style.oTransformOrigin="0px 0px",n.style.transformOrigin="0px 0px",n.style.webkitTransform="scaleX("+t+") scaleY("+i+")",n.style.mozTransform="scaleX("+t+") scaleY("+i+")",n.style.msTransform="scaleX("+t+") scaleY("+i+")",n.style.oTransform="scaleX("+t+") scaleY("+i+")",n.style.transform="scaleX("+t+") scaleY("+i+")");this.snap(function(){n.style.position="relative";n.style.left=""+r.container.scrollLeft+"px";n.style.top=""+r.container.scrollTop+"px";r.container.insertBefore(n,r.peg);r.container.style.overflow="hidden";r.preview_active=!0},n)},unfreeze:function(){this.preview_active&&(this.container.removeChild(this.preview_canvas),delete this.preview_context,delete this.preview_canvas,this.preview_active=!1,this.flip())},flip:function(){if(this.params.flip_horiz){var n=this.container.style;n.webkitTransform="scaleX(-1)";n.mozTransform="scaleX(-1)";n.msTransform="scaleX(-1)";n.oTransform="scaleX(-1)";n.transform="scaleX(-1)";n.filter="FlipH";n.msFilter="FlipH"}},unflip:function(){if(this.params.flip_horiz){var n=this.container.style;n.webkitTransform="scaleX(1)";n.mozTransform="scaleX(1)";n.msTransform="scaleX(1)";n.oTransform="scaleX(1)";n.transform="scaleX(1)";n.filter="";n.msFilter=""}},savePreview:function(n,t){var r=this.params,i=this.preview_canvas,f=this.preview_context,u;t&&(u=t.getContext("2d"),u.drawImage(i,0,0));n(t?null:i.toDataURL("image/"+r.image_format,r.jpeg_quality/100),i,f);this.params.unfreeze_snap&&this.unfreeze()},snap:function(n,t){var c,i,u,f,s,h,e;if(n||(n=this.params.user_callback),t||(t=this.params.user_canvas),c=this,i=this.params,!this.loaded)return this.dispatch("error",new r("Webcam is not loaded yet"));if(!n)return this.dispatch("error",new r("Please provide a callback function or canvas to snap()"));if(this.preview_active)return this.savePreview(n,t),null;if(u=document.createElement("canvas"),u.width=this.params.dest_width,u.height=this.params.dest_height,f=u.getContext("2d"),this.params.flip_horiz&&(f.translate(i.dest_width,0),f.scale(-1,1)),s=function(){var r,e,o;this.src&&this.width&&this.height&&f.drawImage(this,0,0,i.dest_width,i.dest_height);i.crop_width&&i.crop_height&&(r=document.createElement("canvas"),r.width=i.crop_width,r.height=i.crop_height,e=r.getContext("2d"),e.drawImage(u,Math.floor(i.dest_width/2-i.crop_width/2),Math.floor(i.dest_height/2-i.crop_height/2),i.crop_width,i.crop_height,0,0,i.crop_width,i.crop_height),f=e,u=r);t&&(o=t.getContext("2d"),o.drawImage(u,0,0));n(t?null:u.toDataURL("image/"+i.image_format,i.jpeg_quality/100),u,f)},this.userMedia)f.drawImage(this.video,0,0,this.params.dest_width,this.params.dest_height),s();else if(this.iOS){var l=document.getElementById(this.container.id+"-ios_div"),e=document.getElementById(this.container.id+"-ios_img"),o=document.getElementById(this.container.id+"-ios_input");iFunc=function(){s.call(e);e.removeEventListener("load",iFunc);l.style.backgroundImage="none";e.removeAttribute("src");o.value=null};o.value?iFunc(null):(e.addEventListener("load",iFunc),o.style.display="block",o.focus(),o.click(),o.style.display="none")}else h=this.getMovie()._snap(),e=new Image,e.onload=s,e.src="data:image/"+this.params.image_format+";base64,"+h;return null},configure:function(n){n||(n="camera");this.getMovie()._configure(n)},flashNotify:function(n,t){switch(n){case"flashLoadComplete":this.loaded=!0;this.dispatch("load");break;case"cameraLive":this.live=!0;this.dispatch("live");break;case"error":this.dispatch("error",new i(t))}},b64ToUint6:function(n){return n>64&&n<91?n-65:n>96&&n<123?n-71:n>47&&n<58?n+4:n===43?62:n===47?63:0},base64DecToArr:function(n,t){for(var s=n.replace(/[^A-Za-z0-9\+\/]/g,""),r=s.length,h=t?Math.ceil((r*3+1>>2)/t)*t:r*3+1>>2,c=new Uint8Array(h),u,f,e=0,o=0,i=0;i>>(16>>>u&24)&255;e=0}return c},upload:function(n,t,i){var o=this.params.upload_name||"webcam",f="",s,r,h,c,e;if(n.match(/^data\:image\/(\w+)/))f=RegExp.$1;else throw"Cannot locate image format in Data URI";s=n.replace(/^data\:image\/\w+\;base64\,/,"");r=new XMLHttpRequest;r.open("POST",t,!0);r.upload&&r.upload.addEventListener&&r.upload.addEventListener("progress",function(n){if(n.lengthComputable){var t=n.loaded/n.total;u.dispatch("uploadProgress",t,n)}},!1);h=this;r.onload=function(){i&&i.apply(h,[r.status,r.responseText,r.statusText]);u.dispatch("uploadComplete",r.status,r.responseText,r.statusText)};c=new Blob([this.base64DecToArr(s)],{type:"image/"+f});e=new FormData;e.append(o,c,o+"."+f.replace(/e/,""));r.send(e)}};u.init();typeof define=="function"&&define.amd?define(function(){return u}):typeof module=="object"&&module.exports?module.exports=u:t.Webcam=u})(window),function(n,t,i,r){"use strict";var u=function(u,f,e){var o=this;if(o.uploadUrl=u,o.dropTarget=f,o.uploadProgressContainer=e,o._uploadFilesInput=null,o.uploadFiles=function(){!o._uploadFilesInput||o._uploadFilesInput.remove();o._uploadFilesInput=i("");o._uploadFilesInput.attr({type:"file",multiple:"multiple",title:"Disco File Uploading"}).hide().change(function(n){var t=n.target.files;!!t&&t.length>0&&o._uploadFiles(t);o._uploadFilesInput.remove()}).appendTo(o.uploadProgressContainer).click()},!!o.dropTarget){var c=i(t),s=!1,h=null;c.on("dragover",function(){o.dropTarget.addClass("dragHighlight");o.dropTarget.removeClass("dragHover");s=!1});c.on("dragleave",function(){!h||n.clearInterval(h);s=!0;n.setTimeout(function(){s&&o.dropTarget.removeClass("dragHighlight");h=null},200)});o.dropTarget.on("dragover",function(n){n.stopPropagation();n.preventDefault();o.dropTarget.addClass("dragHover");s=!1;n.originalEvent.dataTransfer.dropEffect="copy"});o.dropTarget.on("drop",function(n){n.stopPropagation();n.preventDefault();s=!0;o.dropTarget.removeClass("dragHighlight");var t=n.originalEvent.dataTransfer.files;o._uploadFiles(t)})}return o.uploadImage=function(){function s(){var n=r.snap();o._uploadImage(n)}var u=720,f=540,t=i("
").attr({id:"Disco_AttachmentUpload_ImageDialog",title:"Upload Image","class":"dialog Disco-AttachmentUpload-ImageDialog"}),e;t.dialog({autoOpen:!0,draggable:!1,modal:!0,resizable:!1,width:u,height:f,close:function(){r.reset();n.setTimeout(function(){t.dialog("destroy")},1)}}).closest(".ui-dialog").children(".ui-dialog-titlebar").css("border-bottom","none");e=[{text:"Capture",click:s}];r.set({width:u,height:f,dest_width:u*1.5,dest_height:f*1.5,jpeg_quality:95});r.setSWFLocation("/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf");r.on("error",function(n){alert(n);t.dialog("close")});r.on("live",function(){t.dialog("option","buttons",e);t.closest(".ui-dialog").children(".ui-dialog-buttonpane").css("margin-top",0).find(".ui-button:first").focus()});r.attach(t.attr("id"))},o.getFileComments=function(t,r,u){var o=!1,f=i("
").attr({title:"Upload File","class":"dialog Disco-AttachmentUpload-CommentDialog"}),s,h,e;f.html('
File Name:<\/th><\/td><\/tr>
Comments:<\/th><\/input><\/td><\/tr>
<\/td><\/tr><\/table>');!r||(s=f.find("td.thumbnail"),h=s.find("img"),r(h)&&s.show());f.find("td.filename").text(t).attr("title",t);e=f.find("input.comments").keypress(function(n){n.which===13&&(!e.val()||(o=!0,f.dialog("close")))});f.dialog({resizable:!1,width:400,modal:!0,autoOpen:!0,buttons:{Upload:function(){e.val()?(o=!0,f.dialog("close"),n.setTimeout(function(){e.focus()},1)):alert("Please provide a comment for this attachment.")},Cancel:function(){f.dialog("close")}},close:function(){var n=e.val();f.dialog("destroy").remove();u(o,n)}})},o._uploadImage=function(n){o._hideFlashVideoOverlay()&&i("#webcam_movie_obj, #webcam_movie_embed").css("display","none");var u=n.replace(/^data\:image\/\w+\;base64\,/,""),f=new Blob([r.base64DecToArr(u)],{type:"image/jpeg"}),t="CapturedImage-"+moment().format("YYYYMMDD-HHmmss")+".jpg";o.getFileComments(t,function(t){return t.attr("src",n),!0},function(n,r){(o._hideFlashVideoOverlay()&&i("#webcam_movie_obj, #webcam_movie_embed").css("display",""),n)&&o._uploadFile(f,t,r)})},o._uploadFiles=function(n){var t=i.makeArray(n),r=function(){if(t&&t.length!==0){var n=t.shift();o.getFileComments(n.name,function(t){if(!!n.type&&n.type.indexOf("image/")===0){var i=new FileReader;return i.onload=function(n){t.attr("src",n.target.result)},i.readAsDataURL(n),!0}return!1},function(t,i){t&&(o._uploadFile(n,n.name,i),r())})}};r()},o._uploadFile=function(n,t,r){var f=new FormData,u=new XMLHttpRequest,e=i("
").append(i("").addClass("fa fa-cog fa-spin")).append(i("").text("Uploading: "+t)).appendTo(o.uploadProgressContainer);f.append("Comments",r);f.append("File",n,t);u.open("POST",o.uploadUrl,!0);u.onreadystatechange=function(){u.readyState===4&&(u.status!==200&&alert("Error Uploading ["+t+"]: "+u.statusText),e.slideUp(400,function(){e.remove()}))};u.send(f)},o.__hideFlashVideoOverlay=null,o._hideFlashVideoOverlay=function(){if(o.__hideFlashVideoOverlay===null){o.__hideFlashVideoOverlay=!1;try{var n=/(windows nt) ([\w.]+)/.exec(navigator.userAgent.toLowerCase());!!n&&parseFloat(n[2])<=6.2&&(o.__hideFlashVideoOverlay=!0)}catch(t){}}return o.__hideFlashVideoOverlay},o};t.Disco||(t.Disco={});t.Disco.AttachmentUploader=u}(this,document,$,Webcam); \ No newline at end of file diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.js index 3eba3e7b..dd945d59 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.js @@ -1,67 +1,225 @@ -// WebcamJS v1.0 +// WebcamJS v1.0.26 // Webcam library for capturing JPEG/PNG images in JavaScript // Attempts getUserMedia, falls back to Flash // Author: Joseph Huckaby: http://github.com/jhuckaby // Based on JPEGCam: http://code.google.com/p/jpegcam/ -// Copyright (c) 2012 Joseph Huckaby +// Copyright (c) 2012 - 2019 Joseph Huckaby // Licensed under the MIT License -/* Usage: -
-
- - - - Take Snapshot -*/ +(function(window) { +var _userMedia; + +// declare error types + +// inheritance pattern here: +// https://stackoverflow.com/questions/783818/how-do-i-create-a-custom-error-in-javascript +function FlashError() { + var temp = Error.apply(this, arguments); + temp.name = this.name = "FlashError"; + this.stack = temp.stack; + this.message = temp.message; +} + +function WebcamError() { + var temp = Error.apply(this, arguments); + temp.name = this.name = "WebcamError"; + this.stack = temp.stack; + this.message = temp.message; +} + +var IntermediateInheritor = function() {}; +IntermediateInheritor.prototype = Error.prototype; + +FlashError.prototype = new IntermediateInheritor(); +WebcamError.prototype = new IntermediateInheritor(); var Webcam = { - version: '1.0.0', + version: '1.0.26', // globals protocol: location.protocol.match(/https/i) ? 'https' : 'http', - swfURL: '', // URI to webcam.swf movie (defaults to cwd) - loaded: false, // true when webcam movie finishes loading - live: false, // true when webcam is initialized and ready to snap + loaded: false, // true when webcam movie finishes loading + live: false, // true when webcam is initialized and ready to snap userMedia: true, // true when getUserMedia is supported natively - + + iOS: /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream, + params: { width: 0, height: 0, - dest_width: 0, // size of captured image - dest_height: 0, // these default to width/height - image_format: 'jpeg', // image format (may be jpeg or png) - jpeg_quality: 90, // jpeg image quality from 0 (worst) to 100 (best) - force_flash: false // force flash mode + dest_width: 0, // size of captured image + dest_height: 0, // these default to width/height + image_format: 'jpeg', // image format (may be jpeg or png) + jpeg_quality: 90, // jpeg image quality from 0 (worst) to 100 (best) + enable_flash: true, // enable flash fallback, + force_flash: false, // force flash mode, + flip_horiz: false, // flip image horiz (mirror mode) + fps: 30, // camera frames per second + upload_name: 'webcam', // name of file in upload post data + constraints: null, // custom user media constraints, + swfURL: '', // URI to webcam.swf movie (defaults to the js location) + flashNotDetectedText: 'ERROR: No Adobe Flash Player detected. Webcam.js relies on Flash for browsers that do not support getUserMedia (like yours).', + noInterfaceFoundText: 'No supported webcam interface found.', + unfreeze_snap: true, // Whether to unfreeze the camera after snap (defaults to true) + iosPlaceholderText: 'Click here to open camera.', + user_callback: null, // callback function for snapshot (used if no user_callback parameter given to snap function) + user_canvas: null // user provided canvas for snapshot (used if no user_canvas parameter given to snap function) + }, + + errors: { + FlashError: FlashError, + WebcamError: WebcamError }, - hooks: { - load: null, - live: null, - uploadcomplete: null, - uploadprogress: null, - error: function(msg) { alert("Webcam.js Error: " + msg); } - }, // callback hook functions + hooks: {}, // callback hook functions init: function() { // initialize, check for getUserMedia support - navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; - window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + var self = this; - this.userMedia = this.userMedia && !!navigator.getUserMedia && !!window.URL; + // Setup getUserMedia, with polyfill for older browsers + // Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia + this.mediaDevices = (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) ? + navigator.mediaDevices : ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? { + getUserMedia: function(c) { + return new Promise(function(y, n) { + (navigator.mozGetUserMedia || + navigator.webkitGetUserMedia).call(navigator, c, y, n); + }); + } + } : null); + + window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + this.userMedia = this.userMedia && !!this.mediaDevices && !!window.URL; // Older versions of firefox (< 21) apparently claim support but user media does not actually work if (navigator.userAgent.match(/Firefox\D+(\d+)/)) { if (parseInt(RegExp.$1, 10) < 21) this.userMedia = null; } + + // Make sure media stream is closed when navigating away from page + if (this.userMedia) { + window.addEventListener( 'beforeunload', function(event) { + self.reset(); + } ); + } + }, + + exifOrientation: function(binFile) { + // extract orientation information from the image provided by iOS + // algorithm based on exif-js + var dataView = new DataView(binFile); + if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) { + console.log('Not a valid JPEG file'); + return 0; + } + var offset = 2; + var marker = null; + while (offset < binFile.byteLength) { + // find 0xFFE1 (225 marker) + if (dataView.getUint8(offset) != 0xFF) { + console.log('Not a valid marker at offset ' + offset + ', found: ' + dataView.getUint8(offset)); + return 0; + } + marker = dataView.getUint8(offset + 1); + if (marker == 225) { + offset += 4; + var str = ""; + for (n = 0; n < 4; n++) { + str += String.fromCharCode(dataView.getUint8(offset+n)); + } + if (str != 'Exif') { + console.log('Not valid EXIF data found'); + return 0; + } + + offset += 6; // tiffOffset + var bigEnd = null; + + // test for TIFF validity and endianness + if (dataView.getUint16(offset) == 0x4949) { + bigEnd = false; + } else if (dataView.getUint16(offset) == 0x4D4D) { + bigEnd = true; + } else { + console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)"); + return 0; + } + + if (dataView.getUint16(offset+2, !bigEnd) != 0x002A) { + console.log("Not valid TIFF data! (no 0x002A)"); + return 0; + } + + var firstIFDOffset = dataView.getUint32(offset+4, !bigEnd); + if (firstIFDOffset < 0x00000008) { + console.log("Not valid TIFF data! (First offset less than 8)", dataView.getUint32(offset+4, !bigEnd)); + return 0; + } + + // extract orientation data + var dataStart = offset + firstIFDOffset; + var entries = dataView.getUint16(dataStart, !bigEnd); + for (var i=0; i 8) { + console.log('Invalid EXIF orientation value ('+value+')'); + return 0; + } + return value; + } + } + } else { + offset += 2+dataView.getUint16(offset+2); + } + } + return 0; + }, + + fixOrientation: function(origObjURL, orientation, targetImg) { + // fix image orientation based on exif orientation data + // exif orientation information + // http://www.impulseadventure.com/photo/exif-orientation.html + // link source wikipedia (https://en.wikipedia.org/wiki/Exif#cite_note-20) + var img = new Image(); + img.addEventListener('load', function(event) { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + + // switch width height if orientation needed + if (orientation < 5) { + canvas.width = img.width; + canvas.height = img.height; + } else { + canvas.width = img.height; + canvas.height = img.width; + } + + // transform (rotate) image - see link at beginning this method + switch (orientation) { + case 2: ctx.transform(-1, 0, 0, 1, img.width, 0); break; + case 3: ctx.transform(-1, 0, 0, -1, img.width, img.height); break; + case 4: ctx.transform(1, 0, 0, -1, 0, img.height); break; + case 5: ctx.transform(0, 1, 1, 0, 0, 0); break; + case 6: ctx.transform(0, 1, -1, 0, img.height , 0); break; + case 7: ctx.transform(0, -1, -1, 0, img.height, img.width); break; + case 8: ctx.transform(0, -1, 1, 0, 0, img.width); break; + } + + ctx.drawImage(img, 0, 0); + // pass rotated image data to the target image container + targetImg.src = canvas.toDataURL(); + }, false); + // start transformation by load event + img.src = origObjURL; }, attach: function(elem) { @@ -71,33 +229,53 @@ var Webcam = { elem = document.getElementById(elem) || document.querySelector(elem); } if (!elem) { - return this.dispatch('error', "Could not locate DOM element to attach to."); + return this.dispatch('error', new WebcamError("Could not locate DOM element to attach to.")); } - this.container = elem; + elem.innerHTML = ''; // start with empty element + + // insert "peg" so we can insert our preview canvas adjacent to it later on + var peg = document.createElement('div'); + elem.appendChild( peg ); + this.peg = peg; + + // set width/height if not already set if (!this.params.width) this.params.width = elem.offsetWidth; if (!this.params.height) this.params.height = elem.offsetHeight; + // make sure we have a nonzero width and height at this point + if (!this.params.width || !this.params.height) { + return this.dispatch('error', new WebcamError("No width and/or height for webcam. Please call set() first, or attach to a visible element.")); + } + // set defaults for dest_width / dest_height if not set if (!this.params.dest_width) this.params.dest_width = this.params.width; if (!this.params.dest_height) this.params.dest_height = this.params.height; + this.userMedia = _userMedia === undefined ? this.userMedia : _userMedia; // if force_flash is set, disable userMedia - if (this.params.force_flash) this.userMedia = null; + if (this.params.force_flash) { + _userMedia = this.userMedia; + this.userMedia = null; + } + + // check for default fps + if (typeof this.params.fps !== "number") this.params.fps = 30; + + // adjust scale if dest_width or dest_height is different + var scaleX = this.params.width / this.params.dest_width; + var scaleY = this.params.height / this.params.dest_height; if (this.userMedia) { // setup webcam video container var video = document.createElement('video'); video.setAttribute('autoplay', 'autoplay'); + video.setAttribute('playsinline', 'playsinline'); video.style.width = '' + this.params.dest_width + 'px'; video.style.height = '' + this.params.dest_height + 'px'; - // adjust scale if dest_width or dest_height is different - var scaleX = this.params.width / this.params.dest_width; - var scaleY = this.params.height / this.params.dest_height; - if ((scaleX != 1.0) || (scaleY != 1.0)) { - elem.style.overflow = 'visible'; + elem.style.overflow = 'hidden'; video.style.webkitTransformOrigin = '0px 0px'; video.style.mozTransformOrigin = '0px 0px'; video.style.msTransformOrigin = '0px 0px'; @@ -114,52 +292,215 @@ var Webcam = { elem.appendChild( video ); this.video = video; - // create offscreen canvas element to hold pixels later on - var canvas = document.createElement('canvas'); - canvas.width = this.params.dest_width; - canvas.height = this.params.dest_height; - var context = canvas.getContext('2d'); - this.context = context; - this.canvas = canvas; - // ask user for access to their camera var self = this; - navigator.getUserMedia({ + this.mediaDevices.getUserMedia({ "audio": false, - "video": true - }, - function(stream) { + "video": this.params.constraints || { + mandatory: { + minWidth: this.params.dest_width, + minHeight: this.params.dest_height + } + } + }) + .then( function(stream) { // got access, attach stream to video - video.src = window.URL.createObjectURL( stream ) || stream; - Webcam.stream = stream; - Webcam.loaded = true; - Webcam.live = true; - Webcam.dispatch('load'); - Webcam.dispatch('live'); - }, - function(err) { - return self.dispatch('error', "Could not access webcam."); + video.onloadedmetadata = function(e) { + self.stream = stream; + self.loaded = true; + self.live = true; + self.dispatch('load'); + self.dispatch('live'); + self.flip(); + }; + // as window.URL.createObjectURL() is deprecated, adding a check so that it works in Safari. + // older browsers may not have srcObject + if ("srcObject" in video) { + video.srcObject = stream; + } + else { + // using URL.createObjectURL() as fallback for old browsers + video.src = window.URL.createObjectURL(stream); + } + }) + .catch( function(err) { + // JH 2016-07-31 Instead of dispatching error, now falling back to Flash if userMedia fails (thx @john2014) + // JH 2016-08-07 But only if flash is actually installed -- if not, dispatch error here and now. + if (self.params.enable_flash && self.detectFlash()) { + setTimeout( function() { self.params.force_flash = 1; self.attach(elem); }, 1 ); + } + else { + self.dispatch('error', err); + } }); } - else { + else if (this.iOS) { + // prepare HTML elements + var div = document.createElement('div'); + div.id = this.container.id+'-ios_div'; + div.className = 'webcamjs-ios-placeholder'; + div.style.width = '' + this.params.width + 'px'; + div.style.height = '' + this.params.height + 'px'; + div.style.textAlign = 'center'; + div.style.display = 'table-cell'; + div.style.verticalAlign = 'middle'; + div.style.backgroundRepeat = 'no-repeat'; + div.style.backgroundSize = 'contain'; + div.style.backgroundPosition = 'center'; + var span = document.createElement('span'); + span.className = 'webcamjs-ios-text'; + span.innerHTML = this.params.iosPlaceholderText; + div.appendChild(span); + var img = document.createElement('img'); + img.id = this.container.id+'-ios_img'; + img.style.width = '' + this.params.dest_width + 'px'; + img.style.height = '' + this.params.dest_height + 'px'; + img.style.display = 'none'; + div.appendChild(img); + var input = document.createElement('input'); + input.id = this.container.id+'-ios_input'; + input.setAttribute('type', 'file'); + input.setAttribute('accept', 'image/*'); + input.setAttribute('capture', 'camera'); + + var self = this; + var params = this.params; + // add input listener to load the selected image + input.addEventListener('change', function(event) { + if (event.target.files.length > 0 && event.target.files[0].type.indexOf('image/') == 0) { + var objURL = URL.createObjectURL(event.target.files[0]); + + // load image with auto scale and crop + var image = new Image(); + image.addEventListener('load', function(event) { + var canvas = document.createElement('canvas'); + canvas.width = params.dest_width; + canvas.height = params.dest_height; + var ctx = canvas.getContext('2d'); + + // crop and scale image for final size + ratio = Math.min(image.width / params.dest_width, image.height / params.dest_height); + var sw = params.dest_width * ratio; + var sh = params.dest_height * ratio; + var sx = (image.width - sw) / 2; + var sy = (image.height - sh) / 2; + ctx.drawImage(image, sx, sy, sw, sh, 0, 0, params.dest_width, params.dest_height); + + var dataURL = canvas.toDataURL(); + img.src = dataURL; + div.style.backgroundImage = "url('"+dataURL+"')"; + }, false); + + // read EXIF data + var fileReader = new FileReader(); + fileReader.addEventListener('load', function(e) { + var orientation = self.exifOrientation(e.target.result); + if (orientation > 1) { + // image need to rotate (see comments on fixOrientation method for more information) + // transform image and load to image object + self.fixOrientation(objURL, orientation, image); + } else { + // load image data to image object + image.src = objURL; + } + }, false); + + // Convert image data to blob format + var http = new XMLHttpRequest(); + http.open("GET", objURL, true); + http.responseType = "blob"; + http.onload = function(e) { + if (this.status == 200 || this.status === 0) { + fileReader.readAsArrayBuffer(this.response); + } + }; + http.send(); + + } + }, false); + input.style.display = 'none'; + elem.appendChild(input); + // make div clickable for open camera interface + div.addEventListener('click', function(event) { + if (params.user_callback) { + // global user_callback defined - create the snapshot + self.snap(params.user_callback, params.user_canvas); + } else { + // no global callback definied for snapshot, load image and wait for external snap method call + input.style.display = 'block'; + input.focus(); + input.click(); + input.style.display = 'none'; + } + }, false); + elem.appendChild(div); + this.loaded = true; + this.live = true; + } + else if (this.params.enable_flash && this.detectFlash()) { // flash fallback - elem.innerHTML = this.getSWFHTML(); + window.Webcam = Webcam; // needed for flash-to-js interface + var div = document.createElement('div'); + div.innerHTML = this.getSWFHTML(); + elem.appendChild( div ); + } + else { + this.dispatch('error', new WebcamError( this.params.noInterfaceFoundText )); + } + + // setup final crop for live preview + if (this.params.crop_width && this.params.crop_height) { + var scaled_crop_width = Math.floor( this.params.crop_width * scaleX ); + var scaled_crop_height = Math.floor( this.params.crop_height * scaleY ); + + elem.style.width = '' + scaled_crop_width + 'px'; + elem.style.height = '' + scaled_crop_height + 'px'; + elem.style.overflow = 'hidden'; + + elem.scrollLeft = Math.floor( (this.params.width / 2) - (scaled_crop_width / 2) ); + elem.scrollTop = Math.floor( (this.params.height / 2) - (scaled_crop_height / 2) ); + } + else { + // no crop, set size to desired + elem.style.width = '' + this.params.width + 'px'; + elem.style.height = '' + this.params.height + 'px'; } }, reset: function() { // shutdown camera, reset to potentially attach again + if (this.preview_active) this.unfreeze(); + + // attempt to fix issue #64 + this.unflip(); + if (this.userMedia) { - try { this.stream.stop(); } catch (e) {;} + if (this.stream) { + if (this.stream.getVideoTracks) { + // get video track to call stop on it + var tracks = this.stream.getVideoTracks(); + if (tracks && tracks[0] && tracks[0].stop) tracks[0].stop(); + } + else if (this.stream.stop) { + // deprecated, may be removed in future + this.stream.stop(); + } + } delete this.stream; - delete this.canvas; - delete this.context; delete this.video; } - - this.container.innerHTML = ''; - delete this.container; - + + if ((this.userMedia !== true) && this.loaded && !this.iOS) { + // call for turn off camera in flash + var movie = this.getMovie(); + if (movie && movie._releaseCamera) movie._releaseCamera(); + } + + if (this.container) { + this.container.innerHTML = ''; + delete this.container; + } + this.loaded = false; this.live = false; }, @@ -179,13 +520,25 @@ var Webcam = { on: function(name, callback) { // set callback hook - // supported hooks: onLoad, onError, onLive name = name.replace(/^on/i, '').toLowerCase(); - - if (typeof(this.hooks[name]) == 'undefined') - throw "Event type not supported: " + name; - - this.hooks[name] = callback; + if (!this.hooks[name]) this.hooks[name] = []; + this.hooks[name].push( callback ); + }, + + off: function(name, callback) { + // remove callback hook + name = name.replace(/^on/i, '').toLowerCase(); + if (this.hooks[name]) { + if (callback) { + // remove one selected callback from list + var idx = this.hooks[name].indexOf(callback); + if (idx > -1) this.hooks[name].splice(idx, 1); + } + else { + // no callback specified, so clear all + this.hooks[name] = []; + } + } }, dispatch: function() { @@ -193,40 +546,95 @@ var Webcam = { var name = arguments[0].replace(/^on/i, '').toLowerCase(); var args = Array.prototype.slice.call(arguments, 1); - if (this.hooks[name]) { - if (typeof(this.hooks[name]) == 'function') { - // callback is function reference, call directly - this.hooks[name].apply(this, args); - } - else if (typeof(this.hooks[name]) == 'array') { - // callback is PHP-style object instance method - this.hooks[name][0][this.hooks[name][1]].apply(this.hooks[name][0], args); - } - else if (window[this.hooks[name]]) { - // callback is global function name - window[ this.hooks[name] ].apply(window, args); - } + if (this.hooks[name] && this.hooks[name].length) { + for (var idx = 0, len = this.hooks[name].length; idx < len; idx++) { + var hook = this.hooks[name][idx]; + + if (typeof(hook) == 'function') { + // callback is function reference, call directly + hook.apply(this, args); + } + else if ((typeof(hook) == 'object') && (hook.length == 2)) { + // callback is PHP-style object instance method + hook[0][hook[1]].apply(hook[0], args); + } + else if (window[hook]) { + // callback is global function name + window[ hook ].apply(window, args); + } + } // loop return true; } + else if (name == 'error') { + var message; + if ((args[0] instanceof FlashError) || (args[0] instanceof WebcamError)) { + message = args[0].message; + } else { + message = "Could not access webcam: " + args[0].name + ": " + + args[0].message + " " + args[0].toString(); + } + + // default error handler if no custom one specified + alert("Webcam.js Error: " + message); + } + return false; // no hook defined }, + + setSWFLocation: function(value) { + // for backward compatibility. + this.set('swfURL', value); + }, - setSWFLocation: function(url) { - // set location of SWF movie (defaults to webcam.swf in cwd) - this.swfURL = url; + detectFlash: function() { + // return true if browser supports flash, false otherwise + // Code snippet borrowed from: https://github.com/swfobject/swfobject + var SHOCKWAVE_FLASH = "Shockwave Flash", + SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", + FLASH_MIME_TYPE = "application/x-shockwave-flash", + win = window, + nav = navigator, + hasFlash = false; + + if (typeof nav.plugins !== "undefined" && typeof nav.plugins[SHOCKWAVE_FLASH] === "object") { + var desc = nav.plugins[SHOCKWAVE_FLASH].description; + if (desc && (typeof nav.mimeTypes !== "undefined" && nav.mimeTypes[FLASH_MIME_TYPE] && nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { + hasFlash = true; + } + } + else if (typeof win.ActiveXObject !== "undefined") { + try { + var ax = new ActiveXObject(SHOCKWAVE_FLASH_AX); + if (ax) { + var ver = ax.GetVariable("$version"); + if (ver) hasFlash = true; + } + } + catch (e) {;} + } + + return hasFlash; }, getSWFHTML: function() { // Return HTML for embedding flash based webcam capture movie - var html = ''; + var html = '', + swfURL = this.params.swfURL; // make sure we aren't running locally (flash doesn't work) if (location.protocol.match(/file/)) { - return '

Sorry, the Webcam.js Flash fallback does not work from local disk. Please upload it to a web server first.

'; + this.dispatch('error', new FlashError("Flash does not work from local disk. Please run from a web server.")); + return '

ERROR: the Webcam.js Flash fallback does not work from local disk. Please run it from a web server.

'; + } + + // make sure we have flash + if (!this.detectFlash()) { + this.dispatch('error', new FlashError("Adobe Flash Player not found. Please install from get.adobe.com/flashplayer and try again.")); + return '

' + this.params.flashNotDetectedText + '

'; } // set default swfURL if not explicitly set - if (!this.swfURL) { + if (!swfURL) { // find our script tag, and use that base URL var base_url = ''; var scpts = document.getElementsByTagName('script'); @@ -237,8 +645,8 @@ var Webcam = { idx = len; } } - if (base_url) this.swfURL = base_url + '/webcam.swf'; - else this.swfURL = 'webcam.swf'; + if (base_url) swfURL = base_url + '/webcam.swf'; + else swfURL = 'webcam.swf'; } // if this is the user's first visit, set flashvar so flash privacy settings panel is shown first @@ -254,35 +662,265 @@ var Webcam = { flashvars += key + '=' + escape(this.params[key]); } - html += ''; + // construct object/embed tag + html += ''; return html; }, getMovie: function() { // get reference to movie object/embed in DOM - if (!this.loaded) return this.dispatch('error', "Flash Movie is not loaded yet"); + if (!this.loaded) return this.dispatch('error', new FlashError("Flash Movie is not loaded yet")); var movie = document.getElementById('webcam_movie_obj'); if (!movie || !movie._snap) movie = document.getElementById('webcam_movie_embed'); - if (!movie) this.dispatch('error', "Cannot locate Flash movie in DOM"); + if (!movie) this.dispatch('error', new FlashError("Cannot locate Flash movie in DOM")); return movie; }, - snap: function() { - // take snapshot and return image data uri - if (!this.loaded) return this.dispatch('error', "Webcam is not loaded yet"); - if (!this.live) return this.dispatch('error', "Webcam is not live yet"); + freeze: function() { + // show preview, freeze camera + var self = this; + var params = this.params; + // kill preview if already active + if (this.preview_active) this.unfreeze(); + + // determine scale factor + var scaleX = this.params.width / this.params.dest_width; + var scaleY = this.params.height / this.params.dest_height; + + // must unflip container as preview canvas will be pre-flipped + this.unflip(); + + // calc final size of image + var final_width = params.crop_width || params.dest_width; + var final_height = params.crop_height || params.dest_height; + + // create canvas for holding preview + var preview_canvas = document.createElement('canvas'); + preview_canvas.width = final_width; + preview_canvas.height = final_height; + var preview_context = preview_canvas.getContext('2d'); + + // save for later use + this.preview_canvas = preview_canvas; + this.preview_context = preview_context; + + // scale for preview size + if ((scaleX != 1.0) || (scaleY != 1.0)) { + preview_canvas.style.webkitTransformOrigin = '0px 0px'; + preview_canvas.style.mozTransformOrigin = '0px 0px'; + preview_canvas.style.msTransformOrigin = '0px 0px'; + preview_canvas.style.oTransformOrigin = '0px 0px'; + preview_canvas.style.transformOrigin = '0px 0px'; + preview_canvas.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; + preview_canvas.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; + preview_canvas.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; + preview_canvas.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; + preview_canvas.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; + } + + // take snapshot, but fire our own callback + this.snap( function() { + // add preview image to dom, adjust for crop + preview_canvas.style.position = 'relative'; + preview_canvas.style.left = '' + self.container.scrollLeft + 'px'; + preview_canvas.style.top = '' + self.container.scrollTop + 'px'; + + self.container.insertBefore( preview_canvas, self.peg ); + self.container.style.overflow = 'hidden'; + + // set flag for user capture (use preview) + self.preview_active = true; + + }, preview_canvas ); + }, + + unfreeze: function() { + // cancel preview and resume live video feed + if (this.preview_active) { + // remove preview canvas + this.container.removeChild( this.preview_canvas ); + delete this.preview_context; + delete this.preview_canvas; + + // unflag + this.preview_active = false; + + // re-flip if we unflipped before + this.flip(); + } + }, + + flip: function() { + // flip container horiz (mirror mode) if desired + if (this.params.flip_horiz) { + var sty = this.container.style; + sty.webkitTransform = 'scaleX(-1)'; + sty.mozTransform = 'scaleX(-1)'; + sty.msTransform = 'scaleX(-1)'; + sty.oTransform = 'scaleX(-1)'; + sty.transform = 'scaleX(-1)'; + sty.filter = 'FlipH'; + sty.msFilter = 'FlipH'; + } + }, + + unflip: function() { + // unflip container horiz (mirror mode) if desired + if (this.params.flip_horiz) { + var sty = this.container.style; + sty.webkitTransform = 'scaleX(1)'; + sty.mozTransform = 'scaleX(1)'; + sty.msTransform = 'scaleX(1)'; + sty.oTransform = 'scaleX(1)'; + sty.transform = 'scaleX(1)'; + sty.filter = ''; + sty.msFilter = ''; + } + }, + + savePreview: function(user_callback, user_canvas) { + // save preview freeze and fire user callback + var params = this.params; + var canvas = this.preview_canvas; + var context = this.preview_context; + + // render to user canvas if desired + if (user_canvas) { + var user_context = user_canvas.getContext('2d'); + user_context.drawImage( canvas, 0, 0 ); + } + + // fire user callback if desired + user_callback( + user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ), + canvas, + context + ); + + // remove preview + if (this.params.unfreeze_snap) this.unfreeze(); + }, + + snap: function(user_callback, user_canvas) { + // use global callback and canvas if not defined as parameter + if (!user_callback) user_callback = this.params.user_callback; + if (!user_canvas) user_canvas = this.params.user_canvas; + + // take snapshot and return image data uri + var self = this; + var params = this.params; + + if (!this.loaded) return this.dispatch('error', new WebcamError("Webcam is not loaded yet")); + // if (!this.live) return this.dispatch('error', new WebcamError("Webcam is not live yet")); + if (!user_callback) return this.dispatch('error', new WebcamError("Please provide a callback function or canvas to snap()")); + + // if we have an active preview freeze, use that + if (this.preview_active) { + this.savePreview( user_callback, user_canvas ); + return null; + } + + // create offscreen canvas element to hold pixels + var canvas = document.createElement('canvas'); + canvas.width = this.params.dest_width; + canvas.height = this.params.dest_height; + var context = canvas.getContext('2d'); + + // flip canvas horizontally if desired + if (this.params.flip_horiz) { + context.translate( params.dest_width, 0 ); + context.scale( -1, 1 ); + } + + // create inline function, called after image load (flash) or immediately (native) + var func = function() { + // render image if needed (flash) + if (this.src && this.width && this.height) { + context.drawImage(this, 0, 0, params.dest_width, params.dest_height); + } + + // crop if desired + if (params.crop_width && params.crop_height) { + var crop_canvas = document.createElement('canvas'); + crop_canvas.width = params.crop_width; + crop_canvas.height = params.crop_height; + var crop_context = crop_canvas.getContext('2d'); + + crop_context.drawImage( canvas, + Math.floor( (params.dest_width / 2) - (params.crop_width / 2) ), + Math.floor( (params.dest_height / 2) - (params.crop_height / 2) ), + params.crop_width, + params.crop_height, + 0, + 0, + params.crop_width, + params.crop_height + ); + + // swap canvases + context = crop_context; + canvas = crop_canvas; + } + + // render to user canvas if desired + if (user_canvas) { + var user_context = user_canvas.getContext('2d'); + user_context.drawImage( canvas, 0, 0 ); + } + + // fire user callback if desired + user_callback( + user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ), + canvas, + context + ); + }; + + // grab image frame from userMedia or flash movie if (this.userMedia) { // native implementation - this.context.drawImage(this.video, 0, 0, this.params.dest_width, this.params.dest_height); - return this.canvas.toDataURL('image/' + this.params.image_format, this.params.jpeg_quality / 100 ); + context.drawImage(this.video, 0, 0, this.params.dest_width, this.params.dest_height); + + // fire callback right away + func(); + } + else if (this.iOS) { + var div = document.getElementById(this.container.id+'-ios_div'); + var img = document.getElementById(this.container.id+'-ios_img'); + var input = document.getElementById(this.container.id+'-ios_input'); + // function for handle snapshot event (call user_callback and reset the interface) + iFunc = function(event) { + func.call(img); + img.removeEventListener('load', iFunc); + div.style.backgroundImage = 'none'; + img.removeAttribute('src'); + input.value = null; + }; + if (!input.value) { + // No image selected yet, activate input field + img.addEventListener('load', iFunc); + input.style.display = 'block'; + input.focus(); + input.click(); + input.style.display = 'none'; + } else { + // Image already selected + iFunc(null); + } } else { // flash fallback var raw_data = this.getMovie()._snap(); - return 'data:image/'+this.params.image_format+';base64,' + raw_data; + + // render to image, fire callback when complete + var img = new Image(); + img.onload = func; + img.src = 'data:image/'+this.params.image_format+';base64,' + raw_data; } + + return null; }, configure: function(panel) { @@ -309,7 +947,7 @@ var Webcam = { case 'error': // Flash error - this.dispatch('error', msg); + this.dispatch('error', new FlashError(msg)); break; default: @@ -350,8 +988,7 @@ var Webcam = { upload: function(image_data_uri, target_url, callback) { // submit image data to server using binary AJAX - if (callback) Webcam.on('uploadComplete', callback); - var form_elem_name = 'webcam'; + var form_elem_name = this.params.upload_name || 'webcam'; // detect image format from within image_data_uri var image_fmt = ''; @@ -378,7 +1015,9 @@ var Webcam = { } // completion handler + var self = this; http.onload = function() { + if (callback) callback.apply( self, [http.status, http.responseText, http.statusText] ); Webcam.dispatch('uploadComplete', http.status, http.responseText, http.statusText); }; @@ -396,3 +1035,15 @@ var Webcam = { }; Webcam.init(); + +if (typeof define === 'function' && define.amd) { + define( function() { return Webcam; } ); +} +else if (typeof module === 'object' && module.exports) { + module.exports = Webcam; +} +else { + window.Webcam = Webcam; +} + +}(window)); diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf index e24a6b99..e1d88cd2 100644 Binary files a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf and b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf differ diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor.js index db209141..f748c097 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor.js @@ -1,4 +1,4 @@ -/// +/// function DiscoExpressionEditor(host, validateUrl, expression) { this.host = host; this.hostDocument = null; diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor/disco.expressioneditor.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor/disco.expressioneditor.js index a2214abe..6a23d6e7 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor/disco.expressioneditor.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-ExpressionEditor/disco.expressioneditor.js @@ -1,4 +1,4 @@ -/// +/// function DiscoExpressionEditor(host, validateUrl, expression) { this.host = host; this.hostDocument = null; diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions.js index 76c7b0f6..b15e98cd 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions.js @@ -1,4 +1,4 @@ -/// +/// (function ($) { var checkboxBulkSelectMethods = { diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions/disco.jQueryExtensions.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions/disco.jQueryExtensions.js index b999a841..76b6e2ce 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions/disco.jQueryExtensions.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-jQueryExtensions/disco.jQueryExtensions.js @@ -1,4 +1,4 @@ -/// +/// (function ($) { var checkboxBulkSelectMethods = { diff --git a/Disco.Web/ClientSource/Scripts/Modules/Highcharts.js b/Disco.Web/ClientSource/Scripts/Modules/Highcharts.js index 1b500612..9e063bd7 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Highcharts.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Highcharts.js @@ -17669,4 +17669,4 @@ extend(Highcharts, { version: VERSION }); -}()); \ No newline at end of file +}()); diff --git a/Disco.Web/ClientSource/Scripts/Modules/Knockout.js b/Disco.Web/ClientSource/Scripts/Modules/Knockout.js index 100b53b0..b88cf27f 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Knockout.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Knockout.js @@ -93,4 +93,4 @@ l,g]));k.length=0;a.a.$(k,l)},null,{G:b,Da:function(){return!a.a.eb(k)}});return v,x=0,A,C;A=q[x];x++)switch(C=A.moved,A.status){case "deleted":C===p&&(v=r[t],v.h&&v.h.F(),w.push.apply(w,a.a.ea(v.S,d)),h.beforeRemove&&(e[x]=v,y.push(v)));t++;break;case "retained":k(x,t++);break;case "added":C!==p?k(x,C):(v={ka:A.value,Ia:a.m(u++)},s.push(v),y.push(v),n||(m[x]=v))}l(h.beforeMove,z);a.a.r(w,h.beforeRemove?a.M:a.removeNode);for(var x=0,n=a.e.firstChild(d),E;v=y[x];x++){v.S||a.a.extend(v,b(d,f,v.ka,g,v.Ia));for(t=0;q=v.S[t];n=q.nextSibling,E=q,t++)q!==n&&a.e.rb(d,q,E);!v.Zb&&g&&(g(v.ka, v.S,v.Ia),v.Zb=!0)}l(h.beforeRemove,e);l(h.afterMove,z);l(h.afterAdd,m);a.a.f.set(d,c,s)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Ua);a.K=function(){this.allowTemplateRewriting=!1};a.K.prototype=new a.C;a.K.prototype.renderTemplateSource=function(b){var c=(9>a.a.oa?0:b.nodes)?b.nodes():null;if(c)return a.a.R(c.cloneNode(!0).childNodes);b=b.text();return a.a.Qa(b)};a.K.Ja=new a.K;a.Wa(a.K.Ja);a.b("nativeTemplateEngine",a.K);(function(){a.La=function(){var a=this.ac=function(){if(!t|| !t.tmpl)return 0;try{if(0<=t.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f){f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=t.template(null,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=t.extend({koBindingContext:e},f.templateOptions);e=t.tmpl(h,b,e);e.appendTo(w.createElement("div")); -t.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){w.write("