Browse files

initial commit of ember app

  • Loading branch information...
1 parent 7ed5999 commit b51e20bb19c59131f370814fab3b5e6f39457886 @dgeb committed Jan 2, 2012
View
1 app/assets/javascripts/app.js
@@ -0,0 +1 @@
+App = Em.Application.create();
View
4 app/assets/javascripts/app/controllers/contacts.js
@@ -0,0 +1,4 @@
+App.contactsController = Em.ResourceController.create({
+ url: '/contacts',
+ type: App.Contact
+});
View
6 app/assets/javascripts/app/helpers/fields.js
@@ -0,0 +1,6 @@
+Handlebars.registerHelper('textField', function(property) {
+ var value = Em.getPath(this, property);
+ if (value === undefined)
+ value = "";
+ return new Handlebars.SafeString('<input id="'+property+'" value="' + value + '" />');
+});
View
4 app/assets/javascripts/app/helpers/formatting.js
@@ -0,0 +1,4 @@
+Handlebars.registerHelper('highlight', function(property) {
+ var value = Em.getPath(this, property);
+ return new Handlebars.SafeString('<span class="highlight">'+value+'</span>');
+});
View
21 app/assets/javascripts/app/models/contact.js
@@ -0,0 +1,21 @@
+App.Contact = Em.Object.extend({
+ fullName: Em.computed(function() {
+ return this.get('first_name') + ' ' + this.get('last_name');
+ }).property('first_name', 'last_name'),
+
+ data: Em.computed(function() {
+ return {contact: {first_name: this.get('first_name'),
+ last_name: this.get('last_name')}};
+ })
+});
+
+App.Contact.reopenClass({
+ // Let's do some crude validation here in which errors are returned as a string;
+ // successful validation returns true.
+ validateProperties: function(hash) {
+ if (hash.first_name === '' || hash.last_name === '')
+ return "Contacts require both a first and last name";
+ else
+ return true;
+ }
+});
View
5 app/assets/javascripts/app/templates/contacts/edit.jst.hjs
@@ -0,0 +1,5 @@
+{{#with contact}}
+ {{textField first_name}}
+ {{textField last_name}}
+{{/with}}
+<button type="submit">Save</button>
View
20 app/assets/javascripts/app/templates/contacts/list.jst.hjs
@@ -0,0 +1,20 @@
+<table>
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Name</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#each contacts}}
+ {{view App.ShowContactView contactBinding="this"}}
+ {{/each}}
+ {{#if showNew}}
+ {{view App.NewContactView}}
+ {{/if}}
+ </tbody>
+</table>
+<div class="commands">
+ {{#view Ember.Link action="newRecord"}}New Contact{{/view}}
+ {{#view Ember.Link action="refreshListing"}}Refresh Listing{{/view}}
+</div>
View
9 app/assets/javascripts/app/templates/contacts/new.jst.hjs
@@ -0,0 +1,9 @@
+<td></td>
+<td>
+ <form>
+ {{textField first_name}}
+ {{textField last_name}}
+ <button type="submit">Create</button>
+ </form>
+</td>
+<td></td>
View
14 app/assets/javascripts/app/templates/contacts/show.jst.hjs
@@ -0,0 +1,14 @@
+<td>{{contact.id}}</td>
+<td>
+ {{#if isEditing}}
+ {{view App.EditContactView contactBinding="contact"}}
+ {{else}}
+ {{contact.fullName}}
+ {{/if}}
+</td>
+<td class="commands">
+ {{#unless isEditing}}
+ {{#view Ember.Link action="startEditing"}}Edit{{/view}}
+ {{#view Ember.Link action="destroyRecord"}}Destroy{{/view}}
+ {{/unless}}
+</td>
View
29 app/assets/javascripts/app/views/contacts/edit.js
@@ -0,0 +1,29 @@
+App.EditContactView = Em.View.extend({
+ templateName: 'app/templates/contacts/edit',
+ tagName: 'form',
+
+ submit: function(evt) {
+ evt.preventDefault();
+
+ var data = {
+ first_name: this.$().find("#first_name").val(),
+ last_name: this.$().find("#last_name").val()
+ };
+ var valid = App.Contact.validateProperties(data);
+
+ if (valid === true) {
+ var self = this;
+
+ var contact = this.get("contact");
+ contact.setProperties(data);
+ App.contactsController.updateResource(contact)
+ .done( function() {self.get("parentView").stopEditing();});
+ }
+ else {
+ alert(valid);
+ }
+
+ // prevent event from bubbling up
+ return false;
+ }
+});
View
12 app/assets/javascripts/app/views/contacts/list.js
@@ -0,0 +1,12 @@
+App.ListContactsView = Em.View.extend({
+ templateName: 'app/templates/contacts/list',
+ contactsBinding: 'App.contactsController',
+
+ newRecord: function() {
+ this.set('showNew', true);
+ },
+
+ refreshListing: function() {
+ App.contactsController.findAll();
+ }
+});
View
29 app/assets/javascripts/app/views/contacts/new.js
@@ -0,0 +1,29 @@
+App.NewContactView = Em.View.extend({
+ templateName: 'app/templates/contacts/new',
+ tagName: 'tr',
+
+ submit: function(evt) {
+ evt.preventDefault();
+
+ var data = {
+ first_name: this.$().find("#first_name").val(),
+ last_name: this.$().find("#last_name").val()
+ };
+ var valid = App.Contact.validateProperties(data);
+
+ if (valid === true) {
+ var parentView = this.get("parentView");
+
+ var contact = App.Contact.create(data);
+
+ App.contactsController.createResource(contact)
+ .done(function() {parentView.set('showNew', false)});
+ }
+ else {
+ alert(valid);
+ }
+
+ // prevent event from bubbling up
+ return false;
+ }
+});
View
23 app/assets/javascripts/app/views/contacts/show.js
@@ -0,0 +1,23 @@
+App.ShowContactView = Em.View.extend({
+ templateName: 'app/templates/contacts/show',
+ classNames: ['show-contact'],
+ tagName: 'tr',
+
+ doubleClick: function(evt) {
+ this.startEditing();
+ return false;
+ },
+
+ startEditing: function() {
+ this.set('isEditing', true);
+ },
+
+ stopEditing: function() {
+ this.set('isEditing', false);
+ },
+
+ destroyRecord: function() {
+ var contact = this.get("contact");
+ App.contactsController.destroyResource(contact);
+ }
+});
View
10 app/assets/javascripts/application.js
@@ -6,4 +6,12 @@
//
//= require jquery
//= require jquery_ujs
-//= require_tree .
+//= require ember
+//= require ember_resource_controller
+//= require ember_link
+//= require app
+//= require_tree ./app/models
+//= require_tree ./app/controllers
+//= require_tree ./app/views
+//= require_tree ./app/helpers
+//= require_tree ./app/templates
View
3 app/assets/javascripts/contacts.js.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
View
15 app/assets/javascripts/ember_link.js
@@ -0,0 +1,15 @@
+Ember.Link = Ember.View.extend(Ember.TargetActionSupport, {
+ classNames: ['ember-link'],
+
+ tagName: 'a',
+ attributeBindings: ['href'],
+ href: '#',
+ target: 'parentView',
+ propagateEvents: false,
+
+ click: function(evt) {
+ evt.preventDefault();
+ this.triggerAction();
+ return Ember.get(this, 'propagateEvents');
+ }
+});
View
69 app/assets/javascripts/ember_resource_controller.js
@@ -0,0 +1,69 @@
+Ember.ResourceController = Ember.ArrayController.extend({
+ type: Ember.required(),
+
+ content: [],
+
+ load: function(json) {
+ this.pushObject(this.get('type').create(json));
+ },
+
+ loadAll: function(jsonArray) {
+ for (var i=0; i < jsonArray.length; i++)
+ this.load(jsonArray[i]);
+ },
+
+ findAll: function() {
+ var self = this;
+
+ jQuery.getJSON(this._collectionUrl(), function(data) {
+ self.set("content", []);
+ self.loadAll(data);
+ });
+ },
+
+ updateResource: function(resource) {
+ return jQuery.ajax({
+ url: this._resourceUrl().fmt(resource.get('id')),
+ data: resource.get('data'),
+ dataType: 'json',
+ type: 'PUT'
+ });
+ },
+
+ createResource: function(resource) {
+ var self = this;
+
+ return jQuery.ajax({
+ url: this._collectionUrl(),
+ data: resource.get('data'),
+ dataType: 'json',
+ type: 'POST',
+ success: function(data) { self.load(data); }
+ });
+ },
+
+ destroyResource: function(resource) {
+ var self = this;
+
+ return jQuery.ajax({
+ url: this._resourceUrl().fmt(resource.get('id')),
+ dataType: 'json',
+ type: 'DELETE',
+ success: function() { self.removeObject(resource); }
+ });
+ },
+
+ _collectionUrl: function() {
+ if (this.collectionUrl !== undefined)
+ return this.collectionUrl;
+ else
+ return this.url;
+ },
+
+ _resourceUrl: function() {
+ if (this.resourceUrl !== undefined)
+ return this.resourceUrl;
+ else
+ return this._collectionUrl() + '/%@';
+ }
+});
View
9 app/assets/stylesheets/contacts.css.scss
@@ -1,3 +1,6 @@
-// Place all the styles related to the contacts controller here.
-// They will automatically be included in application.css.
-// You can use Sass (SCSS) here: http://sass-lang.com/
+.commands {
+ margin-top: 10px;
+ a {
+ margin-right: 10px;
+ }
+}
View
4 app/controllers/contacts_controller.rb
@@ -38,7 +38,7 @@ def update
respond_to do |format|
if @contact.update_attributes(params[:contact])
- format.json { head :ok }
+ format.json { render json: nil, status: :ok }
else
format.json { render json: @contact.errors, status: :unprocessable_entity }
end
@@ -51,7 +51,7 @@ def destroy
@contact.destroy
respond_to do |format|
- format.json { head :ok }
+ format.json { render json: nil, status: :ok }
end
end
end
View
25 app/views/contacts/_form.html.erb
@@ -1,25 +0,0 @@
-<%= form_for(@contact) do |f| %>
- <% if @contact.errors.any? %>
- <div id="error_explanation">
- <h2><%= pluralize(@contact.errors.count, "error") %> prohibited this contact from being saved:</h2>
-
- <ul>
- <% @contact.errors.full_messages.each do |msg| %>
- <li><%= msg %></li>
- <% end %>
- </ul>
- </div>
- <% end %>
-
- <div class="field">
- <%= f.label :first_name %><br />
- <%= f.text_field :first_name %>
- </div>
- <div class="field">
- <%= f.label :last_name %><br />
- <%= f.text_field :last_name %>
- </div>
- <div class="actions">
- <%= f.submit %>
- </div>
-<% end %>
View
6 app/views/contacts/edit.html.erb
@@ -1,6 +0,0 @@
-<h1>Editing contact</h1>
-
-<%= render 'form' %>
-
-<%= link_to 'Show', @contact %> |
-<%= link_to 'Back', contacts_path %>
View
32 app/views/contacts/index.html.erb
@@ -1,25 +1,11 @@
-<h1>Listing contacts</h1>
+<h1>Contacts</h1>
-<table>
- <tr>
- <th>First name</th>
- <th>Last name</th>
- <th></th>
- <th></th>
- <th></th>
- </tr>
+<script type="text/x-handlebars">
+ {{ view App.ListContactsView }}
+</script>
-<% @contacts.each do |contact| %>
- <tr>
- <td><%= contact.first_name %></td>
- <td><%= contact.last_name %></td>
- <td><%= link_to 'Show', contact %></td>
- <td><%= link_to 'Edit', edit_contact_path(contact) %></td>
- <td><%= link_to 'Destroy', contact, confirm: 'Are you sure?', method: :delete %></td>
- </tr>
-<% end %>
-</table>
-
-<br />
-
-<%= link_to 'New Contact', new_contact_path %>
+<script type="text/javascript">
+ $(function() {
+ App.contactsController.loadAll(<%= @contacts.to_json.html_safe %>);
+ });
+</script>
View
5 app/views/contacts/new.html.erb
@@ -1,5 +0,0 @@
-<h1>New contact</h1>
-
-<%= render 'form' %>
-
-<%= link_to 'Back', contacts_path %>
View
15 app/views/contacts/show.html.erb
@@ -1,15 +0,0 @@
-<p id="notice"><%= notice %></p>
-
-<p>
- <b>First name:</b>
- <%= @contact.first_name %>
-</p>
-
-<p>
- <b>Last name:</b>
- <%= @contact.last_name %>
-</p>
-
-
-<%= link_to 'Edit', edit_contact_path(@contact) %> |
-<%= link_to 'Back', contacts_path %>
View
241 public/index.html
@@ -1,241 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Ruby on Rails: Welcome aboard</title>
- <style type="text/css" media="screen">
- body {
- margin: 0;
- margin-bottom: 25px;
- padding: 0;
- background-color: #f0f0f0;
- font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
- font-size: 13px;
- color: #333;
- }
-
- h1 {
- font-size: 28px;
- color: #000;
- }
-
- a {color: #03c}
- a:hover {
- background-color: #03c;
- color: white;
- text-decoration: none;
- }
-
-
- #page {
- background-color: #f0f0f0;
- width: 750px;
- margin: 0;
- margin-left: auto;
- margin-right: auto;
- }
-
- #content {
- float: left;
- background-color: white;
- border: 3px solid #aaa;
- border-top: none;
- padding: 25px;
- width: 500px;
- }
-
- #sidebar {
- float: right;
- width: 175px;
- }
-
- #footer {
- clear: both;
- }
-
- #header, #about, #getting-started {
- padding-left: 75px;
- padding-right: 30px;
- }
-
-
- #header {
- background-image: url("/assets/rails.png");
- background-repeat: no-repeat;
- background-position: top left;
- height: 64px;
- }
- #header h1, #header h2 {margin: 0}
- #header h2 {
- color: #888;
- font-weight: normal;
- font-size: 16px;
- }
-
-
- #about h3 {
- margin: 0;
- margin-bottom: 10px;
- font-size: 14px;
- }
-
- #about-content {
- background-color: #ffd;
- border: 1px solid #fc0;
- margin-left: -55px;
- margin-right: -10px;
- }
- #about-content table {
- margin-top: 10px;
- margin-bottom: 10px;
- font-size: 11px;
- border-collapse: collapse;
- }
- #about-content td {
- padding: 10px;
- padding-top: 3px;
- padding-bottom: 3px;
- }
- #about-content td.name {color: #555}
- #about-content td.value {color: #000}
-
- #about-content ul {
- padding: 0;
- list-style-type: none;
- }
-
- #about-content.failure {
- background-color: #fcc;
- border: 1px solid #f00;
- }
- #about-content.failure p {
- margin: 0;
- padding: 10px;
- }
-
-
- #getting-started {
- border-top: 1px solid #ccc;
- margin-top: 25px;
- padding-top: 15px;
- }
- #getting-started h1 {
- margin: 0;
- font-size: 20px;
- }
- #getting-started h2 {
- margin: 0;
- font-size: 14px;
- font-weight: normal;
- color: #333;
- margin-bottom: 25px;
- }
- #getting-started ol {
- margin-left: 0;
- padding-left: 0;
- }
- #getting-started li {
- font-size: 18px;
- color: #888;
- margin-bottom: 25px;
- }
- #getting-started li h2 {
- margin: 0;
- font-weight: normal;
- font-size: 18px;
- color: #333;
- }
- #getting-started li p {
- color: #555;
- font-size: 13px;
- }
-
-
- #sidebar ul {
- margin-left: 0;
- padding-left: 0;
- }
- #sidebar ul h3 {
- margin-top: 25px;
- font-size: 16px;
- padding-bottom: 10px;
- border-bottom: 1px solid #ccc;
- }
- #sidebar li {
- list-style-type: none;
- }
- #sidebar ul.links li {
- margin-bottom: 5px;
- }
-
- .filename {
- font-style: italic;
- }
- </style>
- <script type="text/javascript">
- function about() {
- info = document.getElementById('about-content');
- if (window.XMLHttpRequest)
- { xhr = new XMLHttpRequest(); }
- else
- { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
- xhr.open("GET","rails/info/properties",false);
- xhr.send("");
- info.innerHTML = xhr.responseText;
- info.style.display = 'block'
- }
- </script>
- </head>
- <body>
- <div id="page">
- <div id="sidebar">
- <ul id="sidebar-items">
- <li>
- <h3>Browse the documentation</h3>
- <ul class="links">
- <li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li>
- <li><a href="http://api.rubyonrails.org/">Rails API</a></li>
- <li><a href="http://www.ruby-doc.org/core/">Ruby core</a></li>
- <li><a href="http://www.ruby-doc.org/stdlib/">Ruby standard library</a></li>
- </ul>
- </li>
- </ul>
- </div>
-
- <div id="content">
- <div id="header">
- <h1>Welcome aboard</h1>
- <h2>You&rsquo;re riding Ruby on Rails!</h2>
- </div>
-
- <div id="about">
- <h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
- <div id="about-content" style="display: none"></div>
- </div>
-
- <div id="getting-started">
- <h1>Getting started</h1>
- <h2>Here&rsquo;s how to get rolling:</h2>
-
- <ol>
- <li>
- <h2>Use <code>rails generate</code> to create your models and controllers</h2>
- <p>To see all available options, run it without parameters.</p>
- </li>
-
- <li>
- <h2>Set up a default route and remove <span class="filename">public/index.html</span></h2>
- <p>Routes are set up in <span class="filename">config/routes.rb</span>.</p>
- </li>
-
- <li>
- <h2>Create your database</h2>
- <p>Run <code>rake db:create</code> to create your database. If you're not using SQLite (the default), edit <span class="filename">config/database.yml</span> with your username and password.</p>
- </li>
- </ol>
- </div>
- </div>
-
- <div id="footer">&nbsp;</div>
- </div>
- </body>
-</html>
View
15,075 vendor/assets/javascripts/ember.js
15,075 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.

0 comments on commit b51e20b

Please sign in to comment.