From 6a374979b42a9b43121f7d2acc62b58392173058 Mon Sep 17 00:00:00 2001 From: Thomas O Fredericks Date: Tue, 15 Aug 2017 15:49:54 -0400 Subject: [PATCH] Websockets! --- .../AsciiMassagePacker.pde | 2 +- .../Websocket Client(p5.js)/index.html | 20 + .../libraries/AsciiMassagePacker.js | 91 + .../libraries/AsciiMassageParser.js | 101 + .../libraries/p5.dom.js | 2153 + .../Websocket Client(p5.js)/libraries/p5.js | 33029 ++++++++++++++++ .../libraries/p5.sound.js | 9244 +++++ .../Websocket Client(p5.js)/sketch.js | 77 + .../AsciiMassenger_basic.ino | 4 +- .../AsciiMassenger_basic_UDP.ino | 2 +- .../AsciiMassenger_basic_websocket_server.ino | 133 + .../esp8266AP.h | 22 + library.properties | 2 +- 13 files changed, 44875 insertions(+), 5 deletions(-) create mode 100644 applications/Websocket Client(p5.js)/index.html create mode 100644 applications/Websocket Client(p5.js)/libraries/AsciiMassagePacker.js create mode 100644 applications/Websocket Client(p5.js)/libraries/AsciiMassageParser.js create mode 100644 applications/Websocket Client(p5.js)/libraries/p5.dom.js create mode 100644 applications/Websocket Client(p5.js)/libraries/p5.js create mode 100644 applications/Websocket Client(p5.js)/libraries/p5.sound.js create mode 100644 applications/Websocket Client(p5.js)/sketch.js create mode 100644 examples/AsciiMassenger_basic_websocket_server/AsciiMassenger_basic_websocket_server.ino create mode 100644 examples/AsciiMassenger_basic_websocket_server/esp8266AP.h diff --git a/applications/Processing/AsciiMassage_Processing/AsciiMassagePacker.pde b/applications/Processing/AsciiMassage_Processing/AsciiMassagePacker.pde index 53c83ed..45866ae 100644 --- a/applications/Processing/AsciiMassage_Processing/AsciiMassagePacker.pde +++ b/applications/Processing/AsciiMassage_Processing/AsciiMassagePacker.pde @@ -12,7 +12,7 @@ class AsciiMassagePacker { // Returns a reference to the buffer. byte[] buffer() { - if ( !ended ) println("Warning: betting the buffer of an unended packet!"); + if ( !ended ) println("Warning: getting the buffer of an unended packet!"); return internalString.getBytes(); } diff --git a/applications/Websocket Client(p5.js)/index.html b/applications/Websocket Client(p5.js)/index.html new file mode 100644 index 0000000..f83aa9f --- /dev/null +++ b/applications/Websocket Client(p5.js)/index.html @@ -0,0 +1,20 @@ + + + + + AsciiMassage Websockets + + + + + + + + + + + + + + + diff --git a/applications/Websocket Client(p5.js)/libraries/AsciiMassagePacker.js b/applications/Websocket Client(p5.js)/libraries/AsciiMassagePacker.js new file mode 100644 index 0000000..d9dfd6b --- /dev/null +++ b/applications/Websocket Client(p5.js)/libraries/AsciiMassagePacker.js @@ -0,0 +1,91 @@ +function AsciiMassagePacker() { + + this._messageSize; + this._internalString = ""; + this._ended = false; + + /// Returns size of buffer. + this.size = function() { + return this._internalString.length(); + } + + // Returns a reference to the buffer. + this.buffer = function() { + if ( this.ended == false ) console.log("Warning: getting the buffer of an unended packet!"); + return this._internalString; + } + + /// Begins the sending of a message. + this.beginPacket = function(address) { + this._internalString = address; + this._ended = false; + } + + /// Adds a byte. + this.addByte = function(value) { + this._internalString = this._internalString +" " + value; + } + + /// Adds an int. + this.addInt = function(value) { + this._internalString = this._internalString +" " + value; + } + + /// Adds a long. + this.addLong = function(value) { + this._internalString = this._internalString +" " + value; + } + + /// Adds a float. + this.addFloat = function(value) { + this._internalString = this._internalString +" " + value; + } + + /// Ends the sending of a message. + this.endPacket = function() { + this._internalString += '\n'; + this._ended = true; + } + + /// Create a packet with no arguments. + this.packEmpty = function(address) + { + this.beginPacket(address); + this.endPacket(); + } + + /// Create a packet with a single byte value. + this.packOneByte = function( address, value) + { + this.beginPacket(address); + this.addByte(value); + this.endPacket(); + } + + /// Create a packet with a single int value. + this.packOneInt = function( address, value) + { + this.beginPacket(address); + this.addInt(value); + this.endPacket(); + } + + /// Create a packet with a single long value. + this.packOneLong = function( address, value) + { + this.beginPacket(address); + this.addLong(value); + this.endPacket(); + } + + /// Create a packet with a single float value. + this.packOneFloat = function( address, value) + { + this.beginPacket(address); + this.addFloat(value); + this.endPacket(); + } + + + +} \ No newline at end of file diff --git a/applications/Websocket Client(p5.js)/libraries/AsciiMassageParser.js b/applications/Websocket Client(p5.js)/libraries/AsciiMassageParser.js new file mode 100644 index 0000000..0cf3a32 --- /dev/null +++ b/applications/Websocket Client(p5.js)/libraries/AsciiMassageParser.js @@ -0,0 +1,101 @@ + + +function AsciiMassageParser() { + + + this._flush = function() { + this._needToFlush = false; + this._receivedDataIndex = 0; + this._internalString = new Array(); + this._currentWord = 0; + this._ready = false; + this._words = null; + } + + this._flush(); + + this.parse = function ( data , callback = null ) { + + + + if ( this._needToFlush || this._receivedDataIndex > 1024 ) { + this._flush(); + } + + if ( data == '\n' ) { + + this._needToFlush = true; + if ( this._receivedDataIndex > 0 ) { + this._words = this._internalString.split(" "); + this._ready = true; + this._currentWord = 1; + + if ( callback != null ) callback(); + return true; + } + + } else { + this._internalString += data; + this._receivedDataIndex++; + } + return false; + } + + + this._isReady = function() { + + if ( this._ready && this._currentWord < this._words.length ) { + return true; + } else { + return false; + } + } + + this.fullMatch = function( address ) { + if ( this._isReady() && this._words[0] == address ) { + return true; + } + return false; + } + + this.nextByte = function() { + + if ( this._isReady() ) { + var data = parseInt(this._words[this._currentWord]); + this._currentWord++; + return data; + } + return 0; + } + + this.nextInt = function() { + + if ( this._isReady() ) { + var data = parseInt(this._words[this._currentWord]); + this._currentWord++; + return data; + } + return 0; + } + + this.nextFloat = function() { + + if ( this._isReady() ) { + var data = parseFloat(this._words[this._currentWord]); + this._currentWord++; + return data; + } + return 0; + } + + this.nextLong = function() { + + if ( this._isReady() ) { + var data = parseInt(this._words[this._currentWord]); + this._currentWord++; + return data; + } + return 0; + } + +} \ No newline at end of file diff --git a/applications/Websocket Client(p5.js)/libraries/p5.dom.js b/applications/Websocket Client(p5.js)/libraries/p5.dom.js new file mode 100644 index 0000000..5e7a343 --- /dev/null +++ b/applications/Websocket Client(p5.js)/libraries/p5.dom.js @@ -0,0 +1,2153 @@ +/*! p5.dom.js v0.2.13 Oct 1, 2016 */ +/** + *

The web is much more than just canvas and p5.dom makes it easy to interact + * with other HTML5 objects, including text, hyperlink, image, input, video, + * audio, and webcam.

+ *

There is a set of creation methods, DOM manipulation methods, and + * an extended p5.Element that supports a range of HTML elements. See the + * + * beyond the canvas tutorial for a full overview of how this addon works. + * + *

Methods and properties shown in black are part of the p5.js core, items in + * blue are part of the p5.dom library. You will need to include an extra file + * in order to access the blue functions. See the + * using a library + * section for information on how to include this library. p5.dom comes with + * p5 complete or you can download the single file + * + * here.

+ *

See tutorial: beyond the canvas + * for more info on how to use this libary. + * + * @module p5.dom + * @submodule p5.dom + * @for p5.dom + * @main + */ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) + define('p5.dom', ['p5'], function (p5) { (factory(p5));}); + else if (typeof exports === 'object') + factory(require('../p5')); + else + factory(root['p5']); +}(this, function (p5) { +// ============================================================================= +// p5 additions +// ============================================================================= + + /** + * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.' + * prefixes to specify an ID or class respectively, and none for a tag) and returns it as + * a p5.Element. If a class or tag name is given with more than 1 element, + * only the first element will be returned. + * The DOM node itself can be accessed with .elt. + * Returns null if none found. You can also specify a container to search within. + * + * @method select + * @param {String} name id, class, or tag name of element to search for + * @param {String} [container] id, p5.Element, or HTML element to search within + * @return {Object/p5.Element|Null} p5.Element containing node found + * @example + *

+ * function setup() { + * createCanvas(100,100); + * //translates canvas 50px down + * select('canvas').position(100, 100); + * } + *
+ *
+ * // these are all valid calls to select() + * var a = select('#moo'); + * var b = select('#blah', '#myContainer'); + * var c = select('#foo', b); + * var d = document.getElementById('beep'); + * var e = select('p', d); + *
+ * + */ + p5.prototype.select = function (e, p) { + var res = null; + var container = getContainer(p); + if (e[0] === '.'){ + e = e.slice(1); + res = container.getElementsByClassName(e); + if (res.length) { + res = res[0]; + } else { + res = null; + } + }else if (e[0] === '#'){ + e = e.slice(1); + res = container.getElementById(e); + }else { + res = container.getElementsByTagName(e); + if (res.length) { + res = res[0]; + } else { + res = null; + } + } + if (res) { + return wrapElement(res); + } else { + return null; + } + }; + + /** + * Searches the page for elements with the given class or tag name (using the '.' prefix + * to specify a class and no prefix for a tag) and returns them as p5.Elements + * in an array. + * The DOM node itself can be accessed with .elt. + * Returns an empty array if none found. + * You can also specify a container to search within. + * + * @method selectAll + * @param {String} name class or tag name of elements to search for + * @param {String} [container] id, p5.Element, or HTML element to search within + * @return {Array} Array of p5.Elements containing nodes found + * @example + *
+ * function setup() { + * createButton('btn'); + * createButton('2nd btn'); + * createButton('3rd btn'); + * var buttons = selectAll('button'); + * + * for (var i = 0; i < buttons.length; i++){ + * buttons[i].size(100,100); + * } + * } + *
+ *
+ * // these are all valid calls to selectAll() + * var a = selectAll('.moo'); + * var b = selectAll('div'); + * var c = selectAll('button', '#myContainer'); + * var d = select('#container'); + * var e = selectAll('p', d); + * var f = document.getElementById('beep'); + * var g = select('.blah', f); + *
+ * + */ + p5.prototype.selectAll = function (e, p) { + var arr = []; + var res; + var container = getContainer(p); + if (e[0] === '.'){ + e = e.slice(1); + res = container.getElementsByClassName(e); + } else { + res = container.getElementsByTagName(e); + } + if (res) { + for (var j = 0; j < res.length; j++) { + var obj = wrapElement(res[j]); + arr.push(obj); + } + } + return arr; + }; + + /** + * Helper function for select and selectAll + */ + function getContainer(p) { + var container = document; + if (typeof p === 'string' && p[0] === '#'){ + p = p.slice(1); + container = document.getElementById(p) || document; + } else if (p instanceof p5.Element){ + container = p.elt; + } else if (p instanceof HTMLElement){ + container = p; + } + return container; + } + + /** + * Helper function for getElement and getElements. + */ + function wrapElement(elt) { + if(elt.tagName === "INPUT" && elt.type === "checkbox") { + var converted = new p5.Element(elt); + converted.checked = function(){ + if (arguments.length === 0){ + return this.elt.checked; + } else if(arguments[0]) { + this.elt.checked = true; + } else { + this.elt.checked = false; + } + return this; + }; + return converted; + } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") { + return new p5.MediaElement(elt); + } else { + return new p5.Element(elt); + } + } + + /** + * Removes all elements created by p5, except any canvas / graphics + * elements created by createCanvas or createGraphics. + * Event handlers are removed, and element is removed from the DOM. + * @method removeElements + * @example + *
+ * function setup() { + * createCanvas(100, 100); + * createDiv('this is some text'); + * createP('this is a paragraph'); + * } + * function mousePressed() { + * removeElements(); // this will remove the div and p, not canvas + * } + *
+ * + */ + p5.prototype.removeElements = function (e) { + for (var i=0; i + * var myDiv; + * function setup() { + * myDiv = createDiv('this is some text'); + * } + * + */ + + /** + * Creates a <p></p> element in the DOM with given inner HTML. Used + * for paragraph length text. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createP + * @param {String} html inner HTML for element created + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var myP; + * function setup() { + * myP = createP('this is some text'); + * } + *
+ */ + + /** + * Creates a <span></span> element in the DOM with given inner HTML. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createSpan + * @param {String} html inner HTML for element created + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var mySpan; + * function setup() { + * mySpan = createSpan('this is some text'); + * } + *
+ */ + var tags = ['div', 'p', 'span']; + tags.forEach(function(tag) { + var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1); + p5.prototype[method] = function(html) { + var elt = document.createElement(tag); + elt.innerHTML = typeof html === undefined ? "" : html; + return addElement(elt, this); + } + }); + + /** + * Creates an <img /> element in the DOM with given src and + * alternate text. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createImg + * @param {String} src src path or url for image + * @param {String} [alt] alternate text to be used if image does not load + * @param {Function} [successCallback] callback to be called once image data is loaded + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var img; + * function setup() { + * img = createImg('http://p5js.org/img/asterisk-01.png'); + * } + *
+ */ + p5.prototype.createImg = function() { + var elt = document.createElement('img'); + var args = arguments; + var self; + var setAttrs = function(){ + self.width = elt.offsetWidth; + self.height = elt.offsetHeight; + if (args.length > 1 && typeof args[1] === 'function'){ + self.fn = args[1]; + self.fn(); + }else if (args.length > 1 && typeof args[2] === 'function'){ + self.fn = args[2]; + self.fn(); + } + }; + elt.src = args[0]; + if (args.length > 1 && typeof args[1] === 'string'){ + elt.alt = args[1]; + } + elt.onload = function(){ + setAttrs(); + } + self = addElement(elt, this); + return self; + }; + + /** + * Creates an <a></a> element in the DOM for including a hyperlink. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createA + * @param {String} href url of page to link to + * @param {String} html inner html of link element to display + * @param {String} [target] target where new link should open, + * could be _blank, _self, _parent, _top. + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var myLink; + * function setup() { + * myLink = createA('http://p5js.org/', 'this is a link'); + * } + *
+ */ + p5.prototype.createA = function(href, html, target) { + var elt = document.createElement('a'); + elt.href = href; + elt.innerHTML = html; + if (target) elt.target = target; + return addElement(elt, this); + }; + + /** INPUT **/ + + + /** + * Creates a slider <input></input> element in the DOM. + * Use .size() to set the display length of the slider. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createSlider + * @param {Number} min minimum value of the slider + * @param {Number} max maximum value of the slider + * @param {Number} [value] default value of the slider + * @param {Number} [step] step size for each tick of the slider (if step is set to 0, the slider will move continuously from the minimum to the maximum value) + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var slider; + * function setup() { + * slider = createSlider(0, 255, 100); + * slider.position(10, 10); + * slider.style('width', '80px'); + * } + * + * function draw() { + * var val = slider.value(); + * background(val); + * } + *
+ * + *
+ * var slider; + * function setup() { + * colorMode(HSB); + * slider = createSlider(0, 360, 60, 40); + * slider.position(10, 10); + * slider.style('width', '80px'); + * } + * + * function draw() { + * var val = slider.value(); + * background(val, 100, 100, 1); + * } + *
+ */ + p5.prototype.createSlider = function(min, max, value, step) { + var elt = document.createElement('input'); + elt.type = 'range'; + elt.min = min; + elt.max = max; + if (step === 0) { + elt.step = .000000000000000001; // smallest valid step + } else if (step) { + elt.step = step; + } + if (typeof(value) === "number") elt.value = value; + return addElement(elt, this); + }; + + /** + * Creates a <button></button> element in the DOM. + * Use .size() to set the display size of the button. + * Use .mousePressed() to specify behavior on press. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createButton + * @param {String} label label displayed on the button + * @param {String} [value] value of the button + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var button; + * function setup() { + * createCanvas(100, 100); + * background(0); + * button = createButton('click me'); + * button.position(19, 19); + * button.mousePressed(changeBG); + * } + * + * function changeBG() { + * var val = random(255); + * background(val); + * } + *
+ */ + p5.prototype.createButton = function(label, value) { + var elt = document.createElement('button'); + elt.innerHTML = label; + elt.value = value; + if (value) elt.value = value; + return addElement(elt, this); + }; + + /** + * Creates a checkbox <input></input> element in the DOM. + * Calling .checked() on a checkbox returns if it is checked or not + * + * @method createCheckbox + * @param {String} [label] label displayed after checkbox + * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var checkbox; + * + * function setup() { + * checkbox = createCheckbox('label', false); + * checkbox.changed(myCheckedEvent); + * } + * + * function myCheckedEvent() { + * if (this.checked()) { + * console.log("Checking!"); + * } else { + * console.log("Unchecking!"); + * } + * } + *
+ */ + p5.prototype.createCheckbox = function() { + var elt = document.createElement('div'); + var checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + elt.appendChild(checkbox); + //checkbox must be wrapped in p5.Element before label so that label appears after + var self = addElement(elt, this); + self.checked = function(){ + var cb = self.elt.getElementsByTagName('input')[0]; + if (cb) { + if (arguments.length === 0){ + return cb.checked; + }else if(arguments[0]){ + cb.checked = true; + }else{ + cb.checked = false; + } + } + return self; + }; + this.value = function(val){ + self.value = val; + return this; + }; + if (arguments[0]){ + var ran = Math.random().toString(36).slice(2); + var label = document.createElement('label'); + checkbox.setAttribute('id', ran); + label.htmlFor = ran; + self.value(arguments[0]); + label.appendChild(document.createTextNode(arguments[0])); + elt.appendChild(label); + } + if (arguments[1]){ + checkbox.checked = true; + } + return self; + }; + + /** + * Creates a dropdown menu <select></select> element in the DOM. + * @method createSelect + * @param {boolean} [multiple] [true if dropdown should support multiple selections] + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var sel; + * + * function setup() { + * textAlign(CENTER); + * background(200); + * sel = createSelect(); + * sel.position(10, 10); + * sel.option('pear'); + * sel.option('kiwi'); + * sel.option('grape'); + * sel.changed(mySelectEvent); + * } + * + * function mySelectEvent() { + * var item = sel.value(); + * background(200); + * text("it's a "+item+"!", 50, 50); + * } + *
+ */ + p5.prototype.createSelect = function(mult) { + var elt = document.createElement('select'); + if (mult){ + elt.setAttribute('multiple', 'true'); + } + var self = addElement(elt, this); + self.option = function(name, value){ + var opt = document.createElement('option'); + opt.innerHTML = name; + if (arguments.length > 1) + opt.value = value; + else + opt.value = name; + elt.appendChild(opt); + }; + self.selected = function(value){ + var arr = []; + if (arguments.length > 0){ + for (var i = 0; i < this.elt.length; i++){ + if (value.toString() === this.elt[i].value){ + this.elt.selectedIndex = i; + } + } + return this; + }else{ + if (mult){ + for (var i = 0; i < this.elt.selectedOptions.length; i++){ + arr.push(this.elt.selectedOptions[i].value); + } + return arr; + }else{ + return this.elt.value; + } + } + }; + return self; + }; + + /** + * Creates a radio button <input></input> element in the DOM. + * The .option() method can be used to set options for the radio after it is + * created. The .value() method will return the currently selected option. + * + * @method createRadio + * @param {String} [divId] the id and name of the created div and input field respectively + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var radio; + * + * function setup() { + * radio = createRadio(); + * radio.option("black"); + * radio.option("white"); + * radio.option("gray"); + * radio.style('width', '60px'); + * textAlign(CENTER); + * fill(255, 0, 0); + * } + * + * function draw() { + * var val = radio.value(); + * background(val); + * text(val, width/2, height/2); + * } + *
+ *
+ * var radio; + * + * function setup() { + * radio = createRadio(); + * radio.option('apple', 1); + * radio.option('bread', 2); + * radio.option('juice', 3); + * radio.style('width', '60px'); + * textAlign(CENTER); + * } + * + * function draw() { + * background(200); + * var val = radio.value(); + * if (val) { + * text('item cost is $'+val, width/2, height/2); + * } + * } + *
+ */ + p5.prototype.createRadio = function() { + var radios = document.querySelectorAll("input[type=radio]"); + var count = 0; + if(radios.length > 1){ + var length = radios.length; + var prev=radios[0].name; + var current = radios[1].name; + count = 1; + for(var i = 1; i < length; i++) { + current = radios[i].name; + if(prev != current){ + count++; + } + prev = current; + } + } + else if (radios.length == 1){ + count = 1; + } + var elt = document.createElement('div'); + var self = addElement(elt, this); + var times = -1; + self.option = function(name, value){ + var opt = document.createElement('input'); + opt.type = 'radio'; + opt.innerHTML = name; + if (arguments.length > 1) + opt.value = value; + else + opt.value = name; + opt.setAttribute('name',"defaultradio"+count); + elt.appendChild(opt); + if (name){ + times++; + var ran = Math.random().toString(36).slice(2); + var label = document.createElement('label'); + opt.setAttribute('id', "defaultradio"+count+"-"+times); + label.htmlFor = "defaultradio"+count+"-"+times; + label.appendChild(document.createTextNode(name)); + elt.appendChild(label); + } + return opt; + }; + self.selected = function(){ + var length = this.elt.childNodes.length; + if(arguments.length == 1) { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].value == arguments[0]) + this.elt.childNodes[i].checked = true; + } + return this; + } else { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].checked == true) + return this.elt.childNodes[i].value; + } + } + }; + self.value = function(){ + var length = this.elt.childNodes.length; + if(arguments.length == 1) { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].value == arguments[0]) + this.elt.childNodes[i].checked = true; + } + return this; + } else { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].checked == true) + return this.elt.childNodes[i].value; + } + return ""; + } + }; + return self + }; + + /** + * Creates an <input></input> element in the DOM for text input. + * Use .size() to set the display length of the box. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createInput + * @param {Number} [value] default value of the input box + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * function setup(){ + * var inp = createInput(''); + * inp.input(myInputEvent); + * } + * + * function myInputEvent(){ + * console.log('you are typing: ', this.value()); + * } + * + *
+ */ + p5.prototype.createInput = function(value) { + var elt = document.createElement('input'); + elt.type = 'text'; + if (value) elt.value = value; + return addElement(elt, this); + }; + + /** + * Creates an <input></input> element in the DOM of type 'file'. + * This allows users to select local files for use in a sketch. + * + * @method createFileInput + * @param {Function} [callback] callback function for when a file loaded + * @param {String} [multiple] optional to allow multiple files selected + * @return {Object/p5.Element} pointer to p5.Element holding created DOM element + */ + p5.prototype.createFileInput = function(callback, multiple) { + + // Is the file stuff supported? + if (window.File && window.FileReader && window.FileList && window.Blob) { + // Yup, we're ok and make an input file selector + var elt = document.createElement('input'); + elt.type = 'file'; + + // If we get a second argument that evaluates to true + // then we are looking for multiple files + if (multiple) { + // Anything gets the job done + elt.multiple = 'multiple'; + } + + // Function to handle when a file is selected + // We're simplifying life and assuming that we always + // want to load every selected file + function handleFileSelect(evt) { + // These are the files + var files = evt.target.files; + // Load each one and trigger a callback + for (var i = 0; i < files.length; i++) { + var f = files[i]; + var reader = new FileReader(); + function makeLoader(theFile) { + // Making a p5.File object + var p5file = new p5.File(theFile); + return function(e) { + p5file.data = e.target.result; + callback(p5file); + }; + }; + reader.onload = makeLoader(f); + + // Text or data? + // This should likely be improved + if (f.type.indexOf('text') > -1) { + reader.readAsText(f); + } else { + reader.readAsDataURL(f); + } + } + } + + // Now let's handle when a file was selected + elt.addEventListener('change', handleFileSelect, false); + return addElement(elt, this); + } else { + console.log('The File APIs are not fully supported in this browser. Cannot create element.'); + } + }; + + + /** VIDEO STUFF **/ + + function createMedia(pInst, type, src, callback) { + var elt = document.createElement(type); + + // allow src to be empty + var src = src || ''; + if (typeof src === 'string') { + src = [src]; + } + for (var i=0; i