<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<script type='text/x-handlebars' data-template-name="application">
<!-- APPLICATION TEMPLATE (model: display) -->
<div id="app-wrapper">
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
{{#linkTo 'index' class="brand"}}Home{{/linkTo}}
<div class="nav-collapse collapse" id="main-menu">
<ul class="nav" id="main-menu-left">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Display Presets <b class="caret"></b></a>
<ul class="dropdown-menu" id="swatch-menu">
{{#each display in displays}}
<li>{{#linkTo 'display' display}}{{display.title}}{{/linkTo}}</li>
{{/each}}
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="display">
<!-- DISPLAY TEMPLATE -->
{{!- DASHBOARD -}}
{{render dashboard}}
{{!- ITEM POPUPS -}}
{{outlet}}
{{!- ITEMS -}}
{{render 'items' items}}
</script>
<script type="text/x-handlebars" data-template-name="dashboard">
<div class="span10 dashboard">
<h1>Application Title</h1>
<div class="span9">
itemsLength: {{itemsLength}}
{{#if controllers.items}}
<p class="alert alert-error">Sweet!! Dashboard can access item's info!</p>
{{else}}
<p class="alert alert-error">Dashboard cannot access items... :-/</p>
{{/if}}
</div>
<span class="span2 offset1"><h2>Total: XX</h2></span>
<span class="span3"><h2>Average: XX</h2></span>
<span class="span3"><h2>Cost: $XX.xx</h2></span>
</div>
</script>
<script type="text/x-handlebars" data-template-name="items">
<section class='items span10'>
{{#each}}
<div class='row item'>
{{!-- IMAGE --}}
{{#if image}}
<div class="span2">
{{#linkTo 'itemPopup' display.id id}}<img {{bindAttr src="image"}} class="img-polaroid">{{/linkTo}}
</div>
{{/if}}
{{!-- LEARN MORE --}}
<h3 class=" span7">{{title}}</h3>
<div class="span3">
<p>Mauris tincidunt, erat in adipiscing rhoncus, orci justo placerat tellus, sed venenatis risus enim ut enim. Praesent ac odio tincidunt.</p>
<span>({{#linkTo 'itemPopup' display.id id}}Learn More{{/linkTo}})</span>
</div>
<div class="span2 calculated text-right">
<p>Cost</p>
<h3>{{values.Cost.price}}</h3>
</div>
<div class="span2 calculated text-right">
<p>Other Item Property</p>
<h3>XX<h3>
</div>
<div class="span7">
{{!-- ITEM OPTIONS --}}
<div class="items">
<div class="option header">
<span></span>
<span>Quantity Available</span>
<span>option Price</span>
</div>
{{! need to create option template/model/controller -}}
<div class="option">
<span>dummy option (select me!)</span>
<span>[quantity]</span>
<span>[price]</span>
</div>
</div>
</div>
</div>
{{/each}}
</section>
</script>
<script type="text/x-handlebars" data-template-name="itemPopup">
<!-- POPUP TEMPLATE -->
<div class='popup-view'>
{{#linkTo 'display' model.display class="close"}}close{{/linkTo}}
<h1>{{title}}</h1>
{{#if image}}
<div class="span6">
<div class="span2">
<img {{bindAttr src="image"}} class="img-polaroid">
</div>
<div class="span3">
<p>Mauris tincidunt, erat in adipiscing rhoncus, orci justo placerat tellus, sed venenatis risus enim ut enim. Praesent ac odio tincidunt.</p>
<p>Mauris tincidunt, erat in adipiscing rhoncus, orci justo placerat tellus, sed venenatis risus enim ut enim. Praesent ac odio tincidunt.</p>
</div>
</div>
<div class="row"> </div>
<div class="span6">
</div>
{{else}}
{{#if embed}}
{{{embed}}}
{{/if}}
{{/if}}
</div>
</script>
</body>
</html>
/*************************
* Models
*************************/
/**
* Model for display page.
*/
App.Display = Ember.Object.extend({
identity: 'display',
loadedItems: false,
rawJson: [],
/* Simply returns the title of a display page */
title: function() {
return this.get('id');
}.property('id'),
/**
* Retreives items
*
* It returns a promise that will resolve to be the list of Items from
* our server. This load only occurs once and then results are cached.
*/
loadItems: function() {
var display = this;
return Em.Deferred.promise(function (p) {
// check for cached data
if (display.get('loadedItems')) {
p.resolve(display.get('items'));
// otherwise retreive data
} else {
// If we haven't loaded the items, load them via JSON
p.resolve($.getJSON("/game/json").then(function(data) {
var clean = data_clean_json(data);
var results = data_build_models(clean, display);
/* NOT CURRENTLY INCLUDED IN THIS JSBIN */
return results;
}));
}
});
},
/* Currently broken. Used when reloading url with popup open (eg http://bpf.vm/#/r/aww/3)
*/
findItemById: function(id) {
return this.loadItems().then(function (items) {
return items.findProperty('id', id);
});
}
});
/**
* Adds class methods to Display model
*
* Note: `reopenClass` sounds scary but it's pretty simple. We're just defining
* class level methods instead of instance methods. That way we can say `App.Display.list()`
* to get a list of displays.
*/
App.Display.reopenClass({
/* This class method returns a list of all our displays. We store them in
* a class variable so they will only be created and referenced once.
*/
list: function(id) {
// If we've already loaded the list, return it
if (this._list) {
return this._list;
}
var list = Em.A();
var defaultPresets = [
'Custom',
'Preset 1',
'Preset 2',
'Preset 3'
];
defaultPresets.forEach(function (id) {
list.pushObject(App.Display.create({
id: id,
title: id
}));
});
// Remember what we've created so we don't request it twice.
this._list = list;
return list;
},
/*
Returns the default display to show if the user hasn't selected one.
*/
defaultPreset: function() {
return this.list()[0];
}
});
/**
* Model for Item Popup
*/
App.Item = Ember.Object.extend({
identity: 'item',
title: '',
cost: '',
quantity: '',
options: null,
totalOptionsCost: function(){
var j = this.get('options').reduce(
function(prevValue, currentValue, index, array){
return prevValue + parseInt(currentValue.get('cost'), 10); }, 0);
return j;
}.property('options.@each.cost')
});
/**
* Model for Item Popup
*/
App.ItemPopup = Ember.Object.extend({
identity: 'item popup',
thumbnailUrl: function() {
var thumbnail = this.get('thumbnail');
return ((thumbnail === 'default') || (thumbnail === 'self')) ? null : thumbnail;
}.property('thumbnail'),
image: function() {
var url = this.get('url');
if (!url) {
return false;
}
if (url.match(/\.(jpeg|jpg|gif|png)$/) !== null) {
return true;
}
if (url.match(/imgur\.com\//) !== null) {
return true;
}
return false;
}.property('url'),
embed: function() {
var result = this.get('media_embed.content');
if (!result) return null;
return result.replace(/</g,'<').replace(/>/g,'>');
}.property('media_embed.content'),
imageUrl: function() {
var url = this.get('url');
if (!url) return false;
if (url.match(/imgur\.com\//) !== null) return url + ".jpg";
return url;
}.property('url')
});
/*************************
* Ember.js Routes
*************************/
/* Maps urls to resources */
App.Router.map(function() {
this.resource("display", { path: "/:display_id"}, function() {
this.resource('itemPopup', { path: '/:item_id' } );
});
});
App.ApplicationRoute = Ember.Route.extend({
setupController: function(applicationController) {
applicationController.set('displays', App.Display.list());
}
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('display', App.Display.defaultPreset());
}
});
App.DisplayRoute = Ember.Route.extend({
model: function(params) {
var list = App.Display.list().findProperty('id', params.display_id);
return list;
},
afterModel: function(model) {
if(typeof model != 'undefined'){
var items = model.loadItems();
return items;
} else {
this.transitionTo('display', App.Display.defaultPreset());
}
}
});
App.ItemPopupRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('display').findItemById(params.item_id);
}
});
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |