Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 14 commits
  • 12 files changed
  • 0 commit comments
  • 1 contributor
View
2 .gitignore
@@ -0,0 +1,2 @@
+.sass-cache
+build
View
8 Gemfile
@@ -0,0 +1,8 @@
+source :rubygems
+
+gem "middleman"
+gem "therubyracer"
+
+group :development do
+ gem "heroku"
+end
View
122 Gemfile.lock
@@ -0,0 +1,122 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ activesupport (3.1.2)
+ multi_json (~> 1.0)
+ addressable (2.2.6)
+ chunky_png (1.2.5)
+ coffee-script (2.2.0)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.1.3)
+ compass (0.11.5)
+ chunky_png (~> 1.2)
+ fssm (>= 0.2.7)
+ sass (~> 3.1)
+ daemons (1.1.4)
+ em-websocket (0.3.5)
+ addressable (>= 2.1.1)
+ eventmachine (>= 0.12.9)
+ eventmachine (0.12.10)
+ execjs (1.2.9)
+ multi_json (~> 1.0)
+ fssm (0.2.7)
+ guard (0.6.3)
+ thor (~> 0.14.6)
+ guard-livereload (0.3.1)
+ em-websocket (>= 0.2.0)
+ guard (>= 0.4.0)
+ multi_json (~> 1.0.3)
+ haml (3.1.3)
+ heroku (2.14.0)
+ launchy (>= 0.3.2)
+ rest-client (~> 1.6.1)
+ rubyzip
+ term-ansicolor (~> 1.0.5)
+ hike (1.2.1)
+ http_router (0.10.2)
+ rack (>= 1.0.0)
+ url_mount (~> 0.2.1)
+ i18n (0.6.0)
+ launchy (2.0.5)
+ addressable (~> 2.2.6)
+ libv8 (3.3.10.4)
+ maruku (0.6.0)
+ syntax (>= 1.0.0)
+ middleman (2.0.14)
+ coffee-script (~> 2.2.0)
+ compass (~> 0.11.3)
+ execjs (~> 1.2.7)
+ guard (~> 0.6.2)
+ haml (~> 3.1.0)
+ maruku (~> 0.6.0)
+ middleman-livereload (~> 0.2.0)
+ padrino-core (~> 0.10.5)
+ padrino-helpers (~> 0.10.5)
+ rack (~> 1.3.5)
+ rack-test (~> 0.6.1)
+ sass (~> 3.1.7)
+ sinatra (~> 1.3.1)
+ slim (~> 1.0.2)
+ sprockets (~> 2.0.3)
+ thin (~> 1.2.11)
+ thor (~> 0.14.0)
+ tilt (~> 1.3.1)
+ uglifier (~> 1.0.0)
+ middleman-livereload (0.2.1)
+ guard-livereload (~> 0.3.1)
+ mime-types (1.16)
+ multi_json (1.0.3)
+ padrino-core (0.10.5)
+ activesupport (~> 3.1.0)
+ http_router (~> 0.10.2)
+ sinatra (~> 1.3.1)
+ thor (~> 0.14.3)
+ tilt (~> 1.3.0)
+ padrino-helpers (0.10.5)
+ i18n (~> 0.6)
+ padrino-core (= 0.10.5)
+ rack (1.3.5)
+ rack-protection (1.1.4)
+ rack
+ rack-test (0.6.1)
+ rack (>= 1.0)
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
+ rubyzip (0.9.4)
+ sass (3.1.10)
+ sinatra (1.3.1)
+ rack (~> 1.3, >= 1.3.4)
+ rack-protection (~> 1.1, >= 1.1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ slim (1.0.4)
+ temple (~> 0.3.4)
+ tilt (~> 1.3.2)
+ sprockets (2.0.3)
+ hike (~> 1.2)
+ rack (~> 1.0)
+ tilt (~> 1.1, != 1.3.0)
+ syntax (1.0.0)
+ temple (0.3.4)
+ term-ansicolor (1.0.7)
+ therubyracer (0.9.9)
+ libv8 (~> 3.3.10)
+ thin (1.2.11)
+ daemons (>= 1.0.9)
+ eventmachine (>= 0.12.6)
+ rack (>= 1.0.0)
+ thor (0.14.6)
+ tilt (1.3.3)
+ uglifier (1.0.4)
+ execjs (>= 0.3.0)
+ multi_json (>= 1.0.2)
+ url_mount (0.2.1)
+ rack
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ heroku
+ middleman
+ therubyracer
View
102 config.rb
@@ -0,0 +1,102 @@
+###
+# Compass
+###
+
+# Susy grids in Compass
+# First: gem install compass-susy-plugin
+# require 'susy'
+
+# Change Compass configuration
+# compass_config do |config|
+# config.output_style = :compact
+# end
+
+###
+# Haml
+###
+
+# CodeRay syntax highlighting in Haml
+# First: gem install haml-coderay
+# require 'haml-coderay'
+
+# CoffeeScript filters in Haml
+# First: gem install coffee-filter
+# require 'coffee-filter'
+
+# Automatic image dimensions on image_tag helper
+# activate :automatic_image_sizes
+
+###
+# Page command
+###
+
+# Per-page layout changes:
+#
+# With no layout
+page "/*", :layout => false
+#
+# With alternative layout
+# page "/path/to/file.html", :layout => :otherlayout
+#
+# A path which all have the same layout
+# with_layout :admin do
+# page "/admin/*"
+# end
+
+# Proxy (fake) files
+# page "/this-page-has-no-template.html", :proxy => "/template-file.html" do
+# @which_fake_page = "Rendering a fake page with a variable"
+# end
+
+###
+# Helpers
+###
+
+# Methods defined in the helpers block are available in templates
+# helpers do
+# def some_helper
+# "Helping"
+# end
+# end
+
+# Change the CSS directory
+# set :css_dir, "alternative_css_directory"
+
+# Change the JS directory
+# set :js_dir, "alternative_js_directory"
+
+# Change the images directory
+# set :images_dir, "alternative_image_directory"
+
+configure :development do
+ APP_ID = "306885819329928"
+end
+
+configure :production do
+ APP_ID = "309724822372094"
+end
+
+# Build-specific configuration
+configure :build do
+ APP_ID = "309724822372094"
+
+ # For example, change the Compass output style for deployment
+ # activate :minify_css
+
+ # Minify Javascript on build
+ # activate :minify_javascript
+
+ # Enable cache buster
+ # activate :cache_buster
+
+ # Use relative URLs
+ # activate :relative_assets
+
+ # Compress PNGs after build
+ # First: gem install middleman-smusher
+ # require "middleman-smusher"
+ # activate :smusher
+
+ # Or use a different image path
+ # set :http_path, "/Content/images/"
+end
View
4 config.ru
@@ -0,0 +1,4 @@
+require 'rubygems'
+require 'middleman'
+
+run Middleman.server
View
50 source/index.html.erb
@@ -0,0 +1,50 @@
+<!DOCTYPE>
+<html>
+ <head>
+ <title>Confluence.fm</title>
+ <link rel=stylesheet href="/stylesheets/site.css"></link>
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
+ <script src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
+ <script src="https://raw.github.com/cowboy/jquery-bbq/master/jquery.ba-bbq.min.js"></script>
+ <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
+ <script src="/javascripts/jquery.mustache.js"></script>
+ <script>Confluence = {appId: <%= APP_ID %>}</script>
+ <script src="/javascripts/app.js"></script>
+ <script id="song-row" type="text/mustache">
+ {{#data}}
+ <tr data-id={{videoId}}>
+ <td><img src='http://i.ytimg.com/vi/{{videoId}}/default.jpg'</td>
+ <td class=video-name>{{name}}</td>
+ <td class=friend-name>{{from.name}}</td>
+ <td class=kill-row><a href="javascript:">X</a></td>
+ </tr>
+ {{/data}}
+ </script>
+ </head>
+<body>
+ <hgroup>
+ <h1>Confluence.<span class=tld>fm</span></h1>
+ <h2>Make a playlist out of the music your friends are sharing on Facebook</h2>
+ </hgroup>
+ <div id=main>
+ <div id=controls>
+ <a id=load href="javascript:">Get started by loading your feed</a>
+ <p id=loading href="javascript:">Loading your feed from Facebook...</p>
+ <a id=play href="javascript:">Play</a>
+ </div>
+
+ <div id="video"></div>
+ <table style="display:none">
+ <thead><tr>
+ <td>
+ <td>Video
+ <td>From
+ <td>
+ </tr></thead>
+ <tbody>
+ </tbody>
+ </table>
+ </div>
+ <div id="fb-root"></div>
+</body>
+</html>
View
107 source/javascripts/app.js
@@ -0,0 +1,107 @@
+window.fbAsyncInit = function() {
+ FB.init({
+ appId : Confluence.appId,
+ status : true, // check login status
+ authResponse: true,
+ oath: true,
+ cookie: true
+ });
+};
+
+$(document).ready(function() {
+ $('#load').click(function() {
+ if (FB.getSession()) {
+ loadFeed();
+ }
+ else {
+ FB.login(function(response) {
+ if (response.status == "connected") {
+ loadFeed();
+ }
+ }, {perms: 'read_stream'});
+ }
+ });
+
+ $('tr a').live('click', function() {
+ $(this).closest('tr').remove();
+ });
+
+ $('#play').click(function() {
+ var ids = extractVideoIds();
+ embedVideo(ids);
+
+ $(this).hide();
+ $('.kill-row').remove();
+ });
+});
+
+$('tbody tr').live('mouseenter', function(e) {
+ $('.kill-row a', this).css('visibility', 'visible');
+}).live('mouseleave', function(e) {
+ $('.kill-row a', this).css('visibility', 'hidden');
+});;
+
+function extractVideoIds() {
+ return $('tbody tr').map(function(i, elem) {
+ return $(elem).attr('data-id');
+ }).get();
+}
+
+function loadFeed() {
+ $('#load').hide();
+ $('#loading').show();
+
+ FB.api('/me/home', {limit: 200}, function(response) {
+ if (response.data) {
+ renderList(response);
+ }
+ else {
+ alert(response.error.message);
+ }
+ });
+}
+
+function selectVideoItems(response) {
+ var list = _(response.data).filter(function(item) {
+ return item.type == 'video' && item.source.match('youtu\.?be')
+ }).map(function(item) {
+ item.videoId = item.source.match(/v\/(.+)\?/)[1];
+ return item;
+ });
+
+ return {data: list.reverse()};
+}
+
+function renderList(response) {
+ var template = $('#song-row').html(),
+ response = selectVideoItems(response);
+
+ $('#loading').hide();
+ $('#play').show();
+ $('table').show().find('tbody').append($.mustache(template, response));
+}
+
+function embedVideo(ids) {
+ var firstId = ids.shift();
+ swfobject.embedSWF("http://www.youtube.com/v/" + firstId + "?enablejsapi=1&playerapiid=video&autoplay=1&playlist=" + ids.join(',') + '&playnext=1&version=3', "video", "825", "356", "8", null, null, null, null);
+}
+
+// Load the YouTube JS asynchronously
+var tag = document.createElement('script');
+tag.src = "http://www.youtube.com/player_api";
+var firstScriptTag = document.getElementsByTagName('script')[0];
+firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+
+// Load the Facebook JS asynchronously
+(function(d){
+ var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
+ js = d.createElement('script'); js.id = id; js.async = true;
+ js.src = "//connect.facebook.net/en_US/all.js";
+ d.getElementsByTagName('head')[0].appendChild(js);
+ }(document));
+
+$('a').click(function() {
+ FB.api('/me', function(response) {
+ alert('Your name is ' + response.name);
+ });
+});
View
3 source/javascripts/application.js.coffee
@@ -0,0 +1,3 @@
+#require "jquery.mustache"
+
+console.log "hello world"
View
0 jquery.mustache.js → source/javascripts/jquery.mustache.js
File renamed without changes.
View
51 index.html → source/public/index.html
@@ -1,18 +1,19 @@
<!DOCTYPE>
<html>
<head>
- <title>Facejam</title>
+ <title>Confluence.fm</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script src="https://raw.github.com/cowboy/jquery-bbq/master/jquery.ba-bbq.min.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
- <script src="/jquery.mustache.js"></script>
+ <script src="/javascripts/jquery.mustache.js"></script>
<script id="song-row" type="text/mustache">
{{#data}}
- <tr data-url={{source}}>
- <td>{{from.name}}</td>
+ <tr data-id={{videoId}}>
+ <td><img src='http://i.ytimg.com/vi/{{videoId}}/default.jpg'</td>
<td>{{name}}</td>
- <td><a class=remove href=javascript:>X</a></td>
+ <td>{{from.name}}</td>
+ <td><a style="display:none" href="javascript:">X</a></td>
</tr>
{{/data}}
</script>
@@ -21,26 +22,31 @@
FB.init({
appId : '309724822372094',
status : true, // check login status
- cookie : true, // enable cookies to allow the server to access the session
- oauth : true, // enable OAuth 2.0
+ authResponse: true,
+ oath: true,
+ cookie: true
});
};
$(document).ready(function() {
$('#fetch-stream').click(function() {
- if (FB.getAuthResponse) {
+ if (FB.getSession()) {
loadFeed();
}
else {
FB.login(function(response) {
- if (response.authResponse) {
+ if (response.status == "connected") {
loadFeed();
}
- }, {scope: 'read_stream'});
+ }, {perms: 'read_stream'});
}
});
- $('.remove').live('click', function(e) {
+ $(document).on('mouseenter mouseleave', 'tbody tr', {}, function(e) {
+ $('a', this).toggle();
+ });
+
+ $('tr a').live('click', function() {
$(this).closest('tr').remove();
});
@@ -53,15 +59,9 @@
});
function extractVideoIds() {
- var urls = [];
-
- $('tbody tr').each(function(i, elem) {
- urls.push($(elem).attr('data-url'));
- });
-
- return _.map(urls, function(url) {
- return url.match(/v\/(.+)\?/)[1];
- });
+ return $('tbody tr').map(function(i, elem) {
+ return $(elem).attr('data-id');
+ }).get();
}
function loadFeed() {
@@ -76,9 +76,12 @@
}
function selectVideoItems(response) {
- var list = _.filter(response.data, function(item) {
+ var list = _(response.data).filter(function(item) {
return item.type == 'video' && item.source.match('youtu\.?be')
- })
+ }).map(function(item) {
+ item.videoId = item.source.match(/v\/(.+)\?/)[1];
+ return item;
+ });
return {data: list.reverse()};
}
@@ -120,14 +123,14 @@
</head>
<body>
<div id="fb-root"></div>
- <h1>Facejam</h1>
+ <h1>Confluence.fm</h1>
<h2>Make a playlist out of the music your friends are sharing</h2>
<a id="fetch-stream" href="javascript:">Load music</a>
<a id="play" href="javascript:" style="display:none">Play</a>
<div id="video">
</div>
<table style="display:none">
- <thead><tr><td>From</td><td>Video</td></tr></thead>
+ <thead><tr><td>Video</td><td></td><td>From</td></tr></thead>
<tbody>
</tbody>
</table>
View
437 source/public/javascripts/jquery.mustache.js
@@ -0,0 +1,437 @@
+/*
+Shameless port of a shameless port
+@defunkt => @janl => @aq
+
+See http://github.com/defunkt/mustache for more info.
+*/
+
+;(function($) {
+
+/*
+ mustache.js — Logic-less templates in JavaScript
+
+ See http://mustache.github.com/ for more info.
+*/
+
+var Mustache = function() {
+ var regexCache = {};
+ var Renderer = function() {};
+
+ Renderer.prototype = {
+ otag: "{{",
+ ctag: "}}",
+ pragmas: {},
+ buffer: [],
+ pragmas_implemented: {
+ "IMPLICIT-ITERATOR": true
+ },
+ context: {},
+
+ render: function(template, context, partials, in_recursion) {
+ // reset buffer & set context
+ if(!in_recursion) {
+ this.context = context;
+ this.buffer = []; // TODO: make this non-lazy
+ }
+
+ // fail fast
+ if(!this.includes("", template)) {
+ if(in_recursion) {
+ return template;
+ } else {
+ this.send(template);
+ return;
+ }
+ }
+
+ // get the pragmas together
+ template = this.render_pragmas(template);
+
+ // render the template
+ var html = this.render_section(template, context, partials);
+
+ // render_section did not find any sections, we still need to render the tags
+ if (html === false) {
+ html = this.render_tags(template, context, partials, in_recursion);
+ }
+
+ if (in_recursion) {
+ return html;
+ } else {
+ this.sendLines(html);
+ }
+ },
+
+ /*
+ Sends parsed lines
+ */
+ send: function(line) {
+ if(line !== "") {
+ this.buffer.push(line);
+ }
+ },
+
+ sendLines: function(text) {
+ if (text) {
+ var lines = text.split("\n");
+ for (var i = 0; i < lines.length; i++) {
+ this.send(lines[i]);
+ }
+ }
+ },
+
+ /*
+ Looks for %PRAGMAS
+ */
+ render_pragmas: function(template) {
+ // no pragmas
+ if(!this.includes("%", template)) {
+ return template;
+ }
+
+ var that = this;
+ var regex = this.getCachedRegex("render_pragmas", function(otag, ctag) {
+ return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
+ });
+
+ return template.replace(regex, function(match, pragma, options) {
+ if(!that.pragmas_implemented[pragma]) {
+ throw({message:
+ "This implementation of mustache doesn't understand the '" +
+ pragma + "' pragma"});
+ }
+ that.pragmas[pragma] = {};
+ if(options) {
+ var opts = options.split("=");
+ that.pragmas[pragma][opts[0]] = opts[1];
+ }
+ return "";
+ // ignore unknown pragmas silently
+ });
+ },
+
+ /*
+ Tries to find a partial in the curent scope and render it
+ */
+ render_partial: function(name, context, partials) {
+ name = this.trim(name);
+ if(!partials || partials[name] === undefined) {
+ throw({message: "unknown_partial '" + name + "'"});
+ }
+ if(typeof(context[name]) != "object") {
+ return this.render(partials[name], context, partials, true);
+ }
+ return this.render(partials[name], context[name], partials, true);
+ },
+
+ /*
+ Renders inverted (^) and normal (#) sections
+ */
+ render_section: function(template, context, partials) {
+ if(!this.includes("#", template) && !this.includes("^", template)) {
+ // did not render anything, there were no sections
+ return false;
+ }
+
+ var that = this;
+
+ var regex = this.getCachedRegex("render_section", function(otag, ctag) {
+ // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
+ return new RegExp(
+ "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
+
+ otag + // {{
+ "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
+ ctag + // }}
+
+ "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
+
+ otag + // {{
+ "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag).
+ ctag + // }}
+
+ "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
+
+ "g");
+ });
+
+
+ // for each {{#foo}}{{/foo}} section do...
+ return template.replace(regex, function(match, before, type, name, content, after) {
+ // before contains only tags, no sections
+ var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
+
+ // after may contain both sections and tags, so use full rendering function
+ renderedAfter = after ? that.render(after, context, partials, true) : "",
+
+ // will be computed below
+ renderedContent,
+
+ value = that.find(name, context);
+
+ if (type === "^") { // inverted section
+ if (!value || that.is_array(value) && value.length === 0) {
+ // false or empty list, render it
+ renderedContent = that.render(content, context, partials, true);
+ } else {
+ renderedContent = "";
+ }
+ } else if (type === "#") { // normal section
+ if (that.is_array(value)) { // Enumerable, Let's loop!
+ renderedContent = that.map(value, function(row) {
+ return that.render(content, that.create_context(row), partials, true);
+ }).join("");
+ } else if (that.is_object(value)) { // Object, Use it as subcontext!
+ renderedContent = that.render(content, that.create_context(value),
+ partials, true);
+ } else if (typeof value === "function") {
+ // higher order section
+ renderedContent = value.call(context, content, function(text) {
+ return that.render(text, context, partials, true);
+ });
+ } else if (value) { // boolean section
+ renderedContent = that.render(content, context, partials, true);
+ } else {
+ renderedContent = "";
+ }
+ }
+
+ return renderedBefore + renderedContent + renderedAfter;
+ });
+ },
+
+ /*
+ Replace {{foo}} and friends with values from our view
+ */
+ render_tags: function(template, context, partials, in_recursion) {
+ // tit for tat
+ var that = this;
+
+
+
+ var new_regex = function() {
+ return that.getCachedRegex("render_tags", function(otag, ctag) {
+ return new RegExp(otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + ctag + "+", "g");
+ });
+ };
+
+ var regex = new_regex();
+ var tag_replace_callback = function(match, operator, name) {
+ switch(operator) {
+ case "!": // ignore comments
+ return "";
+ case "=": // set new delimiters, rebuild the replace regexp
+ that.set_delimiters(name);
+ regex = new_regex();
+ return "";
+ case ">": // render partial
+ return that.render_partial(name, context, partials);
+ case "{": // the triple mustache is unescaped
+ return that.find(name, context);
+ default: // escape the value
+ return that.escape(that.find(name, context));
+ }
+ };
+ var lines = template.split("\n");
+ for(var i = 0; i < lines.length; i++) {
+ lines[i] = lines[i].replace(regex, tag_replace_callback, this);
+ if(!in_recursion) {
+ this.send(lines[i]);
+ }
+ }
+
+ if(in_recursion) {
+ return lines.join("\n");
+ }
+ },
+
+ set_delimiters: function(delimiters) {
+ var dels = delimiters.split(" ");
+ this.otag = this.escape_regex(dels[0]);
+ this.ctag = this.escape_regex(dels[1]);
+ },
+
+ escape_regex: function(text) {
+ // thank you Simon Willison
+ if(!arguments.callee.sRE) {
+ var specials = [
+ '/', '.', '*', '+', '?', '|',
+ '(', ')', '[', ']', '{', '}', '\\'
+ ];
+ arguments.callee.sRE = new RegExp(
+ '(\\' + specials.join('|\\') + ')', 'g'
+ );
+ }
+ return text.replace(arguments.callee.sRE, '\\$1');
+ },
+
+ /*
+ find `name` in current `context`. That is find me a value
+ from the view object
+ */
+ find: function(name, context) {
+ name = this.trim(name);
+
+ // Checks whether a value is thruthy or false or 0
+ function is_kinda_truthy(bool) {
+ return bool === false || bool === 0 || bool;
+ }
+
+ var value;
+
+ // check for dot notation eg. foo.bar
+ if(name.match(/([a-z_]+)\./ig)){
+ var childValue = this.walk_context(name, context);
+ if(is_kinda_truthy(childValue)) {
+ value = childValue;
+ }
+ }
+ else{
+ if(is_kinda_truthy(context[name])) {
+ value = context[name];
+ } else if(is_kinda_truthy(this.context[name])) {
+ value = this.context[name];
+ }
+ }
+
+ if(typeof value === "function") {
+ return value.apply(context);
+ }
+ if(value !== undefined) {
+ return value;
+ }
+ // silently ignore unkown variables
+ return "";
+ },
+
+ walk_context: function(name, context){
+ var path = name.split('.');
+ // if the var doesn't exist in current context, check the top level context
+ var value_context = (context[path[0]] != undefined) ? context : this.context;
+ var value = value_context[path.shift()];
+ while(value != undefined && path.length > 0){
+ value_context = value;
+ value = value[path.shift()];
+ }
+ // if the value is a function, call it, binding the correct context
+ if(typeof value === "function") {
+ return value.apply(value_context);
+ }
+ return value;
+ },
+
+ // Utility methods
+
+ /* includes tag */
+ includes: function(needle, haystack) {
+ return haystack.indexOf(this.otag + needle) != -1;
+ },
+
+ /*
+ Does away with nasty characters
+ */
+ escape: function(s) {
+ s = String(s === null ? "" : s);
+ return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
+ switch(s) {
+ case "&": return "&amp;";
+ case '"': return '&quot;';
+ case "'": return '&#39;';
+ case "<": return "&lt;";
+ case ">": return "&gt;";
+ default: return s;
+ }
+ });
+ },
+
+ // by @langalex, support for arrays of strings
+ create_context: function(_context) {
+ if(this.is_object(_context)) {
+ return _context;
+ } else {
+ var iterator = ".";
+ if(this.pragmas["IMPLICIT-ITERATOR"]) {
+ iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
+ }
+ var ctx = {};
+ ctx[iterator] = _context;
+ return ctx;
+ }
+ },
+
+ is_object: function(a) {
+ return a && typeof a == "object";
+ },
+
+ is_array: function(a) {
+ return Object.prototype.toString.call(a) === '[object Array]';
+ },
+
+ /*
+ Gets rid of leading and trailing whitespace
+ */
+ trim: function(s) {
+ return s.replace(/^\s*|\s*$/g, "");
+ },
+
+ /*
+ Why, why, why? Because IE. Cry, cry cry.
+ */
+ map: function(array, fn) {
+ if (typeof array.map == "function") {
+ return array.map(fn);
+ } else {
+ var r = [];
+ var l = array.length;
+ for(var i = 0; i < l; i++) {
+ r.push(fn(array[i]));
+ }
+ return r;
+ }
+ },
+
+ getCachedRegex: function(name, generator) {
+ var byOtag = regexCache[this.otag];
+ if (!byOtag) {
+ byOtag = regexCache[this.otag] = {};
+ }
+
+ var byCtag = byOtag[this.ctag];
+ if (!byCtag) {
+ byCtag = byOtag[this.ctag] = {};
+ }
+
+ var regex = byCtag[name];
+ if (!regex) {
+ regex = byCtag[name] = generator(this.otag, this.ctag);
+ }
+
+ return regex;
+ }
+ };
+
+ return({
+ name: "mustache.js",
+ version: "0.4.0-dev",
+
+ /*
+ Turns a template and view into HTML
+ */
+ to_html: function(template, view, partials, send_fun) {
+ var renderer = new Renderer();
+ if(send_fun) {
+ renderer.send = send_fun;
+ }
+ renderer.render(template, view || {}, partials);
+ if(!send_fun) {
+ return renderer.buffer.join("\n");
+ }
+ }
+ });
+}();
+
+ $.mustache = function(template, view, partials) {
+ return Mustache.to_html(template, view, partials);
+ };
+
+})(jQuery);
View
70 source/stylesheets/site.css.sass
@@ -0,0 +1,70 @@
+@import "compass"
+
+$link-color: #0388a6
+$link-hover-color: #009ce0
+$link-focus-color: false
+$link-active-color: false
+$link-visited-color: false
+
+$font-color: black
+$font-family: Helvetica, sans-serif
+$base-font-size: 12px
+$base-line-height: 18px
+
+$total-cols: 12
+$col-width: 4em
+$gutter-width: 1em
+$side-gutter-width: $gutter-width
+
+@include global-reset
+
+body
+ font-family: $font-family
+ color: $font-color
+
+a
+ @include link-colors($link-color, $link-hover-color, $link-focus-color, $link-active-color, $link-visited-color)
+
+#controls
+ font-size: 24px
+
+#main
+ padding-top: 50px
+ width: 90%
+ margin: 0 auto
+
+hgroup
+ width: 100%
+ background-color: black
+ color: white
+ font-weight: bold
+ padding: 20px
+ .tld
+ color: red
+
+h1
+ font-size: 30px
+ display: inline-block
+h2
+ font-size: 20px
+ margin-left: 20px
+ display: inline-block
+
+.video-name
+ padding-left: 20px
+ width: 500px
+ overflow: hidden
+ text-overflow: ellipsis
+
+#loading, #play
+ display: none
+
+table
+ margin-top: 20px
+ width: 100%
+
+tbody tr:hover
+ background-color: #eee
+
+.kill-row a
+ visibility: hidden

No commit comments for this range

Something went wrong with that request. Please try again.