element!
*************************************************************/
class VideoInput extends HTMLElement {
constructor() {
/*
* Constructor! Default values!
*/
super();
this._isRecording = false;
this._mediablob = [];
this._allblobs = []
this._width = 640;
this._height = 480;
this._labelloc = "bottom";
this._label = "";
this._posturl = "";
this._maxtime = 0;
this._timercounter = 0;
this._interval = 0;
}
static get observedAttributes() { return ["vidwidth", "vidheight", "labelloc", "label", "action", "maxtime"]; }
attributeChangedCallback(name, oldValue, newValue) {
/*
* Saves attributes.
*/
if (name === "vidwidth") {
this._width = newValue;
} else if (name === "vidheight") {
this._height = newValue;
} else if (name === "labelloc") {
if (newValue === "top" | newValue === "bottom" | newValue === "hidden") {
this._labelloc = newValue;
}
} else if (name === "label") {
this._label = newValue;
} else if (name === "action") {
this._posturl = newValue;
} else if (name === "maxtime") {
this._maxtime = newValue;
}
this._updateRendering();
}
startTimer() {
/*
* Starts the timer *if* we are giving videos a time limit.
*/
if (this._maxtime > 0) {
timerid = this.id
timercount = 0;
timermaxtime = this._maxtime;
intervaltracker = setInterval(timerstep, 1000);
}
}
resetTimerLabel() {
/*
* Resets the timer label. This gets called when we complete a recording.
*/
this._updateRendering()
}
connectedCallback() {
this._updateRendering();
}
updateLabel(labeltext) {
/*
* Updates the label above/below the video field.
*/
let gvlabel = document.querySelector("#" + this.id + "label");
gvlabel.innerHTML = labeltext;
}
async submit() {
/*
* Submits the video as a POST request. Note that buttons become disabled
* when this happens as the form has effectively been submitted, albeit
* asynchronously.
*/
// Disables buttons; commented out disabling "download" based on user feedback.
//let gvbutton1 = document.querySelector("#" + this.id + "download")
let gvbutton2 = document.querySelector("#" + this.id + "play")
let gvbutton3 = document.querySelector("#" + this.id + "submit")
let gvbutton4 = document.querySelector("#" + this.id + "recordbutton")
//gvbutton1.disabled = true;
gvbutton2.disabled = true;
gvbutton3.disabled = true;
gvbutton4.disabled = true;
// Creates a FormData objects and includes the file name (based on the
// video-input element's ID) and adds the recording as a file.
var fd = new FormData();
const blob = new Blob(this._allblobs, {type: 'video/webm'});
fd.append('fname', this.id + '.webm');
fd.append('data', blob);
const xhr = new XMLHttpRequest();
xhr.open('POST', this._posturl);
xhr.send(fd);
// Updates the form field to say we're uploading the file.
this.updateLabel("Uploading response... This can take a few minutes.");
// Once the file is uplaoded, we update the label.
xhr.onload = () => {
console.log(xhr.responseText);
this.updateLabel("Upload complete! Thank you.")
}
}
async initializeRecording() {
/*
* Initialize the recording.
*/
try {
let constraints = getConstraints(this._width, this._height);
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleSuccess(stream, "#gum" + this.id);
this.isRecording = true;
this.startTimer();
} catch (e) {
console.error('navigator.getUserMedia error:', e);
}
}
saveBlob(blob) {
/*
* Saves the recording from the global scope to the element itself.
*/
this._mediablob = blob;
}
saveBlobArrays(blobs) {
/*
* Saves the recording from the global scope to the element itself.
*/
this._allblobs = blobs;
}
async downloadblob() {
/*
* Enables you to download the blob as a "webm" file.
*/
const blob = new Blob(this._allblobs, {type: 'video/webm'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = this.id + '.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
}
getBlob() {
/*
* Access the blob.
*/
return this._mediablob;
}
getAllBlobs() {
/*
* Access the blobs.
*/
return this._allblobs;
}
deleteRecording() {
/*
* Clears the blobs from memory. We don't currently use this.
*/
this._mediablob = [];
this._allblobs = [];
playRec(this.id);
}
_updateRendering() {
let innhtml = "• recording
";
let form_field_label = "" + this._label + ""
if (this._maxtime > 0) {
form_field_label += "
Max Time: " + this._maxtime + " seconds";
}
let button_row = ""
if (this._labelloc !== "hidden") {
if (this._labelloc === "top") {
innhtml = "" + form_field_label + "
" + button_row + "
" + innhtml
} else {
innhtml = innhtml + "" + form_field_label + "
" + button_row + "
"
}
}
this.innerHTML = innhtml;
}
}
customElements.define('video-input', VideoInput);
================================================
FILE: videostyle.css
================================================
video {
background:black;
padding:0px;
margin:0px;
}
.videofieldlabel {
color:black;
/*background:black;*/
padding:0px;
margin:0px;
margin-bottom:10px;
}
video-input button {
margin-top:10px;
margin-right:5px;
border:1px solid gray;
padding:5px;
border-radius:3px;
min-width:100px;
}
.recordersign {
background:white;
position:relative;
top:25px;
left:5px;
font-family:arial;
font-size:10px;
margin-top:-20px;
border-radius:3px;
padding:3px;
width:70px;
visibility:hidden;
}