{"version":3,"file":"utils_amd.min.js","sources":["../src/utils_amd.js"],"sourcesContent":["/* jshint ignore:start */\ndefine(['jquery', 'core/log'], function ($, log) {\n\n    \"use strict\"; // jshint ;_;\n\n    log.debug('Filter PoodLL: utils initialising');\n\n    return {\n        timeouthandles: [],\n\n        // Call Upload file from drawingboard a, first handle autosave bits and pieces\n        WhiteboardUploadHandler: function (recid, wboard, opts, theuploader) {\n            // Save button disabling a little risky db perm. fails publish \"startdrawing\" after mode change\n            var savebutton = $('#' + recid + '_btn_upload_whiteboard')[0];\n            savebutton.disabled = true;\n            clearTimeout(this.timeouthandles[recid]);\n            //call the file upload\n            var cvs = this.getCvs(recid, wboard, opts);\n            this.pokeVectorData(recid, wboard, opts);\n            theuploader.uploadFile(cvs.toDataURL(), 'image/png');\n        },\n        getCvs: function (recid, wboard) {\n            if (recid.indexOf('drawingboard_') == 0) {\n                var cvs = wboard.canvas;\n            } else {\n                var cvs = wboard.canvasForExport();\n            }//end of of drawing board\n            return cvs;\n        },\n\n        escapeColon: function (thestring) {\n            return thestring.replace(/:/, '\\\\:');\n        },\n\n        pokeVectorData: function (recid, wboard, opts) {\n            var vectordata = \"\";\n\n            if (recid.indexOf('drawingboard_') == 0) {\n                var historyCopy = JSON.parse(JSON.stringify(wboard.history));\n                var historytosave = this.trimDrawingBoardHistory(historyCopy);\n                vectordata = JSON.stringify(historytosave, null, 2);\n            } else {\n                //only LC has vector data it seems\n                vectordata = JSON.stringify(wboard.getSnapshot());\n            }//end of if drawing board\n\n            //need to do the poke here\n            if (typeof opts['vectorcontrol'] !== 'undefined' && opts['vectorcontrol'] !== '') {\n                //the moodle question has a colon in the field ids, so we need to escape that away\n                $('#' + this.escapeColon(opts['vectorcontrol'])).val(vectordata);\n                log.debug('Vectorcontrol:' + opts['vectorcontrol']);\n                //  log.debug('Vectordata:' + vectordata );\n            }\n            //end of poke vectordata\n        },\n\n        // Function to ensure vectordata size is less than 16MB before we stringify it\n        // This ensures it can be stored in a mysql medium TEXT field without truncation\n        // and a little bit of room for meta data etc, and also goes under\n        // MySQL default max packet size: 64MB\n        trimDrawingBoardHistory: function(history) {\n\n            // Keep removing base64 images from the beginning until size is under 64mb\n            while (JSON.stringify(history, null, 2).length > 15 * 1024 * 1024) {\n                if (history.values.length > 0) {\n                    history.values.shift(); // Remove the first base64 image\n                } else {\n                    break; // Stop if there are no more images to remove\n                }\n            }\n            // Reset the position to the final position (since values array may be trimmed)\n            history.position = history.values.length;\n\n            // Return the trimmed history\n            return history;\n        },\n\n        _concatenateWavBlobs: function (blobs, callback) {\n\n\n\n            //fetch our header\n            var self=this;\n            var allbytes = []; //this will be an array of arraybuffers\n            var loadedblobs = 0;\n            var totalbytes = 0;\n            // fetch the blob data\n            var lng = blobs.length;\n            for (var i = 0; i < lng; i++) {\n                //we run the filereader inside an an immediately executing function\n                //so that we can keep track of the index of the blob being read.\n                //in edge and IE they all get read simulatenously and the order of concatenation\n                //could not be relied on with : allbytes.push(audiodata); so we did: allbytes[index]=audiodata;\n                (function (index) {\n                    var fileReader = new FileReader();\n                    fileReader.onload = function () {\n                        //load blob into arraybuffer\n                        var ab = this.result;\n\n                        //remove header and add audiodata to the all data array\n                        //the slice is from(inclusive) to end(exclusive)\n                        var audiodata = ab.slice(44);\n                        totalbytes += audiodata.byteLength;\n                        //allbytes.push(audiodata);\n                        allbytes[index] = audiodata;\n                        loadedblobs++;\n\n                        //finally add the header and do callback if at end\n                        if (loadedblobs == lng) {\n                            //get header from last blob, and just adjust the data length\n                            var header = ab.slice(0, 44);\n                            var headerview = new DataView(header);\n                            headerview.setUint32(40, totalbytes, true);\n                            allbytes.unshift(header);\n\n                            //make our final binary blob and pass it to callback\n                            var wavblob = new Blob(allbytes, {type: 'audio/wav'});\n                            log.debug(totalbytes);\n                            log.debug(allbytes);\n                            callback(wavblob);\n                        }\n                    };\n                    fileReader.readAsArrayBuffer(blobs[i]);\n                })(i);\n\n            }//end of i loop\n\n        }, //end of concatenateWavBlobs\n\n\n\n        _simpleConcatenateBlobs: function (blobs, type) {\n            return new Blob(blobs, {'type': type});\n        },\n\n        doConcatenateBlobs: function (theblobs, thecallback) {\n           // var mimetype = 'audio/ogg';\n            //can be of format: \"audio/ogg; codecs=opus\"\n            //still works though\n           var mimetype =theblobs[0].type;\n            switch (mimetype) {\n                case 'audio/wav':\n                case 'audio/pcm':\n                    // mediastreamrecorder adds a header to each wav blob,\n                    // we remove them and combine audiodata and new header\n                    this._concatenateWavBlobs(theblobs, thecallback);\n                    break;\n                case 'audio/ogg':\n                case 'audio/webm':\n                case 'video/webm':\n                case 'video/mp4':\n                case 'audio/mp4':\n                case 'audio/mp3':\n                case 'audio/m4a':\n                default:\n                    var concatenatedBlob = this._simpleConcatenateBlobs(theblobs, mimetype);\n                    thecallback(concatenatedBlob);\n                    break;\n            }// end of switch case\n        },\n\n\n        bytesToSize: function (bytes) {\n            var k = 1000;\n            var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n            if (bytes === 0) {\n                return '0 Bytes';\n            }\n            var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10);\n            return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];\n        },\n\n        // below function via: http://goo.gl/6QNDcI\n        getTimeLength: function (milliseconds) {\n            var data = new Date(milliseconds);\n            return data.getUTCHours() + \" hours, \" + data.getUTCMinutes() + \" minutes and \" + data.getUTCSeconds() + \" second(s)\";\n        },\n\n        has_mediarecorder: function(){\n          return typeof MediaRecorder !== 'undefined';\n        },\n\n        can_html5_record: function(mediatype){\n          if( navigator && navigator.mediaDevices\n            && navigator.mediaDevices.getUserMedia){\n              if(mediatype=='audio'){\n                  return true;\n              }else{\n                  return this.has_mediarecorder();\n              }\n          }else{\n              return false;\n          }\n        },\n\n        is_edge: function () {\n            return navigator.userAgent.indexOf('Edge') > -1;\n        },\n\n        is_chrome: function () {\n            var isChromium = window.chrome,\n                winNav = window.navigator,\n                vendorName = winNav.vendor,\n                isOpera = winNav.userAgent.indexOf(\"OPR\") > -1,\n                isIEedge = winNav.userAgent.indexOf(\"Edge\") > -1,\n                isIOSChrome = winNav.userAgent.match(\"CriOS\");\n\n            if (isIOSChrome) {\n                return true;\n            } else if (\n                isChromium !== null &&\n                typeof isChromium !== \"undefined\" &&\n                vendorName === \"Google Inc.\" &&\n                isOpera === false &&\n                isIEedge === false\n            ) {\n                return true;\n            } else {\n                return false;\n            }\n        },\n\n        is_safari: function () {\n            return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n        },\n\n        is_ios: function () {\n            return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n        },\n\n        is_opera: function () {\n            return (typeof opera !== 'undefined' && navigator.userAgent && navigator.userAgent.indexOf('OPR/') !== -1);\n        },\n\n        is_android: function () {\n            var ua = window.navigator.userAgent;\n            var isAndroid = (ua.indexOf(\"android\") > -1) || (ua.indexOf(\"Android\") > -1); //&& ua.indexOf(\"mobile\");\n            return isAndroid;\n        },\n\n        is_ie: function () {\n            var ms_ie = false;\n            var ua = window.navigator.userAgent;\n            var old_ie = ua.indexOf('MSIE ');\n            var new_ie = ua.indexOf('Trident/');\n            var edge = ua.indexOf('Edge/');\n            if ((old_ie > -1) || (new_ie > -1) || (edge > -1)) {\n                ms_ie = true;\n            }\n            return ms_ie;\n        },\n\n        parseQueryString: function (url) {\n            var urlParams = {};\n            url.replace(\n                new RegExp(\"([^?=&]+)(=([^&]*))?\", \"g\"),\n                function ($0, $1, $2, $3) {\n                    urlParams[$1] = $3;\n                }\n            );\n\n            return urlParams;\n        }\n    };//end of return object\n});"],"names":["define","$","log","debug","timeouthandles","WhiteboardUploadHandler","recid","wboard","opts","theuploader","disabled","clearTimeout","this","cvs","getCvs","pokeVectorData","uploadFile","toDataURL","indexOf","canvas","canvasForExport","escapeColon","thestring","replace","vectordata","historyCopy","JSON","parse","stringify","history","historytosave","trimDrawingBoardHistory","getSnapshot","val","length","values","shift","position","_concatenateWavBlobs","blobs","callback","allbytes","loadedblobs","totalbytes","lng","i","index","fileReader","FileReader","onload","ab","result","audiodata","slice","byteLength","header","DataView","setUint32","unshift","wavblob","Blob","type","readAsArrayBuffer","_simpleConcatenateBlobs","doConcatenateBlobs","theblobs","thecallback","mimetype","bytesToSize","bytes","parseInt","Math","floor","pow","toPrecision","getTimeLength","milliseconds","data","Date","getUTCHours","getUTCMinutes","getUTCSeconds","has_mediarecorder","MediaRecorder","can_html5_record","mediatype","navigator","mediaDevices","getUserMedia","is_edge","userAgent","is_chrome","isChromium","window","chrome","winNav","vendorName","vendor","isOpera","isIEedge","match","is_safari","test","is_ios","MSStream","is_opera","opera","is_android","ua","is_ie","ms_ie","old_ie","new_ie","edge","parseQueryString","url","urlParams","RegExp","$0","$1","$2","$3"],"mappings":"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"}