]> git.r.bdr.sh - rbdr/r.bdr.sh/commitdiff
Adds the guestbook functionality.
authorBen Beltran <redacted>
Mon, 23 Feb 2015 05:23:45 +0000 (23:23 -0600)
committerBen Beltran <redacted>
Mon, 23 Feb 2015 05:23:45 +0000 (23:23 -0600)
jekyll/_layouts/default.html
jekyll/css/application.css
jekyll/guestbook.html [new file with mode: 0644]
jekyll/js/unlimited_pizza.js
jekyll/js/unlimited_pizza/pepperoni.js [new file with mode: 0644]

index 416f382bbda449cc34d2ccf3553c06de887d70a8..0e2cec344140912a08a605c386b802f3fb9e7129 100644 (file)
     <script src="/js/vendor/recorderjs/recorder.js"></script>
     <script src="/js/vendor/recorderjs/recorderWorker.js"></script>
 
+    <!--
+        /\
+       / O\   The Unlimited Pizza Family's Own Libraries
+      /O o \    * Melty Cheese: Header Expandos Widget
+     |______|   * Pepperoni: Audio Recorder Widget
+                * Tasty Crust: [Coming Soon] Colorful Navigation Widget
+    -->
     <script src="js/unlimited_pizza.js"></script>
     <script src="js/unlimited_pizza/melty_cheese.js"></script>
+    <script src="js/unlimited_pizza/pepperoni.js"></script>
     <script type="text/javascript">
 
       window.addEventListener('load', function () {
index 9e1f2db7f2dac5b0659fa65b316cd7c3c19ef850..16cb5e6c467a79a1b3af80fd15c730ed643c96b4 100644 (file)
@@ -200,7 +200,8 @@ code {overflow-wrap: normal}
   width: 8.571em;
   float: left;
   text-align: right;
-  padding: 1.071em;
+  padding: 0.5em  1.071em;
+  text-transform: uppercase;
 }
 
 .guestbook-form .guestbook-control {
@@ -230,3 +231,89 @@ code {overflow-wrap: normal}
 .guestbook-post .author {
   font-weight: bold;
 }
+
+/*
+ * The Recorder CSS
+ */
+.pepperoni-widget {
+  justify-content: space-between;
+  display: flex;
+}
+
+.pepperoni-widget .record-button {
+  display: flex;
+  font-size: 1.538461em;
+  padding: 1em;
+  margin: 1em;
+  height: 1em;
+  background-color: #f1f1f1;
+  cursor: pointer;
+  transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.record-info {
+  margin: 1em 0;
+}
+
+.pepperoni-widget .record-button.recording {
+  background-color: #00cc12;
+  color: white;
+  padding: 1em 1.1em 1em 0.68em;
+}
+
+.pepperoni-widget .record-button:hover {
+  text-decoration: none;
+  background-color: #fafafa;
+}
+
+.pepperoni-widget .record-button.recording:hover {
+  background-color: #d30058;
+  color: #f1f1f1;
+}
+
+.pepperoni-widget .record-progress {
+  justify-content: space-between;
+  display: flex;
+  margin: 0.5em 0.76em;
+}
+
+.record-progress-bar-container {
+  background-color: #f1f1f1;
+  height: 2em;
+  width: 15.385em;
+  margin-right: 0.76em;
+}
+
+.record-progress-bar {
+  height: 2em;
+  background-color: #d30058;
+  width: 0;
+}
+
+.record-clear {
+  margin-top: 0.1em;
+  text-transform: uppercase;
+  font-size: 1em;
+  width: 4em;
+  cursor: pointer;
+}
+
+.record-clear:hover {
+  text-decoration: none;
+}
+
+.record-preview {
+  margin: 0.76em;
+  width: 15.385em;
+  height: 2em;
+}
+
+.guestbook-submit {
+  border-radius: 0;
+  border: 0;
+  background-color: #d30058;
+  font-family: 'Oswald', sans-serif;
+  color: #fff;
+  padding: 1em;
+  margin-left: 15em;
+}
diff --git a/jekyll/guestbook.html b/jekyll/guestbook.html
new file mode 100644 (file)
index 0000000..46ccfda
--- /dev/null
@@ -0,0 +1,36 @@
+---
+layout: default
+title: Guestbook
+description: "Audio Guestbook"
+---
+
+<div class="content">
+  <div class="related">
+    <div class="guestbook-form">
+      <h1>Audio Guestbook</h1>
+      <p>
+      Clips will live for a week before being destroyed.
+      <em>Los clips durarán una semana antes de ser destruĂ­dos</em>
+      </p>
+      <form method="post">
+        <ul>
+            <div class="guestbook-control-group">
+              <li class="guestbook-label"><label for="name-control">Nombre / Name</label></li>
+              <li class="guestbook-control"><input name="name" class="name-control" id="name-control" /></li>
+            </div>
+            <div class="guestbook-control-group">
+              <li class="guestbook-control"><div class="pepperoni-widget"></div></li>
+            </div>
+            <div class="guestbook-control-group">
+              <li class="guestbook-control"><input type="submit" value="OK!" class="guestbook-submit" /></li>
+            </div>
+        </ul>
+      </form>
+    </div>
+    <div class="guestbook-content">
+      <h1>CLIPS</h1>
+      <ul class="guestbook-feed">
+      </ul>
+    </div>
+  </div>
+</div>
index 2dc7a7c0001e6cc8bf446208a56abba182bbdce1..af650ee3a52229399820678dd4e68c82a62977a4 100644 (file)
@@ -13,11 +13,14 @@ Class("UnlimitedPizza").inherits(Widget)({
   },
 
   prototype : {
+    _fb : null,
     _loaded : false,
 
     init : function (config) {
       Widget.prototype.init.call(this, config)
 
+      this._fb = new Firebase("https://guestbook-nsovocal.firebaseio.com");
+
       this._bindInternalEvents();
     },
 
@@ -39,9 +42,16 @@ Class("UnlimitedPizza").inherits(Widget)({
 
       // Melty cheese is our header image widget.
       this._loadMeltyCheese();
+
+      // Pepperoni is our recording widget.
+      this._loadPepperoni();
+
+      // Simple guestbook functionality
+      this._loadGuestbook();
+      this._loadPosts();
     },
 
-    _loadMeltyCheese : function() {
+    _loadMeltyCheese : function () {
       this.element.find('.post-image').each(function (i, headerElement) {
 
         // Create and activate
@@ -51,6 +61,90 @@ Class("UnlimitedPizza").inherits(Widget)({
         }));
         this['header-' + i].activate();
       }.bind(this));
+    },
+
+    _loadPepperoni : function () {
+      this.element.find('.pepperoni-widget').each(function (i, widgetElement) {
+
+        // Create and activate
+        this.appendChild(new UnlimitedPizza.Pepperoni({
+          element : $(widgetElement),
+          name : 'recorder-' + i
+        }));
+        this['recorder-' + i].activate();
+      }.bind(this));
+    },
+
+    _loadGuestbook : function () {
+      var form = this.element.find('.guestbook-form form');
+      form.on('submit', function submitPost(ev) {
+        ev.preventDefault();
+
+        var formArray = form.serializeArray();
+        var recorder = this['recorder-0'];
+
+        recorder.finalize(function (buffer) {
+          var fb, arrayBuffer, fileReader;
+
+          if (buffer.size <= 44) {
+            alert("You need to record something.");
+            return;
+          }
+          if (formArray[0].value.length === 0) {
+            alert("You need a name.");
+            return;
+          }
+
+          fb = this._fb;
+
+          fileReader = new FileReader();
+          fileReader.onload = function() {
+            var binary, bytes, length, i;
+
+            binary = '';
+            bytes = new Uint8Array( this.result );
+            length = bytes.byteLength;
+            for (i = 0; i < length; i++) {
+              binary += String.fromCharCode( bytes[ i ] );
+            }
+
+            fb.push({
+              buffer: btoa(binary),
+              name: formArray[0].value
+            });
+            recorder.clear();
+          };
+          fileReader.readAsArrayBuffer(buffer);
+        }.bind(this));
+        return false;
+      }.bind(this))
+    },
+
+    _loadPosts : function () {
+      var feed = this.element.find('.guestbook-feed');
+
+      console.log("Loadin", feed.length);
+      if (feed.length > 0) {
+        this._fb.on('value', function (data) {
+          var posts, property, post;
+
+          // Clear feed
+          feed.empty();
+          posts = data.val();
+
+          for (property in posts) {
+            if (posts.hasOwnProperty(property)) {
+              post = posts[property];
+
+              feed.append($('<li>\
+                    <div class="author">FROM: ' + post.name + '</div>\
+                    <div class="content">\
+                    <audio src="data:audio/wav;base64,' + post.buffer + '" controls></audio>\
+                    </div></li>'))
+            }
+          }
+        });
+      }
     }
   }
 });
diff --git a/jekyll/js/unlimited_pizza/pepperoni.js b/jekyll/js/unlimited_pizza/pepperoni.js
new file mode 100644 (file)
index 0000000..d874243
--- /dev/null
@@ -0,0 +1,152 @@
+Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
+  INNER_HTML : ' \
+<a class="record-button">&#11044</a> \
+<div class="record-info"> \
+  <div class="record-progress"> \
+    <div class="record-progress-bar-container"> \
+      <div class="record-progress-bar"></div> \
+    </div> \
+    <a class="record-clear">X</a> \
+  </div> \
+  <audio class="record-preview" controls></audio> \
+</div> \
+  ',
+  PAUSE : '&#9616;&#9616;',
+  RECORD : '&#11044;',
+  prototype : {
+    maxSize : 1048576,
+    recording : false,
+    source : null,
+    recorder : null,
+    context : null,
+    workerPath : '/js/vendor/recorderjs/recorderWorker.js',
+    init : function init(config) {
+      Widget.prototype.init.call(this, config);
+
+      if (!this.context) {
+        this.context = new (window.AudioContext || window.webkitAudioContext)();
+      }
+
+      if (!this.source) {
+        this._getUserMedia({
+          audio : true
+        }, this._onUserMedia.bind(this), this._onUserMediaError.bind(this))
+      }
+
+      this.element.html(this.constructor.INNER_HTML);
+
+      this.controlButton = this.element.find('.record-button');
+      this.clearButton = this.element.find('.record-clear');
+      this.audioElement = this.element.find('audio');
+      this.progressBarContainer = this.element.find('.record-progress-bar-container');
+      this.progressBar = this.element.find('.record-progress-bar');
+
+      this._bindEvents();
+    },
+
+    record : function record() {
+      if (this.recorder && !this.recording) {
+        this._canRecord(function handleCanRecord(canRecord) {
+          if (canRecord) {
+            this.recording = true;
+            this.controlButton.addClass('recording')
+            this.controlButton.html(this.constructor.PAUSE);
+            this._interval = setInterval(this._onRecordCheck.bind(this), 100);
+            this.recorder.record();
+          }
+        }.bind(this));
+      }
+    },
+
+    stop : function stop() {
+      if (this.recorder && this.recording) {
+        this.recording = false;
+        this.controlButton.removeClass('recording')
+        this.controlButton.html(this.constructor.RECORD);
+        clearInterval(this._interval);
+        this.recorder.stop();
+        this.recorder.exportWAV();
+      }
+    },
+
+    clear : function clear() {
+      if (this.recorder) {
+        this.progressBar.width(0);
+        this.audioElement.attr('src', '');
+        this.audioElement[0].load();
+        this.recorder.clear()
+      }
+    },
+
+    finalize : function finalize(callback) {
+      if (this.recorder) {
+        this.recorder.exportWAV(callback);
+      }
+    },
+
+    getBuffer : function getBuffer(callback) {
+      if (this.recorder) {
+        this.recorder.getBuffer(callback);
+      }
+    },
+
+    _bindEvents : function bindEvents() {
+      this.controlButton.on('click', function () {
+        if (this.recording) {
+          this.stop();
+        } else {
+          this.record();
+        }
+      }.bind(this))
+
+      this.clearButton.on('click', function () {
+        if (!this.recording) {
+          this.clear();
+        }
+      }.bind(this))
+    },
+
+    _onRecording : function _onRecording(buffer) {
+      this._buffer = buffer;
+
+      this.audioElement.attr('src', URL.createObjectURL(buffer));
+      this.audioElement[0].load();
+    },
+
+    _onUserMedia : function _onUserMedia(localMediaStream) {
+      this.source = this.context.createMediaStreamSource(localMediaStream);
+      this.recorder = new Recorder(this.source, {
+        workerPath : this.workerPath,
+        callback : this._onRecording.bind(this)
+      });
+    },
+
+    _onUserMediaError : function _onUserMediaError(error) {
+      console.log("Something went wrong", error);
+      this.disable();
+    },
+
+    _onRecordCheck : function _onRecordCheck() {
+      this._canRecord(function (canRecord, bufferSize) {
+        var width =  bufferSize * this.progressBarContainer.width() / this.maxSize;
+        this.progressBar.width(width);
+        if (!canRecord) {
+          this.stop();
+        }
+      }.bind(this));
+    },
+
+    _canRecord : function _canRecord(callback) {
+      this.recorder.getBuffer(function getBuffer(buffer) {
+        var bufferSize = buffer[0].length + buffer[1].length;
+         callback && callback(bufferSize <= this.maxSize, bufferSize);
+      }.bind(this));
+    },
+
+    // Normalize get user media
+    _getUserMedia : (navigator.getUserMedia ||
+                     navigator.webkitGetUserMedia ||
+                     navigator.mozGetUserMedia ||
+                     navigator.msGetUserMedia).bind(navigator)
+  }
+});