Skip to content
Browse files

Init

  • Loading branch information...
0 parents commit 32712872f11f9155c7ecea5acd10bf15c8354175 @1602 1602 committed
1 .gitignore
@@ -0,0 +1 @@
+node_modules
1 Procfile
@@ -0,0 +1 @@
+web: node server.js
3 app/controllers/application_controller.js
@@ -0,0 +1,3 @@
+before('protect from forgery', function () {
+ protectFromForgery('596b3f1de3e79c98056023b656f83a58644050b9');
+});
78 app/controllers/messages_controller.js
@@ -0,0 +1,78 @@
+load('application');
+
+before(loadMessage, {only: ['show', 'edit', 'update', 'destroy']});
+
+action('new', function () {
+ this.title = 'New message';
+ this.message = new Message;
+ render();
+});
+
+action(function create() {
+ Message.create(req.body.Message, function (err, message) {
+ if (err) {
+ flash('error', 'Message can not be created');
+ render('new', {
+ message: message,
+ title: 'New message'
+ });
+ } else {
+ flash('info', 'Message created');
+ redirect(path_to.messages());
+ }
+ });
+});
+
+action(function index() {
+ this.title = 'Messages index';
+ Message.all(function (err, messages) {
+ render({
+ messages: messages
+ });
+ });
+});
+
+action(function show() {
+ this.title = 'Message show';
+ render();
+});
+
+action(function edit() {
+ this.title = 'Message edit';
+ render();
+});
+
+action(function update() {
+ this.message.updateAttributes(body.Message, function (err) {
+ if (!err) {
+ flash('info', 'Message updated');
+ redirect(path_to.message(this.message));
+ } else {
+ flash('error', 'Message can not be updated');
+ this.title = 'Edit message details';
+ render('edit');
+ }
+ }.bind(this));
+});
+
+action(function destroy() {
+ this.message.destroy(function (error) {
+ if (error) {
+ flash('error', 'Can not destroy message');
+ } else {
+ flash('info', 'Message successfully removed');
+ }
+ send("'" + path_to.messages() + "'");
+ });
+});
+
+function loadMessage() {
+ Message.find(params.id, function (err, message) {
+ if (err || !message) {
+ redirect(path_to.messages());
+ } else {
+ this.message = message;
+ next();
+ }
+ }.bind(this));
+}
2 app/helpers/messages_helper.js
@@ -0,0 +1,2 @@
+module.exports = {
+};
0 app/models/message.js
No changes.
41 app/views/layouts/application_layout.ejs
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title><%= title %></title>
+ <%- stylesheet_link_tag('bootstrap', 'style', 'bootstrap-responsive') %>
+ <%- javascript_include_tag('http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', 'bootstrap', 'rails', 'application') %>
+ <%- csrf_meta_tag() %>
+ </head>
+ <body>
+ <div class="navbar">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="#">Project name</a>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <% var flash = request.flash('info').pop(); if (flash) { %>
+ <div class="alert alert-info">
+ <a class="close" data-dismiss="alert">×</a>
+ <%- flash %>
+ </div>
+ <% } %>
+
+ <% flash = request.flash('error').pop(); if (flash) { %>
+ <div class="alert alert-error">
+ <a class="close" data-dismiss="alert">×</a>
+ <%- flash %>
+ </div>
+ <% }; %>
+
+ <%- body %>
+
+ <hr />
+ <footer>
+ <p>&copy; Company 2012</p>
+ </footer>
+ </div>
+ </body>
+</html>
41 app/views/layouts/messages_layout.ejs
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title><%= title %></title>
+ <%- stylesheet_link_tag('bootstrap', 'style', 'bootstrap-responsive') %>
+ <%- javascript_include_tag('http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', 'bootstrap', 'rails', 'application') %>
+ <%- csrf_meta_tag() %>
+ </head>
+ <body>
+ <div class="navbar">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="#">Project name</a>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <% var flash = request.flash('info').pop(); if (flash) { %>
+ <div class="alert alert-info">
+ <a class="close" data-dismiss="alert">×</a>
+ <%- flash %>
+ </div>
+ <% } %>
+
+ <% flash = request.flash('error').pop(); if (flash) { %>
+ <div class="alert alert-error">
+ <a class="close" data-dismiss="alert">×</a>
+ <%- flash %>
+ </div>
+ <% }; %>
+
+ <%- body %>
+
+ <hr />
+ <footer>
+ <p>&copy; Company 2012</p>
+ </footer>
+ </div>
+ </body>
+</html>
25 app/views/messages/_form.ejs
@@ -0,0 +1,25 @@
+<%- errorMessagesFor(message) %>
+<div class="control-group">
+ <%- form.label("firstname", false, {class: "control-label"}) %>
+ <div class="controls">
+ <%- form.input("firstname") %>
+ </div>
+</div>
+<div class="control-group">
+ <%- form.label("lastname", false, {class: "control-label"}) %>
+ <div class="controls">
+ <%- form.input("lastname") %>
+ </div>
+</div>
+<div class="control-group">
+ <%- form.label("phone", false, {class: "control-label"}) %>
+ <div class="controls">
+ <%- form.input("phone") %>
+ </div>
+</div>
+<div class="control-group">
+ <%- form.label("message", false, {class: "control-label"}) %>
+ <div class="controls">
+ <%- form.input("message") %>
+ </div>
+</div>
9 app/views/messages/edit.ejs
@@ -0,0 +1,9 @@
+<div class="page-header"><h1>Edit message</h1></div>
+
+<% form_for(message, {action: path_to.message(message), method: 'PUT', id: "message_form", class: 'form-horizontal'}, function (form) { %>
+ <%- partial('messages/form.ejs', {locals: {form: form, message: message}}) %>
+ <div class="form-actions">
+ <%- form.submit('<i class="icon-ok icon-white"></i> Update message', {class: 'btn btn-primary'}) %> or
+ <%- link_to('Cancel', path_to.message(message), {class: 'btn'}) %>
+ </div>
+<% });%>
39 app/views/messages/index.ejs
@@ -0,0 +1,39 @@
+<div class="page-header">
+ <h1>Index of message</h1>
+</div>
+
+<div class="row">
+ <div class="span12">
+ <p><%- link_to('<i class="icon-plus icon-white"></i> New message', path_to.new_message(), {class: 'btn btn-primary'}) %></>
+ </div>
+</div>
+
+<div class="row">
+ <div class="span12">
+ <% if (messages.length > 0) { %>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% messages.forEach(function (message) { %>
+ <tr>
+ <td><strong><%- link_to('message #' + message.id, path_to.message(message)) %></strong></td>
+ <td>
+ <%- link_to('<i class="icon-edit"></i> Edit', path_to.edit_message(message), {class: 'btn btn-mini'}) %>
+ <%- link_to('<i class="icon-remove icon-white"></i> Delete', path_to.message(message), {class: 'btn btn-mini btn-danger', method: 'delete', remote: true, jsonp: '(function (u) {location.href = u;})'}) %>
+ </td>
+ </tr>
+ <% }); %>
+ </tbody>
+ </table>
+ <% } else { %>
+ <p class="alert alert-block alert-info">
+ <strong>No messages were found.</strong>
+ </p>
+ <% } %>
+ </div>
+</div>
11 app/views/messages/new.ejs
@@ -0,0 +1,11 @@
+<div class="page-header">
+ <h1>New message</h1>
+</div>
+
+<% form_for(message, {action: path_to.messages(), method: 'POST', id: "message_form", class: 'form-horizontal'}, function (form) { %>
+ <%- partial('messages/form.ejs', {locals: {form: form, message: message}}) %>
+ <div class="form-actions">
+ <%- form.submit('<i class="icon-ok icon-white"></i> Create message', {class: 'btn btn-primary'}) %> or
+ <%- link_to('Cancel', path_to.messages(), {class: 'btn'}) %>
+ </div>
+<% });%>
20 app/views/messages/show.ejs
@@ -0,0 +1,20 @@
+<div class="page-header">
+ <h1>Details of message</h1>
+</div>
+
+
+<table class="table table-bordered">
+ <tbody>
+ <tr><th>firstname</th><td><%= message.firstname %></td></tr>
+ <tr><th>lastname</th><td><%= message.lastname %></td></tr>
+ <tr><th>phone</th><td><%= message.phone %></td></tr>
+ <tr><th>message</th><td><%= message.message %></td></tr>
+ </tbody>
+</table>
+
+<div class="well">
+ <%- link_to('<i class="icon-edit icon-white"></i> Edit', path_to.edit_message(message), {class: 'btn btn-primary'}) %>
+ <%- link_to('<i class="icon-remove icon-white"></i> Delete', path_to.message(message), {class: 'btn btn-danger', method: 'delete', remote: true, jsonp: '(function (u) { location.href = u; })'}) %>
+ or
+ <%- link_to('Back to index', path_to.messages()) %>
+</div>
7 config/database.json
@@ -0,0 +1,7 @@
+{ "development":
+ { "driver": "memory"
+ }
+, "test":
+ { "driver": "memory"
+ }
+}
17 config/environment.js
@@ -0,0 +1,17 @@
+var express = require('express');
+
+app.configure(function(){
+ var cwd = process.cwd();
+
+ app.use(express.static(cwd + '/public', {maxAge: 86400000}));
+ app.set('view engine', 'ejs');
+ app.set('view options', {complexNames: true});
+ app.set('jsDirectory', '/javascripts/');
+ app.set('cssDirectory', '/stylesheets/');
+ app.use(express.bodyParser());
+ app.use(express.cookieParser('secret'));
+ app.use(express.session({secret: 'secret'}));
+ app.use(express.methodOverride());
+ app.use(app.router);
+});
+
9 config/environments/development.js
@@ -0,0 +1,9 @@
+app.configure('development', function () {
+ app.disable('view cache');
+ app.disable('model cache');
+ app.disable('eval cache');
+ app.enable('log actions');
+ app.enable('env info');
+ app.use(require('express').errorHandler({ dumpExceptions: true, showStack: true }));
+});
+
11 config/environments/production.js
@@ -0,0 +1,11 @@
+app.configure('production', function () {
+ app.enable('view cache');
+ app.enable('model cache');
+ app.enable('eval cache');
+ app.enable('merge javascripts');
+ app.enable('merge stylesheets');
+ app.disable('assets timestamps');
+ app.use(require('express').errorHandler());
+ app.settings.quiet = true;
+});
+
8 config/environments/test.js
@@ -0,0 +1,8 @@
+app.configure('test', function(){
+ app.use(require('express').errorHandler({ dumpExceptions: true, showStack: true }));
+ app.settings.quiet = true;
+ app.enable('view cache');
+ app.enable('model cache');
+ app.enable('eval cache');
+});
+
51 config/initializers/db-tools.js
@@ -0,0 +1,51 @@
+railway.tools.database = function db() {
+ var action = process.argv[3];
+ switch (action) {
+ case 'migrate':
+ case 'update':
+ perform(action, process.exit);
+ break;
+ default:
+ console.log('Unknown action', action);
+ break;
+ }
+};
+
+railway.tools.database.help = {
+ shortcut: 'db',
+ usage: 'db [migrate|update]',
+ description: 'Migrate or update database(s)'
+};
+
+function getUniqueSchemas() {
+ var schemas = [];
+ Object.keys(app.models).forEach(function (modelName) {
+ var Model = app.models[modelName];
+ var schema = Model.schema;
+ if (!~schemas.indexOf(schema)) {
+ schemas.push(schema);
+ }
+ });
+ return schemas;
+}
+
+function perform(action, callback) {
+ console.log('Perform', action, 'on');
+ var wait = 0;
+ getUniqueSchemas().forEach(function (schema) {
+ if (schema['auto' + action]) {
+ console.log(' - ' + schema.name);
+ wait += 1;
+ process.nextTick(function () {
+ schema['auto' + action](done);
+ });
+ }
+ });
+
+ if (wait === 0) done(); else console.log(wait);
+
+ function done() {
+ if (--wait === 0) callback();
+ }
+}
+
8 config/routes.js
@@ -0,0 +1,8 @@
+exports.routes = function (map) {
+ map.resources('messages');
+
+ // Generic routes. Add all your routes below this line
+ // feel free to remove generic routes
+ map.all(':controller/:action');
+ map.all(':controller/:action/:id');
+};
29 db/schema.js
@@ -0,0 +1,29 @@
+/*
+ db/schema.js contains database schema description for application models
+ by default (when using jugglingdb as ORM) this file uses database connection
+ described in config/database.json. But it's possible to use another database
+ connections and multiple different schemas, docs available at
+
+ http://railwayjs.com/orm.html
+
+ Example of model definition:
+
+ define('User', function () {
+ property('email', String, { index: true });
+ property('password', String);
+ property('activated', Boolean, {default: false});
+ });
+
+ Example of schema configured without config/database.json (heroku redistogo addon):
+ schema('redis', {url: process.env.REDISTOGO_URL}, function () {
+ // model definitions here
+ });
+
+*/
+
+var Message = describe('Message', function () {
+ property('firstname', String);
+ property('lastname', String);
+ property('phone', String);
+ property('message', String);
+});
3 npmfile.js
@@ -0,0 +1,3 @@
+require('ejs-ext');
+require('jugglingdb');
+require('seedjs');
21 package.json
@@ -0,0 +1,21 @@
+{ "name": "default"
+, "version": "0.0.1"
+, "engines": ["node >= 0.4.0"]
+, "main": "server.js"
+, "dependencies":
+ { "ejs": "*"
+ , "ejs-ext": "*"
+ , "express": "~2.x"
+ , "railway": ">= 0.2.6"
+ , "jugglingdb": ">= 0.1.0"
+ , "coffee-script": ">= 1.1.1"
+ },
+ "devDependencies":
+ { "nodeunit": "*"
+ , "sinon": "*"
+ , "semicov": "*"
+ }
+, "scripts":
+ { "test": "nodeunit test/*/*"
+ }
+}
BIN public/favicon.ico
Binary file not shown.
BIN public/images/glyphicons-halflings-white.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN public/images/glyphicons-halflings.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 public/index.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Welcome to Railway</title>
+ <link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css">
+ <meta name="viewport" content="width=500, initial-scale=0.5">
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+ <script type="text/javascript" src="/javascripts/rails.js"></script>
+ </head>
+ <body>
+ <div class="container">
+ <div class="page-header">
+ <h1 style="text-align: center; padding: 35px;">Welcome to Railway</h1>
+ </div>
+ <h6 style="text-align: center;">
+ <a href="/railway/environment.json" id="show-env-info-link" data-remote="true" data-jsonp="load">Information about application environment</a>
+ </h6>
+ <div id="env-info"></div>
+ <hr />
+ <div class="row">
+ <div class="span8 offset4">
+ <a href="http://github.com/1602/express-on-railway"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://d3nwyuy0nl342s.cloudfront.net/img/e6bef7a091f5f3138b8cd40bc3e114258dd68ddf/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub"></a>
+ <div class="content">
+ <h6>1. Start with <a href="http://railwayjs.com/#generators">generators</a></h6>
+ <p> this is a fastest way to create application:</p>
+ <pre>railway g crud post title content date:date published:boolean</pre>
+ <h6>2. Then describe <a href="http://railwayjs.com/#routing">routes</a></h6>
+ <p>in <code>config/routes.js</code> and remove this file (<code>public/index.html</code>)</p>
+ <pre>exports.routes = function (map) {
+ map.get('/', 'posts#index');
+};</pre>
+ <h6>3. Design your <a href="http://railwayjs.com/#orm">database</a></h6>
+ <p>in <code>db/schema.js</code> and describe models in <code>app/models/*</code></p>
+ <h6>4. Keep you <a href="http://railwayjs.com/#controllers">controllers</a> thin</h6>
+ <p>write tests, and good luck.<br> If you have any questions feel free to ask at <a href="http://groups.google.com/group/railwayjs">RailwayJS Google Group</a>.</p>
+ <p>Track RailwayJS project state on <a href="https://trello.com/board/railwayjs/4f0a0d49128365065e008a1d">trello board</a>, vote for features, discuss. Help us to get better!</p>
+ </div>
+ </div>
+
+ <div class="span4">
+ <p>
+ <h6>5. Links in sidebar</h6>
+ <ul style="padding-left: 0px;">
+ <li><a href="http://railwayjs.com">RailwayJS project docs</a></li>
+ <li><a href="http://modules.node-js.ru">NodeJS modules rating</a></li>
+ <li><a href="http://expressjs.com">ExpressJS project homepage</a></li>
+ <li><a href="http://mongoosejs.com">MongooseJS ORM project homepage</a></li>
+ <li><a href="http://railwayjs.com/juggling.html">Try JugglingDB in your browser, docs</a></li>
+ </ul>
+ </p>
+ </div>
+
+ </div>
+ <footer>
+ </footer>
+ <script>
+ function load(data) {
+ $('#show-env-info-link').hide();
+ if (data.forbidden) {
+ return '';
+ }
+ var html = '<table class=".zebra-striped">';
+ html += makeList('Versions', data.versions);
+ html += makeList('Settings', data.settings);
+ html += makeList('Application', data.application);
+ html += makeList('ENV', data.env);
+ html += '</table>';
+
+ $('#env-info').html(html);
+ }
+
+ function makeList(title, obj) {
+ var res = '<tr><td colspan="2"><h6>' + title + '</h6></td></tr>';
+ for (var i in obj) {
+ res += '<tr><td>' + i + '</td><td>' + toS(obj[i]) + '</td></tr>';
+ }
+ return res;
+ }
+
+ function toS(obj) {
+ if (obj instanceof Array) {
+ return obj.join('<br />');
+ } else if (typeof obj === 'object') {
+ var s = [];
+ for (var i in obj) {
+ s.push(i + ': ' + obj[i]);
+ }
+ return s.join(', ');
+ } else {
+ return obj;
+ }
+ }
+ </script>
+ </div>
+ </body>
+</html>
1 public/javascripts/application.js
@@ -0,0 +1 @@
+// place your application-wide javascripts here
1,720 public/javascripts/bootstrap.js
1,720 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
139 public/javascripts/rails.js
@@ -0,0 +1,139 @@
+jQuery(function ($) {
+ var csrf_token = $('meta[name=csrf-token]').attr('content'),
+ csrf_param = $('meta[name=csrf-param]').attr('content');
+
+ $.fn.extend({
+ /**
+ * Triggers a custom event on an element and returns the event result
+ * this is used to get around not being able to ensure callbacks are placed
+ * at the end of the chain.
+ *
+ * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
+ * own events and placing ourselves at the end of the chain.
+ */
+ triggerAndReturn: function (name, data) {
+ var event = new $.Event(name);
+ this.trigger(event, data);
+
+ return event.result !== false;
+ },
+
+ /**
+ * Handles execution of remote calls firing overridable events along the way
+ */
+ callRemote: function () {
+ var el = this,
+ method = el.attr('method') || el.attr('data-method') || 'GET',
+ url = el.attr('action') || el.attr('href'),
+ dataType = el.attr('data-type') || 'script';
+
+ if (el.attr('data-jsonp')) {
+ dataType = 'text';
+ }
+
+ if (url === undefined) {
+ throw "No URL specified for remote call (action or href must be present).";
+ } else {
+ if (el.triggerAndReturn('ajax:before')) {
+ var data = el.is('form') ? el.serializeArray() : [];
+ $.ajax({
+ url: url,
+ data: data,
+ dataType: dataType,
+ type: method.toUpperCase(),
+ beforeSend: function (xhr) {
+ el.trigger('ajax:loading', xhr);
+ },
+ success: function (data, status, xhr) {
+ if (el.attr('data-jsonp')) {
+ eval(el.attr('data-jsonp') + '(' + data + ')');
+ }
+ el.trigger('ajax:success', [data, status, xhr]);
+ },
+ complete: function (xhr) {
+ el.trigger('ajax:complete', xhr);
+ },
+ error: function (xhr, status, error) {
+ el.trigger('ajax:failure', [xhr, status, error]);
+ }
+ });
+ }
+
+ el.trigger('ajax:after');
+ }
+ }
+ });
+
+ /**
+ * confirmation handler
+ */
+ $('a[data-confirm],input[data-confirm]').live('click', function () {
+ var el = $(this);
+ if (el.triggerAndReturn('confirm')) {
+ if (!confirm(el.attr('data-confirm'))) {
+ return false;
+ }
+ }
+ });
+
+
+ /**
+ * remote handlers
+ */
+ $('form[data-remote]').live('submit', function (e) {
+ $(this).callRemote();
+ e.preventDefault();
+ });
+
+ $('a[data-remote],input[data-remote]').live('click', function (e) {
+ $(this).callRemote();
+ e.preventDefault();
+ });
+
+ $('a[data-method]:not([data-remote])').live('click', function (e){
+ var link = $(this),
+ href = link.attr('href'),
+ method = link.attr('data-method'),
+ form = $('<form method="post" action="'+href+'"></form>'),
+ metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';
+
+ if (csrf_param != null && csrf_token != null) {
+ metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
+ }
+
+ form.hide()
+ .append(metadata_input)
+ .appendTo('body');
+
+ e.preventDefault();
+ form.submit();
+ });
+
+ /**
+ * disable-with handlers
+ */
+ var disable_with_input_selector = 'input[data-disable-with]';
+ var disable_with_form_remote_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';
+ var disable_with_form_not_remote_selector = 'form:not([data-remote]):has(' + disable_with_input_selector + ')';
+
+ var disable_with_input_function = function () {
+ $(this).find(disable_with_input_selector).each(function () {
+ var input = $(this);
+ input.data('enable-with', input.val())
+ .attr('value', input.attr('data-disable-with'))
+ .attr('disabled', 'disabled');
+ });
+ };
+
+ $(disable_with_form_remote_selector).live('ajax:before', disable_with_input_function);
+ $(disable_with_form_not_remote_selector).live('submit', disable_with_input_function);
+
+ $(disable_with_form_remote_selector).live('ajax:complete', function () {
+ $(this).find(disable_with_input_selector).each(function () {
+ var input = $(this);
+ input.removeAttr('disabled')
+ .val(input.data('enable-with'));
+ });
+ });
+
+});
581 public/stylesheets/bootstrap-responsive.css
@@ -0,0 +1,581 @@
+/*!
+ * Bootstrap Responsive v2.0.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before, .clearfix:after {
+ display: table;
+ content: "";
+}
+.clearfix:after {
+ clear: both;
+}
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+@media (max-width: 480px) {
+ .nav-collapse {
+ -webkit-transform: translate3d(0, 0, 0);
+ }
+ .page-header h1 small {
+ display: block;
+ line-height: 18px;
+ }
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {
+ display: block;
+ width: 100%;
+ min-height: 28px;
+ /* Make inputs at least the height of their button counterpart */
+
+ /* Makes inputs behave like true block-level elements */
+
+ -webkit-box-sizing: border-box;
+ /* Older Webkit */
+
+ -moz-box-sizing: border-box;
+ /* Older FF */
+
+ -ms-box-sizing: border-box;
+ /* IE8 */
+
+ box-sizing: border-box;
+ /* CSS3 spec*/
+
+ }
+ .input-prepend input[class*="span"], .input-append input[class*="span"] {
+ width: auto;
+ }
+ input[type="checkbox"], input[type="radio"] {
+ border: 1px solid #ccc;
+ }
+ .form-horizontal .control-group > label {
+ float: none;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+ .form-horizontal .controls {
+ margin-left: 0;
+ }
+ .form-horizontal .control-list {
+ padding-top: 0;
+ }
+ .form-horizontal .form-actions {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ .modal {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ right: 10px;
+ width: auto;
+ margin: 0;
+ }
+ .modal.fade.in {
+ top: auto;
+ }
+ .modal-header .close {
+ padding: 10px;
+ margin: -10px;
+ }
+ .carousel-caption {
+ position: static;
+ }
+}
+@media (max-width: 767px) {
+ .container {
+ width: auto;
+ padding: 0 20px;
+ }
+ .row-fluid {
+ width: 100%;
+ }
+ .row {
+ margin-left: 0;
+ }
+ .row > [class*="span"], .row-fluid > [class*="span"] {
+ float: none;
+ display: block;
+ width: auto;
+ margin: 0;
+ }
+}
+@media (min-width: 768px) and (max-width: 979px) {
+ .row {
+ margin-left: -20px;
+ *zoom: 1;
+ }
+ .row:before, .row:after {
+ display: table;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ margin-left: 20px;
+ }
+ .span1 {
+ width: 42px;
+ }
+ .span2 {
+ width: 104px;
+ }
+ .span3 {
+ width: 166px;
+ }
+ .span4 {
+ width: 228px;
+ }
+ .span5 {
+ width: 290px;
+ }
+ .span6 {
+ width: 352px;
+ }
+ .span7 {
+ width: 414px;
+ }
+ .span8 {
+ width: 476px;
+ }
+ .span9 {
+ width: 538px;
+ }
+ .span10 {
+ width: 600px;
+ }
+ .span11 {
+ width: 662px;
+ }
+ .span12, .container {
+ width: 724px;
+ }
+ .offset1 {
+ margin-left: 82px;
+ }
+ .offset2 {
+ margin-left: 144px;
+ }
+ .offset3 {
+ margin-left: 206px;
+ }
+ .offset4 {
+ margin-left: 268px;
+ }
+ .offset5 {
+ margin-left: 330px;
+ }
+ .offset6 {
+ margin-left: 392px;
+ }
+ .offset7 {
+ margin-left: 454px;
+ }
+ .offset8 {
+ margin-left: 516px;
+ }
+ .offset9 {
+ margin-left: 578px;
+ }
+ .offset10 {
+ margin-left: 640px;
+ }
+ .offset11 {
+ margin-left: 702px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before, .row-fluid:after {
+ display: table;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.762430939%;
+ }
+ .row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid > .span1 {
+ width: 5.801104972%;
+ }
+ .row-fluid > .span2 {
+ width: 14.364640883%;
+ }
+ .row-fluid > .span3 {
+ width: 22.928176794%;
+ }
+ .row-fluid > .span4 {
+ width: 31.491712705%;
+ }
+ .row-fluid > .span5 {
+ width: 40.055248616%;
+ }
+ .row-fluid > .span6 {
+ width: 48.618784527%;
+ }
+ .row-fluid > .span7 {
+ width: 57.182320438000005%;
+ }
+ .row-fluid > .span8 {
+ width: 65.74585634900001%;
+ }
+ .row-fluid > .span9 {
+ width: 74.30939226%;
+ }
+ .row-fluid > .span10 {
+ width: 82.87292817100001%;
+ }
+ .row-fluid > .span11 {
+ width: 91.436464082%;
+ }
+ .row-fluid > .span12 {
+ width: 99.999999993%;
+ }
+ input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 32px;
+ }
+ input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 94px;
+ }
+ input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 156px;
+ }
+ input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 218px;
+ }
+ input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 280px;
+ }
+ input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 342px;
+ }
+ input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 404px;
+ }
+ input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 466px;
+ }
+ input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 528px;
+ }
+ input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 590px;
+ }
+ input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 652px;
+ }
+ input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 714px;
+ }
+}
+@media (max-width: 979px) {
+ body {
+ padding-top: 0;
+ }
+ .navbar-fixed-top {
+ position: static;
+ margin-bottom: 18px;
+ }
+ .navbar-fixed-top .navbar-inner {
+ padding: 5px;
+ }
+ .navbar .container {
+ width: auto;
+ padding: 0;
+ }
+ .navbar .brand {
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0 0 0 -5px;
+ }
+ .navbar .nav-collapse {
+ clear: left;
+ }
+ .navbar .nav {
+ float: none;
+ margin: 0 0 9px;
+ }
+ .navbar .nav > li {
+ float: none;
+ }
+ .navbar .nav > li > a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > .divider-vertical {
+ display: none;
+ }
+ .navbar .nav .nav-header {
+ color: #999999;
+ text-shadow: none;
+ }
+ .navbar .nav > li > a, .navbar .dropdown-menu a {
+ padding: 6px 15px;
+ font-weight: bold;
+ color: #999999;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ }
+ .navbar .dropdown-menu li + li a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover {
+ background-color: #222222;
+ }
+ .navbar .dropdown-menu {
+ position: static;
+ top: auto;
+ left: auto;
+ float: none;
+ display: block;
+ max-width: none;
+ margin: 0 15px;
+ padding: 0;
+ background-color: transparent;
+ border: none;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar .dropdown-menu:before, .navbar .dropdown-menu:after {
+ display: none;
+ }
+ .navbar .dropdown-menu .divider {
+ display: none;
+ }
+ .navbar-form, .navbar-search {
+ float: none;
+ padding: 9px 15px;
+ margin: 9px 0;
+ border-top: 1px solid #222222;
+ border-bottom: 1px solid #222222;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ }
+ .navbar .nav.pull-right {
+ float: none;
+ margin-left: 0;
+ }
+ .navbar-static .navbar-inner {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ .btn-navbar {
+ display: block;
+ }
+ .nav-collapse {
+ overflow: hidden;
+ height: 0;
+ }
+}
+@media (min-width: 980px) {
+ .nav-collapse.collapse {
+ height: auto !important;
+ }
+}
+@media (min-width: 1200px) {
+ .row {
+ margin-left: -30px;
+ *zoom: 1;
+ }
+ .row:before, .row:after {
+ display: table;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ margin-left: 30px;
+ }
+ .span1 {
+ width: 70px;
+ }
+ .span2 {
+ width: 170px;
+ }
+ .span3 {
+ width: 270px;
+ }
+ .span4 {
+ width: 370px;
+ }
+ .span5 {
+ width: 470px;
+ }
+ .span6 {
+ width: 570px;
+ }
+ .span7 {
+ width: 670px;
+ }
+ .span8 {
+ width: 770px;
+ }
+ .span9 {
+ width: 870px;
+ }
+ .span10 {
+ width: 970px;
+ }
+ .span11 {
+ width: 1070px;
+ }
+ .span12, .container {
+ width: 1170px;
+ }
+ .offset1 {
+ margin-left: 130px;
+ }
+ .offset2 {
+ margin-left: 230px;
+ }
+ .offset3 {
+ margin-left: 330px;
+ }
+ .offset4 {
+ margin-left: 430px;
+ }
+ .offset5 {
+ margin-left: 530px;
+ }
+ .offset6 {
+ margin-left: 630px;
+ }
+ .offset7 {
+ margin-left: 730px;
+ }
+ .offset8 {
+ margin-left: 830px;
+ }
+ .offset9 {
+ margin-left: 930px;
+ }
+ .offset10 {
+ margin-left: 1030px;
+ }
+ .offset11 {
+ margin-left: 1130px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before, .row-fluid:after {
+ display: table;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.564102564%;
+ }
+ .row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid > .span1 {
+ width: 5.982905983%;
+ }
+ .row-fluid > .span2 {
+ width: 14.529914530000001%;
+ }
+ .row-fluid > .span3 {
+ width: 23.076923077%;
+ }
+ .row-fluid > .span4 {
+ width: 31.623931624%;
+ }
+ .row-fluid > .span5 {
+ width: 40.170940171000005%;
+ }
+ .row-fluid > .span6 {
+ width: 48.717948718%;
+ }
+ .row-fluid > .span7 {
+ width: 57.264957265%;
+ }
+ .row-fluid > .span8 {
+ width: 65.81196581200001%;
+ }
+ .row-fluid > .span9 {
+ width: 74.358974359%;
+ }
+ .row-fluid > .span10 {
+ width: 82.905982906%;
+ }
+ .row-fluid > .span11 {
+ width: 91.45299145300001%;
+ }
+ .row-fluid > .span12 {
+ width: 100%;
+ }
+ input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 60px;
+ }
+ input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 160px;
+ }
+ input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 260px;
+ }
+ input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 360px;
+ }
+ input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 460px;
+ }
+ input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 560px;
+ }
+ input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 660px;
+ }
+ input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 760px;
+ }
+ input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 860px;
+ }
+ input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 960px;
+ }
+ input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 1060px;
+ }
+ input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 1160px;
+ }
+ .thumbnails {
+ margin-left: -30px;
+ }
+ .thumbnails > li {
+ margin-left: 30px;
+ }
+}
3,496 public/stylesheets/bootstrap.css
3,496 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
0 public/stylesheets/style.css
No changes.
10 server.js
@@ -0,0 +1,10 @@
+#!/usr/bin/env node
+
+var app = module.exports = require('railway').createServer();
+
+if (!module.parent) {
+ var port = process.env.PORT || 3000
+ app.listen(port);
+ console.log("Railway server listening on port %d within %s environment", port, app.settings.env);
+}
+
123 test/controllers/messages_controller_test.js
@@ -0,0 +1,123 @@
+require('../test_helper.js').controller('messages', module.exports);
+
+var sinon = require('sinon');
+
+function ValidAttributes () {
+ return {
+ firstname: '',
+ lastname: '',
+ phone: '',
+ message: ''
+ };
+}
+
+exports['messages controller'] = {
+
+ 'GET new': function (test) {
+ test.get('/messages/new', function () {
+ test.success();
+ test.render('new');
+ test.render('form.' + app.set('view engine'));
+ test.done();
+ });
+ },
+
+ 'GET index': function (test) {
+ test.get('/messages', function () {
+ test.success();
+ test.render('index');
+ test.done();
+ });
+ },
+
+ 'GET edit': function (test) {
+ var find = Message.find;
+ Message.find = sinon.spy(function (id, callback) {
+ callback(null, new Message);
+ });
+ test.get('/messages/42/edit', function () {
+ test.ok(Message.find.calledWith('42'));
+ Message.find = find;
+ test.success();
+ test.render('edit');
+ test.done();
+ });
+ },
+
+ 'GET show': function (test) {
+ var find = Message.find;
+ Message.find = sinon.spy(function (id, callback) {
+ callback(null, new Message);
+ });
+ test.get('/messages/42', function (req, res) {
+ test.ok(Message.find.calledWith('42'));
+ Message.find = find;
+ test.success();
+ test.render('show');
+ test.done();
+ });
+ },
+
+ 'POST create': function (test) {
+ var message = new ValidAttributes;
+ var create = Message.create;
+ Message.create = sinon.spy(function (data, callback) {
+ test.strictEqual(data, message);
+ callback(null, message);
+ });
+ test.post('/messages', {Message: message}, function () {
+ test.redirect('/messages');
+ test.flash('info');
+ test.done();
+ });
+ },
+
+ 'POST create fail': function (test) {
+ var message = new ValidAttributes;
+ var create = Message.create;
+ Message.create = sinon.spy(function (data, callback) {
+ test.strictEqual(data, message);
+ callback(new Error, message);
+ });
+ test.post('/messages', {Message: message}, function () {
+ test.success();
+ test.render('new');
+ test.flash('error');
+ test.done();
+ });
+ },
+
+ 'PUT update': function (test) {
+ Message.find = sinon.spy(function (id, callback) {
+ test.equal(id, 1);
+ callback(null, {id: 1, updateAttributes: function (data, cb) { cb(null); }});
+ });
+ test.put('/messages/1', new ValidAttributes, function () {
+ test.redirect('/messages/1');
+ test.flash('info');
+ test.done();
+ });
+ },
+
+ 'PUT update fail': function (test) {
+ Message.find = sinon.spy(function (id, callback) {
+ test.equal(id, 1);
+ callback(null, {id: 1, updateAttributes: function (data, cb) { cb(new Error); }});
+ });
+ test.put('/messages/1', new ValidAttributes, function () {
+ test.success();
+ test.render('edit');
+ test.flash('error');
+ test.done();
+ });
+ },
+
+ 'DELETE destroy': function (test) {
+ test.done();
+ },
+
+ 'DELETE destroy fail': function (test) {
+ test.done();
+ }
+};
+
204 test/test_helper.js
@@ -0,0 +1,204 @@
+var app = require('railway').createServer();
+app.enable('quiet');
+app.enable('models cache');
+app.enable('eval cache');
+
+
+exports.controller = function (controllerName, exp) {
+
+ exports.init(exp);
+
+ // trick
+ it('init', function (test) { process.nextTick(function () { test.done(); }); });
+ var nu = process.env.NODEUNIT_PATH || 'nodeunit';
+
+ var http = require('http');
+ var sinon = require('sinon');
+ var assert = require(require.resolve(nu).replace(/index\.js$/, 'lib/assert'));
+ var nodeunit = require(nu);
+
+ assert.render = function (template, message) {
+ if (!this.res.render.calledWith(template) && !this.res.render.calledWith(controllerName + '/' + template)) {
+ assert.fail([template, controllerName + '/' + template],
+ this.res.render.args.map(function (x) { return x[0]; }),
+ message || 'Render template',
+ 'in',
+ assert.render);
+ }
+ };
+
+ assert.redirect = function (path, message) {
+ if (this.res.statusCode !== 302) {
+ assert.fail(this.res.statusCode, 302, 'Status code is not 302', '===', assert.redirect);
+ }
+ var realPath = require('url').parse(this.res.headers.location).pathname;
+ if (realPath !== path) {
+ assert.fail(realPath, path, message || 'Wrong location', '===', assert.redirect);
+ }
+ };
+
+ assert.send = function (args, message) {
+ if (this.res.statusCode !== 200) {
+ assert.fail(this.res.statusCode, 200, 'Status code is not 200', '===', assert.status200);
+ } else if (!this.res.send.calledWithExactly(args)) {
+ assert.fail(this.res.send.args[0][0], args, message || 'send() does not called with expected args', '===', assert.send);
+ }
+ };
+
+ assert.success = function (template, message) {
+ if (this.res.statusCode !== 200) {
+ assert.fail(this.res.statusCode, 200, message || 'Status code is not 200', '===', assert.status200);
+ }
+ };
+
+ assert.flash = function (kind) {
+ if (!this.req.flash.called) {
+ assert.fail(this.req.flash.called, true, 'req.flash() does not called', '===', assert.flash);
+ } else if (!this.req.flash.calledWith(kind)) {
+ assert.fail(this.req.flash.args[0][0], kind, 'req.flash() does not called with ' + kind, '===', assert.flash);
+ }
+ };
+
+ assert.assign = function (name, value) {
+ if (!this.req.sandbox.hasOwnProperty(name)) {
+ assert.fail(name, this.req.sandbox, 'Not assigned', 'in', assert.assign);
+ } else if (typeof value !== 'undefined') {
+ if (typeof value == 'function') {
+ if (!value(this.req.sandbox[name])) {
+ assert.fail(this.req.sandbox[name], '[user check]', 'Assigned value doesn\'t matched', '[user check]', assert.assign);
+ }
+ } else if (value !== this.req.sandbox[name]) {
+ assert.fail(this.req.sandbox[name], value, 'Assigned value doesn\'t matched', '===', assert.assign);
+ }
+ }
+ };
+
+ assert.get = stubRequest('GET');
+ assert.post = stubRequest('POST');
+ assert.put = stubRequest('POST', 'PUT');
+ assert.del = stubRequest('POST', 'DELETE');
+
+ var origTest = nodeunit.types.test;
+ nodeunit.types.test = function () {
+ var test = origTest.apply(this, Array.prototype.slice.call(arguments));
+ test.wait = function (n) {
+ var test = this;
+ var origDone = test.done;
+ test.done = function () {
+ if (--n === 0) {
+ test.done = origDone;
+ test.done();
+ }
+ }.bind(this);
+ };
+
+ return test;
+ };
+
+ var cookies = {};
+ var csrfToken = '';
+
+ function stubRequest(method, _method) {
+ return function (url, callback) {
+
+ var req = new http.IncomingMessage;
+ var res = new http.ServerResponse({method: 'NOTHEAD'});
+
+ res.render = sinon.spy(res.render);
+ res.send = sinon.spy(res.send);
+ res.redirect = sinon.spy(res.redirect);
+ res.headers = {};
+ res.setHeader = res.header = function (header, value) {
+ res.headers[header.toLowerCase()] = value;
+ };
+
+ req.headers = {
+ host:'localhost',
+ cookie: cookieString(cookies)
+ };
+
+ req.flash = sinon.spy(req.flash);
+ req.connection = {};
+ req.url = url;
+ req.method = method;
+
+ if (method === 'POST') {
+ if (typeof callback === 'object') {
+ req.body = callback;
+ callback = arguments[2];
+ }
+
+ if (_method) {
+ req.body._method = _method;
+ }
+
+ req.body.authenticity_token = csrfToken;
+
+ }
+
+ res.end = function () {
+ this.req = req;
+ this.res = res;
+ if (res.headers['set-cookie']) {
+ var c = res.headers['set-cookie'].split(';').shift().split('=');
+ cookies[c[0]] = c[1];
+ }
+ csrfToken = req.csrfToken;
+ callback.call(this);
+ }.bind(this);
+
+ app.handle(req, res);
+ }
+ };
+
+ function cookieString(obj) {
+ var s = [];
+ Object.keys(obj).forEach(function (val) {
+ s.push(val + '=' + obj[val]);
+ });
+ return s.join('; ');
+ }
+
+};
+
+var group_name = false, EXT_EXP;
+function it (should, test_case) {
+ check_external_exports();
+ if (group_name) {
+ EXT_EXP[group_name][should] = test_case;
+ } else {
+ EXT_EXP[should] = test_case;
+ }
+}
+
+global.it = it;
+
+function context(name, tests) {
+ check_external_exports();
+ EXT_EXP[name] = {};
+ group_name = name;
+ tests({
+ before: function (f) {
+ it('setUp', f);
+ },
+ after: function (f) {
+ it('tearDown', f);
+ }
+ });
+ group_name = false;
+}
+
+global.context = context;
+
+exports.init = function (external_exports) {
+ EXT_EXP = external_exports;
+ if (external_exports.done) {
+ external_exports.done();
+ }
+};
+
+function check_external_exports() {
+ if (!EXT_EXP) throw new Error(
+ 'Before run this, please ensure that ' +
+ 'require("spec_helper").init(exports); called');
+}

0 comments on commit 3271287

Please sign in to comment.
Something went wrong with that request. Please try again.