diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.js index 6e2174e7..deec4591 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.js @@ -1,1056 +1,4 @@ -// 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 - 2019 Joseph Huckaby -// Licensed under the MIT License - -(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.26', - - // globals - protocol: location.protocol.match(/https/i) ? 'https' : 'http', - 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) - 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: {}, // callback hook functions - - init: function() { - // initialize, check for getUserMedia support - var self = this; - - // 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) { - // create webcam preview and attach to DOM element - // pass in actual DOM reference, ID, or CSS selector - if (typeof(elem) == 'string') { - elem = document.getElementById(elem) || document.querySelector(elem); - } - if (!elem) { - 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) { - _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'; - - if ((scaleX != 1.0) || (scaleY != 1.0)) { - elem.style.overflow = 'hidden'; - video.style.webkitTransformOrigin = '0px 0px'; - video.style.mozTransformOrigin = '0px 0px'; - video.style.msTransformOrigin = '0px 0px'; - video.style.oTransformOrigin = '0px 0px'; - video.style.transformOrigin = '0px 0px'; - video.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; - video.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; - video.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; - video.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; - video.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; - } - - // add video element to dom - elem.appendChild( video ); - this.video = video; - - // ask user for access to their camera - var self = this; - this.mediaDevices.getUserMedia({ - "audio": false, - "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.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 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 - 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) { - 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.video; - } - - 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; - }, - - set: function() { - // set one or more params - // variable argument list: 1 param = hash, 2 params = key, value - if (arguments.length == 1) { - for (var key in arguments[0]) { - this.params[key] = arguments[0][key]; - } - } - else { - this.params[ arguments[0] ] = arguments[1]; - } - }, - - on: function(name, callback) { - // set callback hook - name = name.replace(/^on/i, '').toLowerCase(); - 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() { - // fire hook callback, passing optional value to it - var name = arguments[0].replace(/^on/i, '').toLowerCase(); - var args = Array.prototype.slice.call(arguments, 1); - - 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); - }, - - 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 = '', - swfURL = this.params.swfURL; - - // make sure we aren't running locally (flash doesn't work) - if (location.protocol.match(/file/)) { - 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 (!swfURL) { - // find our script tag, and use that base URL - var base_url = ''; - var scpts = document.getElementsByTagName('script'); - for (var idx = 0, len = scpts.length; idx < len; idx++) { - var src = scpts[idx].getAttribute('src'); - if (src && src.match(/\/webcam(\.min)?\.js/)) { - base_url = src.replace(/\/webcam(\.min)?\.js.*$/, ''); - idx = len; - } - } - 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 - if (window.localStorage && !localStorage.getItem('visited')) { - this.params.new_user = 1; - localStorage.setItem('visited', 1); - } - - // construct flashvars string - var flashvars = ''; - for (var key in this.params) { - if (flashvars) flashvars += '&'; - flashvars += key + '=' + escape(this.params[key]); - } - - // construct object/embed tag - html += ''; - - return html; - }, - - getMovie: function() { - // get reference to movie object/embed in DOM - 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', new FlashError("Cannot locate Flash movie in DOM")); - return movie; - }, - - 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 - 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(); - - // 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) { - // open flash configuration panel -- specify tab name: - // "camera", "privacy", "default", "localStorage", "microphone", "settingsManager" - if (!panel) panel = "camera"; - this.getMovie()._configure(panel); - }, - - flashNotify: function(type, msg) { - // receive notification from flash about event - switch (type) { - case 'flashLoadComplete': - // movie loaded successfully - this.loaded = true; - this.dispatch('load'); - break; - - case 'cameraLive': - // camera is live and ready to snap - this.live = true; - this.dispatch('live'); - break; - - case 'error': - // Flash error - this.dispatch('error', new FlashError(msg)); - break; - - default: - // catch-all event, just in case - // console.log("webcam flash_notify: " + type + ": " + msg); - break; - } - }, - - b64ToUint6: function(nChr) { - // convert base64 encoded character to 6-bit integer - // from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding - return nChr > 64 && nChr < 91 ? nChr - 65 - : nChr > 96 && nChr < 123 ? nChr - 71 - : nChr > 47 && nChr < 58 ? nChr + 4 - : nChr === 43 ? 62 : nChr === 47 ? 63 : 0; - }, - - base64DecToArr: function(sBase64, nBlocksSize) { - // convert base64 encoded string to Uintarray - // from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding - var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length, - nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, - taBytes = new Uint8Array(nOutLen); - - for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { - nMod4 = nInIdx & 3; - nUint24 |= this.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4; - if (nMod4 === 3 || nInLen - nInIdx === 1) { - for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { - taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; - } - nUint24 = 0; - } - } - return taBytes; - }, - - upload: function(image_data_uri, target_url, callback) { - // submit image data to server using binary AJAX - var form_elem_name = this.params.upload_name || 'webcam'; - - // detect image format from within image_data_uri - var image_fmt = ''; - if (image_data_uri.match(/^data\:image\/(\w+)/)) - image_fmt = RegExp.$1; - else - throw "Cannot locate image format in Data URI"; - - // extract raw base64 data from Data URI - var raw_image_data = image_data_uri.replace(/^data\:image\/\w+\;base64\,/, ''); - - // contruct use AJAX object - var http = new XMLHttpRequest(); - http.open("POST", target_url, true); - - // setup progress events - if (http.upload && http.upload.addEventListener) { - http.upload.addEventListener( 'progress', function(e) { - if (e.lengthComputable) { - var progress = e.loaded / e.total; - Webcam.dispatch('uploadProgress', progress, e); - } - }, false ); - } - - // 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); - }; - - // create a blob and decode our base64 to binary - var blob = new Blob( [ this.base64DecToArr(raw_image_data) ], {type: 'image/'+image_fmt} ); - - // stuff into a form, so servers can easily receive it as a standard file upload - var form = new FormData(); - form.append( form_elem_name, blob, form_elem_name+"."+image_fmt.replace(/e/, '') ); - - // send data to server - http.send(form); - } - -}; - -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)); - -/// - -; (function (window, document, $, Webcam) { +(function (window, document, $) { "use strict"; var attachmentUploader = function (uploadUrl, dropTarget, uploadProgressContainer) { @@ -1132,12 +80,11 @@ else { // #region Webcam Support self.uploadImage = function () { - var mediaWidth = 720; - var mediaHeight = 540; - var mediaStream; + let mediaStream = null; + let videoStreaming = false; // Setup Dialog - var dialog = $('
') + var dialog = $('
') .attr({ id: 'Disco_AttachmentUpload_ImageDialog', title: 'Upload Image', @@ -1148,46 +95,68 @@ else { draggable: false, modal: true, resizable: false, - width: mediaWidth, - height: mediaHeight, + width: 720, + height: 405, close: function () { - Webcam.reset(); + if (mediaStream) { + mediaStream.getTracks().forEach(track => track.stop()); + } window.setTimeout(function () { dialog.dialog('destroy'); }, 1); } }).closest('.ui-dialog').children('.ui-dialog-titlebar').css('border-bottom', 'none'); + const video = dialog.find('video')[0]; - var dialogButtons = [{ - text: 'Capture', - click: captureImage - }]; + navigator.mediaDevices + .getUserMedia({ + audio: false, + video: { + width: { ideal: 1080 }, + height: { ideal: 720 }, + facingMode: 'environment' + } + }) + .then(stream => { + mediaStream = stream; + video.srcObject = stream; + video.play(); + }) + .catch(err => { + console.error(err); + dialog.dialog('destroy'); + }); - // Capturing - function captureImage() { - var dataUri = Webcam.snap(); - self._uploadImage(dataUri); - } - Webcam.set({ - width: mediaWidth, - height: mediaHeight, - dest_width: mediaWidth * 1.5, - dest_height: mediaHeight * 1.5, - jpeg_quality: 95 - }); - Webcam.setSWFLocation('/ClientSource/Scripts/Modules/Disco-AttachmentUploader/webcam.swf'); - Webcam.on('error', function (error) { - alert(error); - dialog.dialog('close'); - }); - Webcam.on('live', function () { - dialog.dialog('option', 'buttons', dialogButtons); - dialog.closest('.ui-dialog') - .children('.ui-dialog-buttonpane') - .css('margin-top', 0) - .find('.ui-button:first').focus(); - }); - Webcam.attach(dialog.attr('id')); + video.addEventListener('canplay', ev => { + if (!videoStreaming) { + const width = 720; + let height = video.videoHeight / (video.videoWidth / width); + if (isNaN(height)) { + height = 405; + } + video.setAttribute('width', width); + video.setAttribute('height', height); + videoStreaming = true; + dialog.dialog('option', 'buttons', [{ + text: 'Capture', + click: () => { + const canvas = document.createElement('canvas'); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + const context = canvas.getContext('2d'); + context.drawImage(video, 0, 0); + canvas.toBlob(blob => { + self._uploadImage(blob); + }, 'image/jpg'); + } + }]); + dialog.css('height', ''); + dialog.closest('.ui-dialog') + .children('.ui-dialog-buttonpane') + .css('margin-top', 0) + .find('.ui-button:first').focus(); + } + }) }; // #endregion @@ -1248,28 +217,18 @@ else { }); }; - self._uploadImage = function (dataUri) { - - if (self._hideFlashVideoOverlay()) - $('#webcam_movie_obj, #webcam_movie_embed').css('display', 'none'); - - var imageData = dataUri.replace(/^data\:image\/\w+\;base64\,/, ''); - - var imageBlob = new Blob([Webcam.base64DecToArr(imageData)], { type: 'image/jpeg' }); - + self._uploadImage = function (blob) { var fileName = 'CapturedImage-' + moment().format('YYYYMMDD-HHmmss') + '.jpg'; self.getFileComments(fileName, function (img) { + const dataUri = URL.createObjectURL(blob); img.attr('src', dataUri); return true; }, function (result, comments) { - if (self._hideFlashVideoOverlay()) - $('#webcam_movie_obj, #webcam_movie_embed').css('display', ''); - if (!result) return; - self._uploadFile(imageBlob, fileName, comments); + self._uploadFile(blob, fileName, comments); }); }; @@ -1329,23 +288,6 @@ else { }; // #endregion - // Flash Video hides Dom elements (comment dialog) in <= Win7 - self.__hideFlashVideoOverlay = null; - self._hideFlashVideoOverlay = function () { - if (self.__hideFlashVideoOverlay === null) { - self.__hideFlashVideoOverlay = false; - - // Test for: <= Windows 7 - try { - var match = /(windows nt) ([\w.]+)/.exec(navigator.userAgent.toLowerCase()); - if (!!match && parseFloat(match[2]) <= 6.2) - self.__hideFlashVideoOverlay = true; - } catch (e) { } - } - - return self.__hideFlashVideoOverlay; - } - return self; }; @@ -1354,4 +296,4 @@ else { } document.Disco.AttachmentUploader = attachmentUploader; -}(this, document, $, Webcam)); \ No newline at end of file +}(this, document, $)); \ No newline at end of file diff --git a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.min.js b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.min.js index 21ddc099..d0baa391 100644 --- a/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.min.js +++ b/Disco.Web/ClientSource/Scripts/Modules/Disco-AttachmentUploader.min.js @@ -1 +1 @@ -(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 ICT 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(n,t,i){"use strict";var r=function(r,u,f){var e=this;if(e.uploadUrl=r,e.dropTarget=u,e.uploadProgressContainer=f,e._uploadFilesInput=null,e.uploadFiles=function(){!e._uploadFilesInput||e._uploadFilesInput.remove();e._uploadFilesInput=i("");e._uploadFilesInput.attr({type:"file",multiple:"multiple",title:"Disco ICT File Uploading"}).hide().change(function(n){var t=n.target.files;!!t&&t.length>0&&e._uploadFiles(t);e._uploadFilesInput.remove()}).appendTo(e.uploadProgressContainer).click()},!!e.dropTarget){var h=i(t),o=!1,s=null;h.on("dragover",function(){e.dropTarget.addClass("dragHighlight");e.dropTarget.removeClass("dragHover");o=!1});h.on("dragleave",function(){!s||n.clearInterval(s);o=!0;n.setTimeout(function(){o&&e.dropTarget.removeClass("dragHighlight");s=null},200)});e.dropTarget.on("dragover",function(n){n.stopPropagation();n.preventDefault();e.dropTarget.addClass("dragHover");o=!1;n.originalEvent.dataTransfer.dropEffect="copy"});e.dropTarget.on("drop",function(n){n.stopPropagation();n.preventDefault();o=!0;e.dropTarget.removeClass("dragHighlight");var t=n.originalEvent.dataTransfer.files;e._uploadFiles(t)})}return e.uploadImage=function(){let f=null,o=!1;var u=i("