- BootstrapZola2015-04-13T00:00:00+00:00https://www.fullstackstanley.com/tags/bootstrap/atom.xmlWhy you should use Bootstrap with a CSS Preprocessor2015-04-13T00:00:00+00:002015-04-13T00:00:00+00:00https://www.fullstackstanley.com/articles/why-you-should-use-bootstrap-with-a-css-preprocessor/<p>It's all too easy to import Twitter Bootstrap from <a href="http://www.bootstrapcdn.com/">BootstrapCDN</a>, overwrite the styles in your own CSS and just stick an <code>!important</code> on anything that doesn't work the first time you try to change it.</p>
<span id="continue-reading"></span>
<p>Using a preprocessor such as SASS lets you make these changes in a much easier and more organised fashion.</p>
<p>Say for instance that you wanted to change the background colour for the Bootstrap class <code>btn-primary</code>. What you would need to do is go to the <a href="http://getbootstrap.com/customize">customise</a> section of the Bootstrap documentation, scroll down to <a href="http://getbootstrap.com/customize/#buttons">buttons</a> and find the variable(s) that are used to set <code>btn-primary</code>'s styles.</p>
<p>For this example <code>@btn-primary-border</code> and <code>@btn-primary-bg</code> would be what you need to change. Since I use SASS I need to switch out the <code>@</code> for <code>$</code>. Then I put the new value above <code>@import "bootstrap";</code> in my <code>app.scss</code>.</p>
<pre data-lang="scss" style="background-color:#2b303b;color:#c0c5ce;" class="language-scss "><code class="language-scss" data-lang="scss"><span>$</span><span style="color:#bf616a;">btn-primary-bg</span><span>:</span><span style="color:#96b5b4;">#ff0000</span><span>;
</span><span>$</span><span style="color:#bf616a;">btn-primary-border</span><span>: </span><span style="color:#96b5b4;">darken</span><span>(</span><span style="color:#96b5b4;">#ff0000</span><span>, </span><span style="color:#d08770;">5</span><span>);
</span><span style="color:#b48ead;">@import </span><span>"</span><span style="color:#a3be8c;">bootstrap</span><span>";
</span></code></pre>
<p>This goes for everything else as well. The navigation bar, alerts, background colour, grid margin etc. It's also much more convenient than overriding them in a separate stylesheet. It's also faster than using the Bootstrap website's customiser because you have the option to adjust them to your preference very quickly.</p>
<p>Another major benefit is that you can extend these Bootstrap classes and make your own! Perhaps you want another button class called <code>btn-help</code> which will look slightly different to <code>btn-info</code>.</p>
<p>It's as simple as using SASS's <code>extend</code> and then overriding the properties you want to change.</p>
<pre data-lang="scss" style="background-color:#2b303b;color:#c0c5ce;" class="language-scss "><code class="language-scss" data-lang="scss"><span style="color:#8fa1b3;">.</span><span style="color:#d08770;">btn-help </span><span>{
</span><span> </span><span style="color:#b48ead;">@extend </span><span style="color:#8fa1b3;">.</span><span style="color:#d08770;">btn-help</span><span>;
</span><span> background-color: </span><span style="color:#96b5b4;">lighten</span><span>($</span><span style="color:#bf616a;">btn-info-bg</span><span>, </span><span style="color:#d08770;">5</span><span>);
</span><span>}
</span></code></pre>
<p>I could go on about the benefits of SASS and LESS. Hell, even Stylus has a <a href="https://github.com/maxmx/bootstrap-stylus">Bootstrap port</a>! There is one last thing that I'd like to mention and that's organisation.</p>
<p>I have found from own experience that sticking all of your CSS into one file is a recipe for a disaster. Yes, you could split your stylesheets into separate files and include them separately, or have a Grunt/Gulp task that minifies them but if you're going that far you may as well let a preprocessor do it for you while giving you it's other benefits.</p>
<p>If you are using one CSS file then consider this: When you first make your website you may place all of the code in neat groups that make logical sense. Then one Friday at 5 o' clock you need to fix a bug that your boss just noticed. You quickly add a fix to the bottom of your stylesheet. It's not a big deal but suddenly your header CSS is in two different places. Little things like this add up, and the more of it you have, the more difficult it becomes to reorganise.</p>
<p>Right now I'm using <a href="https://gist.github.com/bensmithett/4736571">BEMSMACSS</a> to organise my CSS. But I've also added a <code>_shame.scss</code> file which I first heard about from <a href="https://thechangelog.com/shame-css/">The Changelog Podcast</a>. </p>
<p>The idea behind a <code>shame.css</code> is to add any CSS that needs to be done in a rush, or using CSS hacks to fix something that you can't quite figure out. This isolates them and lets you or a team member come back to them later. The name <code>shame.css</code> really encourages you to fix the content. I think it's a genious idea because it's so simple yet effective.</p>
Laravel Elixir with Bootstrap SASS and Font Awesome2015-04-12T00:00:00+00:002015-04-12T00:00:00+00:00https://www.fullstackstanley.com/articles/laravel-elixir-with-bootstrap-sass-and-font-awesome/<p>This is my current Gulpfile for Laravel Elixir which is heavily influenced from <a href="https://gist.github.com/ericbarnes/c3ab73520bae8f1a83a2">this gist</a> and the comments within it.</p>
<span id="continue-reading"></span>
<p>All I've done is added Font Awesome, set it compile all scripts in <code>resources/javascripts</code> which is where I keep my own Javascript code and added asset versioning.</p>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#65737e;">// gulpfile.js
</span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">paths </span><span>= {
</span><span>'</span><span style="color:#a3be8c;">jquery</span><span>': '</span><span style="color:#a3be8c;">./vendor/bower_components/jquery/</span><span>',
</span><span>'</span><span style="color:#a3be8c;">bootstrap</span><span>': '</span><span style="color:#a3be8c;">./vendor/bower_components/bootstrap-sass-official/assets/</span><span>',
</span><span>'</span><span style="color:#a3be8c;">fontawesome</span><span>': '</span><span style="color:#a3be8c;">./vendor/bower_components/fontawesome/</span><span>'
</span><span>}
</span><span>
</span><span style="color:#8fa1b3;">elixir</span><span>(</span><span style="color:#b48ead;">function</span><span>(</span><span style="color:#bf616a;">mix</span><span>) {
</span><span> </span><span style="color:#bf616a;">mix</span><span>.</span><span style="color:#8fa1b3;">sass</span><span>('</span><span style="color:#a3be8c;">*</span><span>', '</span><span style="color:#a3be8c;">public/css/</span><span>', {includePaths: [</span><span style="color:#bf616a;">paths</span><span>.</span><span style="color:#bf616a;">bootstrap </span><span>+ '</span><span style="color:#a3be8c;">stylesheets</span><span>', </span><span style="color:#bf616a;">paths</span><span>.</span><span style="color:#bf616a;">fontawesome </span><span>+ '</span><span style="color:#a3be8c;">scss</span><span>']})
</span><span> .</span><span style="color:#8fa1b3;">copy</span><span>(</span><span style="color:#bf616a;">paths</span><span>.</span><span style="color:#bf616a;">bootstrap </span><span>+ '</span><span style="color:#a3be8c;">fonts/bootstrap/**</span><span>', '</span><span style="color:#a3be8c;">public/fonts/bootstrap</span><span>')
</span><span> .</span><span style="color:#8fa1b3;">copy</span><span>(</span><span style="color:#bf616a;">paths</span><span>.</span><span style="color:#bf616a;">fontawesome </span><span>+ '</span><span style="color:#a3be8c;">fonts/**</span><span>', '</span><span style="color:#a3be8c;">public/fonts/fontawesome</span><span>')
</span><span> .</span><span style="color:#8fa1b3;">scripts</span><span>([
</span><span> </span><span style="color:#bf616a;">paths</span><span>.</span><span style="color:#bf616a;">jquery </span><span>+ "</span><span style="color:#a3be8c;">dist/jquery.js</span><span>",
</span><span> </span><span style="color:#bf616a;">paths</span><span>.</span><span style="color:#bf616a;">bootstrap </span><span>+ "</span><span style="color:#a3be8c;">javascripts/bootstrap.js</span><span>",
</span><span> '</span><span style="color:#a3be8c;">./resources/javascripts/**/*.js</span><span>',
</span><span> ], '</span><span style="color:#a3be8c;">public/js/app.js</span><span>', '</span><span style="color:#a3be8c;">./</span><span>')
</span><span> .</span><span style="color:#8fa1b3;">version</span><span>([
</span><span> '</span><span style="color:#a3be8c;">css/app.css</span><span>',
</span><span> '</span><span style="color:#a3be8c;">js/app.js</span><span>'
</span><span> ])
</span><span>});
</span></code></pre>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#65737e;">// bower.json
</span><span>{
</span><span> "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">Laravel Application</span><span>",
</span><span> "</span><span style="color:#a3be8c;">dependencies</span><span>": {
</span><span> "</span><span style="color:#a3be8c;">bootstrap-sass-official</span><span>": "</span><span style="color:#a3be8c;">~3.3.1</span><span>",
</span><span> "</span><span style="color:#a3be8c;">fontawesome</span><span>": "</span><span style="color:#a3be8c;">~4.3.0</span><span>"
</span><span> }
</span><span>}
</span></code></pre>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#65737e;">// .bowerrc
</span><span>{
</span><span> "</span><span style="color:#a3be8c;">directory</span><span>": "</span><span style="color:#a3be8c;">vendor/bower_components</span><span>"
</span><span>}
</span></code></pre>
<p>Make sure you have Bower installed globally</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>npm install -g bower
</span></code></pre>
<p>Install the bower packages</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>bower install
</span></code></pre>
<p>After that, you can run the <code>gulp watch</code> command which will copy Glyphicons and Font Awesome into <code>public/fonts</code>. </p>
<p><code>resources/assets/sass</code> and <code>resources/javascripts</code> will be watched for changes and concatenated into <code>public/css/app.css</code> and <code>public/js/app.js</code> respectively.</p>
<p>Your <code>resources/assets/sass/app.scss</code> should include the following to look for the fonts in the correct place and import their stylesheets.</p>
<pre data-lang="scss" style="background-color:#2b303b;color:#c0c5ce;" class="language-scss "><code class="language-scss" data-lang="scss"><span>$</span><span style="color:#bf616a;">icon-font-path</span><span>: "</span><span style="color:#a3be8c;">/fonts/bootstrap/</span><span>";
</span><span>$</span><span style="color:#bf616a;">fa-font-path</span><span>: "</span><span style="color:#a3be8c;">/fonts/fontawesome</span><span>";
</span><span style="color:#b48ead;">@import </span><span>"</span><span style="color:#a3be8c;">bootstrap</span><span>";
</span><span style="color:#b48ead;">@import </span><span>"</span><span style="color:#a3be8c;">font-awesome</span><span>";
</span></code></pre>
<p>That's it! Note that I'm using Elixir's handy asset versioning, too. In your HTML layout you can use the <code>elixir</code> function.</p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#bf616a;">link </span><span style="color:#d08770;">href</span><span>="</span><span style="color:#a3be8c;">{{ elixir('css/app.css') }}</span><span>" </span><span style="color:#d08770;">rel</span><span>="</span><span style="color:#a3be8c;">stylesheet</span><span>">
</span><span> <</span><span style="color:#bf616a;">script </span><span style="color:#d08770;">src</span><span>="</span><span style="color:#a3be8c;">{{ elixir('js/app.js') }}</span><span>"></</span><span style="color:#bf616a;">script</span><span>>
</span></code></pre>
Realtime chat with Laravel, Ember JS and Pusher2015-03-29T00:00:00+00:002015-03-29T00:00:00+00:00https://www.fullstackstanley.com/articles/realtime-chat-with-laravel-ember-js-and-pusher/<p>I've been hearing a lot of noise about Firebase recently. Lots of good noise. When I first started making this article I wanted to make use of Firehose which is an open source alternative to Firebase. </p>
<span id="continue-reading"></span>
<p>Setting up the API with Laravel was a breeze. The only stumbling block was with my Ubuntu Vagrant box which installed a version of Redis which was too old (Firehose requries 2.6+ where as Ubuntu's package manager only has 2.2). This was a pretty simple to fix and if you <em>are</em> interested in Firehose then you can find instructions for getting the latest Redis <a href="http://codecuriosity.com/blog/2013/10/29/install-redis-on-ubuntu/">here</a>.</p>
<p>Anyway I started building my Ember application and I hit a brick wall. Firehose touts Ember support out of the box but I can see literally no documentation on how to get started with it.</p>
<p>I decided to switch to Pusher which I'm already familiar with. Unfortunately Pusher isn't open source but it does have a reasonable free package. This allowed me to continue the use of my Laravel application where as switching to Firebase would not. Also, there is already a pretty amazing Firebase Ember tutorial <a href="https://www.firebase.com/blog/2015-03-13-ember-cli-in-9-minutes.html">here</a> so it seems pointless to do the same thing.</p>
<p>This article will show you a very bare bones chat system with Laravel 5, Ember JS 1.10 and Pusher.</p>
<span id="continue-reading"></span><h2 id="laravel">Laravel</h2>
<p>Start off by making a new Laravel application</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">laravel</span><span> new realtimechat
</span></code></pre>
<p>For this application you'll use 2 packages: <a href="https://github.com/laracasts/Laravel-5-Generators-Extended">laracasts/Laravel-5-Generators-Extended</a> and <a href="https://github.com/vinkla/pusher">vinkla/pusher</a>.</p>
<p>Install the two packages</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">composer</span><span> require laracasts/generators</span><span style="color:#bf616a;"> --dev
</span><span style="color:#bf616a;">composer</span><span> require vinkla/pusher:</span><span style="color:#bf616a;">~</span><span>1.0
</span></code></pre>
<p>In <code>app/Providers/AppServiceProvider.php</code> add the generator service provider as suggested in the documentation.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span>if ($this->app->environment() == 'local') {
</span><span> $this->app->register('Laracasts\Generators\GeneratorsServiceProvider');
</span><span>}
</span></code></pre>
<p>In <code>config/app.php</code> Add the Pusher service provider. Do not add the facade as at the time of writing there is an issue with it.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span>'Vinkla\Pusher\PusherServiceProvider'
</span></code></pre>
<p>Create a new migration for a table called messages</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>php artisan make:migration:schema create_messages_table --schema="name:string, body:string"
</span></code></pre>
<p>The first field, <code>name</code>, will be the user's name. The second field, <code>body</code>, will be the content of the message. You might be tempted to rename <code>body</code> to <code>content</code> (as I was). I recommend that you don't because Ember's controllers and templates set <code>content</code> to the current model which makes things unnecessaryly confusing.</p>
<p>If you haven't configured your database settings then now is the time. I'm using Sqlite for this application which works perfectly well. Run the migration afterwards.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">php</span><span> artisan migrate
</span></code></pre>
<p>You will need to remove the global CSRF token protection provided by Laravel. If your app has other non-API routes then I recommend wrapping them in <code>Route::group</code> with the CSRF middleware. You can remove the global middleware in <code>app/Http/Kernal.php</code> by removing the <code>App\Http\Middleware\VerifyCSRFToken</code> line.</p>
<p>At this point make sure you have signed up at <a href="http://pusher.com">Pusher</a> and create your first application. </p>
<p>In your terminal publish the Pusher configuration file with this command</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">php</span><span> artisan vendor:publish
</span></code></pre>
<p>Open up <code>app/config/pusher.php</code> and add your <code>auth_key</code>, <code>secret</code> and <code>app_id</code> to the <code>main</code> array. These can be found on your Pusher application's dashboard.</p>
<p>In <code>app/Http/routes.php</code> add a new resource route.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span style="color:#ab7967;"><?php
</span><span style="color:#ebcb8b;">Route</span><span>::</span><span style="color:#bf616a;">resource</span><span>('</span><span style="color:#a3be8c;">messages</span><span>', '</span><span style="color:#a3be8c;">MessagesController</span><span>', ['</span><span style="color:#a3be8c;">only</span><span>' => ['</span><span style="color:#a3be8c;">index</span><span>', '</span><span style="color:#a3be8c;">store</span><span>', '</span><span style="color:#a3be8c;">show</span><span>']]);
</span></code></pre>
<p>You'll only be using <code>index</code> and <code>store</code> but it's worth defining <code>show</code> incase Ember tries to fetch a single row.</p>
<p>Now create the controller</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">php</span><span> artisan make:controller MessagesController
</span></code></pre>
<p>Open up <code>app/Http/Controllers/MessagesController.php</code> and update the code as follows:</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span style="color:#ab7967;"><?php </span><span style="color:#d08770;">namespace </span><span>App\Http\</span><span style="color:#d08770;">Controllers</span><span>;
</span><span>
</span><span style="color:#b48ead;">use </span><span>App\Http\</span><span style="color:#ebcb8b;">Requests</span><span>;
</span><span style="color:#b48ead;">use </span><span>App\Http\Controllers\</span><span style="color:#ebcb8b;">Controller</span><span>;
</span><span style="color:#b48ead;">use </span><span>App\</span><span style="color:#ebcb8b;">Message</span><span>;
</span><span>
</span><span style="color:#b48ead;">use </span><span>Illuminate\Http\</span><span style="color:#ebcb8b;">Request</span><span>;
</span><span style="color:#b48ead;">use </span><span style="color:#ebcb8b;">Input</span><span>;
</span><span style="color:#b48ead;">use </span><span style="color:#ebcb8b;">Response</span><span>;
</span><span style="color:#b48ead;">use </span><span>GuzzleHttp\</span><span style="color:#ebcb8b;">Client</span><span>;
</span><span style="color:#b48ead;">use </span><span>Vinkla\Pusher\</span><span style="color:#ebcb8b;">PusherManager</span><span>;
</span><span>
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">MessagesController </span><span style="color:#b48ead;">extends </span><span style="color:#a3be8c;">Controller </span><span style="color:#eff1f5;">{
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">protected </span><span>$</span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">protected </span><span>$</span><span style="color:#bf616a;">pusher</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">public function </span><span style="color:#96b5b4;">__construct</span><span style="color:#eff1f5;">(</span><span style="color:#ebcb8b;">Message </span><span>$</span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">, </span><span style="color:#ebcb8b;">PusherManager </span><span>$</span><span style="color:#bf616a;">pusher</span><span style="color:#eff1f5;">)
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">message </span><span>= $</span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">pusher </span><span>= $</span><span style="color:#bf616a;">pusher</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#65737e;">/**
</span><span style="color:#65737e;"> * Display a listing of the resource.
</span><span style="color:#65737e;"> *
</span><span style="color:#65737e;"> * </span><span style="color:#b48ead;">@return</span><span style="color:#65737e;"> Response
</span><span style="color:#65737e;"> */
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">public function </span><span style="color:#8fa1b3;">index</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">messages </span><span>= $</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">orderBy</span><span style="color:#eff1f5;">(</span><span>'</span><span style="color:#a3be8c;">id</span><span>'</span><span style="color:#eff1f5;">, </span><span>'</span><span style="color:#a3be8c;">desc</span><span>'</span><span style="color:#eff1f5;">)-></span><span style="color:#bf616a;">take</span><span style="color:#eff1f5;">(</span><span style="color:#d08770;">5</span><span style="color:#eff1f5;">)-></span><span style="color:#bf616a;">get</span><span style="color:#eff1f5;">();
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span style="color:#ebcb8b;">Response</span><span style="color:#eff1f5;">::</span><span style="color:#bf616a;">json</span><span style="color:#eff1f5;">([</span><span>'</span><span style="color:#a3be8c;">messages</span><span>' => $</span><span style="color:#bf616a;">messages</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">toArray</span><span style="color:#eff1f5;">()]);
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#65737e;">/**
</span><span style="color:#65737e;"> * Store a newly created resource in storage.
</span><span style="color:#65737e;"> *
</span><span style="color:#65737e;"> * </span><span style="color:#b48ead;">@return</span><span style="color:#65737e;"> Response
</span><span style="color:#65737e;"> */
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">public function </span><span style="color:#8fa1b3;">store</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">message </span><span>= $</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">create</span><span style="color:#eff1f5;">(</span><span style="color:#ebcb8b;">Input</span><span style="color:#eff1f5;">::</span><span style="color:#bf616a;">get</span><span style="color:#eff1f5;">(</span><span>'</span><span style="color:#a3be8c;">message</span><span>'</span><span style="color:#eff1f5;">));
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">pusher</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">trigger</span><span style="color:#eff1f5;">(</span><span>'</span><span style="color:#a3be8c;">messages</span><span>'</span><span style="color:#eff1f5;">, </span><span>'</span><span style="color:#a3be8c;">new-message</span><span>'</span><span style="color:#eff1f5;">, [</span><span>'</span><span style="color:#a3be8c;">message</span><span>' => $</span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">toArray</span><span style="color:#eff1f5;">()]);
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span style="color:#ebcb8b;">Response</span><span style="color:#eff1f5;">::</span><span style="color:#bf616a;">json</span><span style="color:#eff1f5;">([</span><span>'</span><span style="color:#a3be8c;">message</span><span>' => $</span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">toArray</span><span style="color:#eff1f5;">()]);
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#65737e;">/**
</span><span style="color:#65737e;"> * Display the specified resource.
</span><span style="color:#65737e;"> *
</span><span style="color:#65737e;"> * </span><span style="color:#b48ead;">@param</span><span style="color:#65737e;"> int $id
</span><span style="color:#65737e;"> * </span><span style="color:#b48ead;">@return</span><span style="color:#65737e;"> Response
</span><span style="color:#65737e;"> */
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">public function </span><span style="color:#8fa1b3;">show</span><span style="color:#eff1f5;">(</span><span>$</span><span style="color:#bf616a;">id</span><span style="color:#eff1f5;">)
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">message </span><span>= $</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">findOrFail</span><span style="color:#eff1f5;">(</span><span>$</span><span style="color:#bf616a;">id</span><span style="color:#eff1f5;">);
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span style="color:#ebcb8b;">Response</span><span style="color:#eff1f5;">::</span><span style="color:#bf616a;">json</span><span style="color:#eff1f5;">([</span><span>'</span><span style="color:#a3be8c;">message</span><span>' => $</span><span style="color:#bf616a;">message</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">toArray</span><span style="color:#eff1f5;">()]);
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">}
</span></code></pre>
<p>I have used dependancy injection for the <code>Message</code> model and for <code>PusherManager</code> which are set in the constructor.</p>
<p>You may also notice that the JSON responses wrap <code>message</code> for single objects and <code>messages</code> for collections. This is how Ember will expect its data.</p>
<p>If you're familiar with Ember then you might be already be considering converting the keys to camel case (created_at to createdAt etc). Don't worry about this for now.</p>
<p>You can also see this line of code</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>$this->pusher->trigger('messages', 'new-message', ['message' => $message->toArray()]);
</span></code></pre>
<p>When you create a new row in the database you want to tell Pusher so that each client can be notified.</p>
<p>The <code>index</code> method on line 30 takes the latest 5 messages. This as a nice way to introduce newly connected users to the chat without bombarding them with thousands of messages. Feel free to adjust this to your preference.</p>
<p>At this point it's a good idea to test that the API for creating messages works because it's the trickiest to debug.</p>
<p>There are a few ways that you can do this. I've been using <a href="https://luckymarmot.com/paw">Paw</a> which is a really sweet REST client. <a href="https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en">Postman - REST client</a> is an incredible free alternative. </p>
<p>If you're thinking, "stop throwing all of these stupid apps in my face. Give me the Curl command!" then here you go.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">curl -X</span><span> POST</span><span style="color:#bf616a;"> -d </span><span>"</span><span style="color:#a3be8c;">message[name]=Mitch</span><span>"</span><span style="color:#bf616a;"> -d </span><span>"</span><span style="color:#a3be8c;">message[body]=this is a message</span><span>" '</span><span style="color:#a3be8c;">http://realtime.dev/messages</span><span>'
</span></code></pre>
<h2 id="ember">Ember</h2>
<p>Here's a preview of the final application:</p>
<p><img src="https://i.imgur.com/03wDiJq.png" alt="Realtime Chat" /></p>
<p>Once the messages reach the input fields a scrollbar will appear. The scrollbar will automatically scroll to the bottom when a new message is received.</p>
<p>Go ahead and install Ember CLI if you haven't already</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">npm</span><span> install</span><span style="color:#bf616a;"> -g</span><span> ember-cli phantomjs
</span></code></pre>
<p>For reference I'm using the following package versions with <a href="https://iojs.org/en/index.html">IO.js v1.2.0</a></p>
<ul>
<li>Ember-CLI 0.2.1</li>
<li>Ember 1.10</li>
<li>Ember-CLI-HTMLBars 0.7.4</li>
<li>Ember Data 1.0.0-beta.16</li>
<li>jQuery 1.11.2</li>
</ul>
<p>Make a new Ember application. I recommend doing so outside of your Laravel directory.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">ember</span><span> new realtime
</span></code></pre>
<p>After it's set up install the following add ons</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">ember</span><span> install:addon ember-cli-pusher
</span><span style="color:#bf616a;">npm</span><span> install</span><span style="color:#bf616a;"> --save-dev</span><span> ember-cli-content-security-policy
</span></code></pre>
<p>In your configuration file located at <code>config/environment.js</code> add your pusher key to the <code>APP</code> property.</p>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span>PUSHER_OPTS: {
</span><span> key: '</span><span style="color:#a3be8c;"><KEYHERE></span><span>',
</span><span> connection: {},
</span><span> logAllEvents: </span><span style="color:#d08770;">false
</span><span>}
</span></code></pre>
<p>Then above the <code>return ENV;</code> add these Content Security Policy settings - this is necessary for Pusher's data to be retrieved. You can remove the bootstrap stylesheet in <code>style-src</code> if you wish to include it locally or not at all.</p>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#bf616a;">ENV</span><span>['</span><span style="color:#a3be8c;">contentSecurityPolicy</span><span>'] = {
</span><span> '</span><span style="color:#a3be8c;">default-src</span><span>': "</span><span style="color:#a3be8c;">'none'</span><span>",
</span><span> '</span><span style="color:#a3be8c;">script-src</span><span>': "</span><span style="color:#a3be8c;">'self' http://stats.pusher.com/</span><span>",
</span><span> '</span><span style="color:#a3be8c;">connect-src</span><span>': "</span><span style="color:#a3be8c;">'self' ws://ws.pusherapp.com/</span><span>",
</span><span> '</span><span style="color:#a3be8c;">img-src</span><span>': "</span><span style="color:#a3be8c;">'self'</span><span>",
</span><span> '</span><span style="color:#a3be8c;">style-src</span><span>': "</span><span style="color:#a3be8c;">'self' 'unsafe-inline' http://maxcdn.bootstrapcdn.com/</span><span>",
</span><span> '</span><span style="color:#a3be8c;">media-src</span><span>': "</span><span style="color:#a3be8c;">'self'</span><span>",
</span><span> };
</span></code></pre>
<p>Make <code>messages</code> the root route in <code>app/router.js</code></p>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#b48ead;">import </span><span style="color:#bf616a;">Ember </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember</span><span>';
</span><span style="color:#b48ead;">import </span><span style="color:#bf616a;">config </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">./config/environment</span><span>';
</span><span>
</span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">Router </span><span>= </span><span style="color:#bf616a;">Ember</span><span>.</span><span style="color:#bf616a;">Router</span><span>.</span><span style="color:#8fa1b3;">extend</span><span>({
</span><span> location: </span><span style="color:#bf616a;">config</span><span>.</span><span style="color:#bf616a;">locationType
</span><span>});
</span><span>
</span><span style="color:#bf616a;">Router</span><span>.</span><span style="color:#8fa1b3;">map</span><span>(</span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#bf616a;">this</span><span>.</span><span style="color:#8fa1b3;">resource</span><span>('</span><span style="color:#a3be8c;">messages</span><span>', {path: '</span><span style="color:#a3be8c;">/</span><span>'}, </span><span style="color:#b48ead;">function</span><span>() {});
</span><span>});
</span><span>
</span><span style="color:#b48ead;">export default </span><span style="color:#bf616a;">Router</span><span>;
</span></code></pre>
<p>Run the following command to change the <code>RestAdapter</code> to one that will work with our API.</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>ember g adapter application
</span></code></pre>
<p>In <code>app/adapters/application.js</code> update the adapter name like so:</p>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#b48ead;">import </span><span style="color:#bf616a;">DS </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember-data</span><span>';
</span><span>
</span><span style="color:#b48ead;">export default </span><span style="color:#bf616a;">DS</span><span>.</span><span style="color:#bf616a;">ActiveModelAdapter</span><span>.</span><span style="color:#8fa1b3;">extend</span><span>({
</span><span>});
</span></code></pre>
<p><code>ActiveModel</code> is a thin wrapper around the Ruby on Rails' ORM <code>ActiveRecord</code>. I'm using this adapter because the API expects data in the same format. This is why you don't need to worry about updating camel case properties to snake case: <code>ActiveModelAdapter</code> handles it all for you.</p>
<p>Create a <code>message</code> model which defines the message properties.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">ember</span><span> g model message
</span></code></pre>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#65737e;">// app/models/message.js
</span><span style="color:#b48ead;">import </span><span style="color:#bf616a;">DS </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember-data</span><span>';
</span><span>
</span><span style="color:#b48ead;">export default </span><span style="color:#bf616a;">DS</span><span>.</span><span style="color:#bf616a;">Model</span><span>.</span><span style="color:#8fa1b3;">extend</span><span>({
</span><span> name: </span><span style="color:#bf616a;">DS</span><span>.</span><span style="color:#8fa1b3;">attr</span><span>('</span><span style="color:#a3be8c;">string</span><span>'),
</span><span> body: </span><span style="color:#bf616a;">DS</span><span>.</span><span style="color:#8fa1b3;">attr</span><span>('</span><span style="color:#a3be8c;">string</span><span>'),
</span><span> createdAt: </span><span style="color:#bf616a;">DS</span><span>.</span><span style="color:#8fa1b3;">attr</span><span>('</span><span style="color:#a3be8c;">string</span><span>'),
</span><span> updatedAt: </span><span style="color:#bf616a;">DS</span><span>.</span><span style="color:#8fa1b3;">attr</span><span>('</span><span style="color:#a3be8c;">string</span><span>')
</span><span>});
</span></code></pre>
<p>Now create the messages route which will use the message model</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">ember</span><span> g route messages
</span></code></pre>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#65737e;">// app/routes/messages.js
</span><span style="color:#b48ead;">import </span><span style="color:#bf616a;">Ember </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember</span><span>';
</span><span>
</span><span style="color:#b48ead;">export default </span><span style="color:#bf616a;">Ember</span><span>.</span><span style="color:#bf616a;">Route</span><span>.</span><span style="color:#8fa1b3;">extend</span><span>({
</span><span> </span><span style="color:#8fa1b3;">model</span><span>: </span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">this</span><span>.</span><span style="color:#bf616a;">store</span><span>.</span><span style="color:#96b5b4;">find</span><span>('</span><span style="color:#a3be8c;">message</span><span>');
</span><span> }
</span><span>});
</span></code></pre>
<p>The messages controller is the most complex part of the application. Create it with the following command.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">ember</span><span> g controller messages
</span></code></pre>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#65737e;">// app/controllers/messages.js
</span><span style="color:#b48ead;">import </span><span style="color:#bf616a;">Ember </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember</span><span>';
</span><span style="color:#b48ead;">import </span><span>{ </span><span style="color:#bf616a;">Bindings </span><span>} </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember-pusher/bindings</span><span>';
</span><span>
</span><span style="color:#b48ead;">export default </span><span style="color:#bf616a;">Ember</span><span>.</span><span style="color:#bf616a;">ArrayController</span><span>.</span><span style="color:#8fa1b3;">extend</span><span>(</span><span style="color:#bf616a;">Bindings</span><span>, {
</span><span> sortProperties: ['</span><span style="color:#a3be8c;">createdAt</span><span>'],
</span><span> sortAscending: </span><span style="color:#d08770;">true</span><span>,
</span><span> logPusherEvents: </span><span style="color:#d08770;">true</span><span>,
</span><span> PUSHER_SUBSCRIPTIONS: {
</span><span> messages: ['</span><span style="color:#a3be8c;">new-message</span><span>']
</span><span> },
</span><span> </span><span style="color:#8fa1b3;">isValid</span><span>: </span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#b48ead;">return </span><span>(</span><span style="color:#bf616a;">this</span><span>.</span><span style="color:#96b5b4;">get</span><span>('</span><span style="color:#a3be8c;">name</span><span>') && </span><span style="color:#bf616a;">this</span><span>.</span><span style="color:#96b5b4;">get</span><span>('</span><span style="color:#a3be8c;">body</span><span>'));
</span><span> }.</span><span style="color:#8fa1b3;">property</span><span>('</span><span style="color:#a3be8c;">name</span><span>', '</span><span style="color:#a3be8c;">body</span><span>'),
</span><span> actions: {
</span><span> </span><span style="color:#8fa1b3;">newMessage</span><span>: </span><span style="color:#b48ead;">function</span><span>(</span><span style="color:#bf616a;">data</span><span>) {
</span><span> </span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">_this </span><span>= </span><span style="color:#bf616a;">this</span><span>,
</span><span> </span><span style="color:#bf616a;">chat </span><span>= </span><span style="color:#8fa1b3;">jQuery</span><span>('</span><span style="color:#a3be8c;">#chat</span><span>');
</span><span>
</span><span> </span><span style="color:#bf616a;">Ember</span><span>.</span><span style="color:#bf616a;">run</span><span>.</span><span style="color:#8fa1b3;">later</span><span>((</span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#bf616a;">_this</span><span>.</span><span style="color:#bf616a;">store</span><span>.</span><span style="color:#96b5b4;">push</span><span>('</span><span style="color:#a3be8c;">message</span><span>', </span><span style="color:#bf616a;">_this</span><span>.</span><span style="color:#bf616a;">store</span><span>.</span><span style="color:#96b5b4;">normalize</span><span>('</span><span style="color:#a3be8c;">message</span><span>', </span><span style="color:#bf616a;">data</span><span>.</span><span style="color:#bf616a;">message</span><span>));
</span><span> </span><span style="color:#bf616a;">Ember</span><span>.</span><span style="color:#bf616a;">run</span><span>.</span><span style="color:#8fa1b3;">schedule</span><span>( '</span><span style="color:#a3be8c;">afterRender</span><span>', </span><span style="color:#b48ead;">function </span><span>() {
</span><span> </span><span style="color:#bf616a;">chat</span><span>.</span><span style="color:#96b5b4;">animate</span><span>({scrollTop: </span><span style="color:#bf616a;">chat</span><span>[</span><span style="color:#d08770;">0</span><span>].</span><span style="color:#bf616a;">scrollHeight </span><span>});
</span><span> });
</span><span> }), </span><span style="color:#d08770;">200</span><span>);
</span><span> },
</span><span> </span><span style="color:#8fa1b3;">send</span><span>: </span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">_this </span><span>= </span><span style="color:#bf616a;">this</span><span>;
</span><span> </span><span style="color:#b48ead;">if</span><span>(</span><span style="color:#bf616a;">this</span><span>.</span><span style="color:#96b5b4;">get</span><span>('</span><span style="color:#a3be8c;">isValid</span><span>')) {
</span><span> </span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">message </span><span>= </span><span style="color:#bf616a;">this</span><span>.</span><span style="color:#bf616a;">store</span><span>.</span><span style="color:#8fa1b3;">createRecord</span><span>('</span><span style="color:#a3be8c;">message</span><span>', {
</span><span> name: </span><span style="color:#bf616a;">this</span><span>.name,
</span><span> body: </span><span style="color:#bf616a;">this</span><span>.body
</span><span> });
</span><span> </span><span style="color:#bf616a;">message</span><span>.</span><span style="color:#8fa1b3;">save</span><span>().</span><span style="color:#96b5b4;">then</span><span>(</span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#bf616a;">_this</span><span>.</span><span style="color:#96b5b4;">set</span><span>('</span><span style="color:#a3be8c;">body</span><span>', '');
</span><span> });
</span><span> } </span><span style="color:#b48ead;">else </span><span>{
</span><span> </span><span style="color:#8fa1b3;">alert</span><span>('</span><span style="color:#a3be8c;">Please enter a name and a message.</span><span>');
</span><span> }
</span><span> }
</span><span> }
</span><span>});
</span></code></pre>
<p>There's a lot of interesting stuff going on here.</p>
<p>You're importing Ember-pusher on line 2 and on lines 8-10 we subscribe to the 'new-message' event from Pusher. When you receive this event Ember will automatically call the action of the same name (but camel cased).</p>
<p>On lines 6 and 7 you're setting how the data will be sorted. Chat systems generally show the latest messages at the bottom so that's why <code>createdAt</code> is sorted ascending. Do not sort by id because <code>sortProperties</code> only supports strings and therefore '10' comes before '2'. This will give the appearance of a completely random order.</p>
<p>This <code>newMessage</code> action pushes the new message onto the model. It waits a short moment to prevent duplicate entries on the client of the original message with <code>Ember.run.later</code>.</p>
<p>The scrollbar for the chat system needs to automatically scroll to the bottom so that new messages can be seen. To do this <code>Ember.run.schedule</code> is run with <code>afterRender</code> (after the new message has been added to the DOM) and then jQuery is used to animate the chat to the bottom of the screen.</p>
<p>The last action, <code>send</code>, is called when the form in the template is submitted. The <code>isValid</code> property checks that the <code>name</code> and <code>body</code> has been filled in before sending to the API. Then after the message is saved the <code>body</code> value is cleared so the user can start writing new messages in the input field.</p>
<p>For the user interface I've chosen to use Twitter Bootstrap 3.2.</p>
<p>Add the bootstrap stylesheet it into <code>app/index.html</code></p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#bf616a;">link </span><span style="color:#d08770;">rel</span><span>="</span><span style="color:#a3be8c;">stylesheet</span><span>" </span><span style="color:#d08770;">href</span><span>="</span><span style="color:#a3be8c;">//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css</span><span>">
</span></code></pre>
<p>and add the following styles into <code>app/styles/app.css</code></p>
<pre data-lang="css" style="background-color:#2b303b;color:#c0c5ce;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#8fa1b3;">.</span><span style="color:#d08770;">message </span><span>{
</span><span> background-color: </span><span style="color:#96b5b4;">#f3f3f4</span><span>;
</span><span> color: </span><span style="color:#96b5b4;">rgba</span><span>(</span><span style="color:#d08770;">0</span><span>, </span><span style="color:#d08770;">0</span><span>, </span><span style="color:#d08770;">0</span><span>, </span><span style="color:#d08770;">0.5</span><span>);
</span><span> border-color: </span><span style="color:#96b5b4;">rgba</span><span>(</span><span style="color:#d08770;">0</span><span>, </span><span style="color:#d08770;">0</span><span>, </span><span style="color:#d08770;">0</span><span>, </span><span style="color:#d08770;">0.1</span><span>);
</span><span> margin-top: </span><span style="color:#d08770;">20px</span><span>;
</span><span> margin-bottom: </span><span style="color:#d08770;">0px</span><span>;
</span><span> padding: </span><span style="color:#d08770;">15px</span><span>;
</span><span> border: </span><span style="color:#d08770;">1px </span><span>solid;
</span><span> border-radius: </span><span style="color:#d08770;">4px</span><span>;
</span><span>}
</span><span style="color:#8fa1b3;">.</span><span style="color:#d08770;">message</span><span style="color:#8fa1b3;">:</span><span style="color:#b48ead;">first-child </span><span>{
</span><span> margin-top: </span><span style="color:#d08770;">0px</span><span>;
</span><span>}
</span><span>
</span><span style="color:#8fa1b3;">#chat </span><span>{
</span><span> overflow: auto;
</span><span> height: </span><span style="color:#d08770;">340px</span><span>;
</span><span>}
</span><span>
</span><span style="color:#8fa1b3;">.</span><span style="color:#d08770;">form-chat </span><span>{
</span><span> margin-top: </span><span style="color:#d08770;">20px</span><span>;
</span><span>}
</span></code></pre>
<p>Update <code>app/templates/application.hbs</code> like so</p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">container</span><span>">
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">row</span><span>">
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">col-xs-12</span><span>">
</span><span> <</span><span style="color:#bf616a;">h2 </span><span style="color:#8fa1b3;">id</span><span>="</span><span style="color:#a3be8c;">title</span><span>">Ember Chat</</span><span style="color:#bf616a;">h2</span><span>>
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> {{outlet}}
</span><span></</span><span style="color:#bf616a;">div</span><span>>
</span></code></pre>
<p>Then in <code>app/templates/messages.hbs</code></p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">row</span><span>">
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">col-xs-12</span><span>">
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#8fa1b3;">id</span><span>="</span><span style="color:#a3be8c;">chat</span><span>">
</span><span> {{#each message in arrangedContent}}
</span><span> {{message-row message=message}}
</span><span> {{/each}}
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> <</span><span style="color:#bf616a;">form </span><span style="color:#d08770;">{{action </span><span style="background-color:#bf616a;color:#2b303b;">"</span><span style="color:#d08770;">send</span><span style="background-color:#bf616a;color:#2b303b;">"</span><span> </span><span style="color:#d08770;">on</span><span>="</span><span style="color:#a3be8c;">submit</span><span>"</span><span style="color:#d08770;">}} class</span><span>="</span><span style="color:#a3be8c;">form-chat</span><span>">
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">row</span><span>">
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">col-xs-2</span><span>">
</span><span> {{input placeholder="Name" classNames="form-control" value=name}}
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">col-xs-9</span><span>">
</span><span> {{input placeholder="Message" classNames="form-control" value=body}}
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> <</span><span style="color:#bf616a;">div </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">col-xs-1 text-right</span><span>">
</span><span> <</span><span style="color:#bf616a;">button </span><span style="color:#d08770;">{{bind-attr class</span><span>="</span><span style="color:#a3be8c;">:btn :btn-primary isValid::disabled</span><span>"</span><span style="color:#d08770;">}}</span><span>>Send</</span><span style="color:#bf616a;">button</span><span>>
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> </</span><span style="color:#bf616a;">div</span><span>>
</span><span> </</span><span style="color:#bf616a;">form</span><span>>
</span></code></pre>
<p>Here there is a form with an action <code>send</code> which is sent to the messages controller. The send button has 2 static classes and 1 dynamic one. When the controller's <code>isValid</code> property is false then the <code>disabled</code> class will be added to the button - giving it the appearance of being unusable.</p>
<p>On lines 4-6 the messages are looped through and sent to a <code>message-row</code> component which we'll create next.</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>ember g component message-row
</span></code></pre>
<p>in <code>app/components/message-row.js</code></p>
<pre data-lang="js" style="background-color:#2b303b;color:#c0c5ce;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#b48ead;">import </span><span style="color:#bf616a;">Ember </span><span style="color:#b48ead;">from </span><span>'</span><span style="color:#a3be8c;">ember</span><span>';
</span><span>
</span><span style="color:#b48ead;">export default </span><span style="color:#bf616a;">Ember</span><span>.</span><span style="color:#bf616a;">Component</span><span>.</span><span style="color:#8fa1b3;">extend</span><span>({
</span><span> tagName: '</span><span style="color:#a3be8c;">div</span><span>',
</span><span> classNames: ['</span><span style="color:#a3be8c;">message</span><span>'],
</span><span> message: </span><span style="color:#d08770;">null
</span><span>});
</span></code></pre>
<p>And for the template in <code>app/templates/components/message-row.hbs</code></p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span>[{{message.createdAt}}] {{message.name}}: {{message.body}}
</span></code></pre>
<p>Components are partials with no context. You can adjust their settings in <code>app/components/*.js</code> and adjust the templates in <code>app/templates/components/*.hbs</code>.</p>
<p>If you haven't already then fire up Ember! Note the proxy argument which allows you to use Ember with your Laravel API.</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>ember server --proxy http://realtime.dev
</span></code></pre>
<h2 id="preview">Preview</h2>
<p>Here's a short video of the system in action. There are two browser windows are used to show the new messages being loaded in realtime.</p>
<div style='position:relative; padding-bottom:56.25%'>
<iframe src="http://gfycat.com/ifr/RichTinyDegus" frameborder="0" scrolling="no" width="100%" height="100%" style='position:absolute;top:0;left:0;' ></iframe>
</div>
<h2 id="conclusion">Conclusion</h2>
<p>In this article I have shown you how to set up a simple Laravel 5 API that's compatible with Ember JS. I used Pusher to send realtime notifications to clients and discussed some of the alternatives briefly. I then set up the chat system in Ember which sends and receives messages in realtime.</p>
<p>In some ways I've found this project easy but in others I feel I have failed. I'm quite disapointed that I couldn't get Firehose to work with Ember and if I had more time I would have liked to have pursued it further.</p>
<p>This application was done in one weekend and in my opinion it is far from finished. It could definitely do with authentication and there are some kinks that need to be ironed out.</p>
<p>One kink in particular is when a client sends a message it's pushed to the top of the chat because the <code>createdAt</code> timestamp is not set. This fixes itself when the Pusher event updates it but it's not ideal.</p>
<p>I believe this could easily be fixed by adding <code>moment.js</code> and inserting the current time when creating a new record. If you've created the application yourself then I definitely recommend doing this as the next step.</p>
Bootstrap 2 pagination in Laravel 52015-03-21T00:00:00+00:002015-03-21T00:00:00+00:00https://www.fullstackstanley.com/articles/bootstrap-2-pagination-in-laravel-5/<p>I recently had to help port a website that used Twitter Bootstrap 2 to Laravel 5 and discovered that changing the pagination template is completely different in Laravel 5.</p>
<span id="continue-reading"></span>
<p>Thanks to <a href="http://stackoverflow.com/questions/28240777/custom-pagination-view-in-laravel-5">this StackOverflow thread</a> I came up with this solution.</p>
<p>In short: Laravel 5 makes use of presenter classes to style pagination.</p>
<p>You can put this class wherever you like. It's down to how you structure your project.</p>
<p>In this example I put the class in a file named <code>BootstrapTwoPresenter.php</code> which lives inside of a newly created <code>app/Presenters</code> directory.</p>
<p>The class inherits from Laravel 5's <code>BootstrapThreePresenter</code> because Bootstrap 2 and Bootstrap 3 pagination are very similar.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span style="color:#ab7967;"><?php </span><span style="color:#d08770;">namespace </span><span>App\</span><span style="color:#d08770;">Presenters</span><span>;
</span><span>
</span><span style="color:#b48ead;">use </span><span>Illuminate\Pagination\</span><span style="color:#ebcb8b;">BootstrapThreePresenter</span><span>;
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">BootstrapTwoPresenter </span><span style="color:#b48ead;">extends </span><span style="color:#a3be8c;">BootstrapThreePresenter
</span><span style="color:#eff1f5;">{
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">public function </span><span style="color:#8fa1b3;">render</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">if</span><span style="color:#eff1f5;">( </span><span>! $</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">hasPages</span><span style="color:#eff1f5;">())
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span>''</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span style="color:#96b5b4;">sprintf</span><span style="color:#eff1f5;">(
</span><span style="color:#eff1f5;"> </span><span>'</span><span style="color:#a3be8c;"><div class="pagination"><ul>%s %s %s</ul></div></span><span>'</span><span style="color:#eff1f5;">,
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getPreviousButton</span><span style="color:#eff1f5;">(),
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getLinks</span><span style="color:#eff1f5;">(),
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getNextButton</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> );
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">}
</span></code></pre>
<p>In your views you can insert the new class into the <code>render</code> method for the desired results.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span>{!! $users->render(new App\Presenters\BootstrapTwoPresenter($users)) !!}
</span></code></pre>
<p>If you wish to customise the pagination further then the following methods are available to override.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span style="color:#ab7967;"><?php </span><span style="color:#d08770;">namespace </span><span>App\</span><span style="color:#d08770;">Presenters</span><span>;
</span><span>
</span><span style="color:#b48ead;">use </span><span>Illuminate\Pagination\</span><span style="color:#ebcb8b;">BootstrapThreePresenter</span><span>;
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">BootstrapTwoPresenter </span><span style="color:#b48ead;">extends </span><span style="color:#a3be8c;">BootstrapThreePresenter
</span><span style="color:#eff1f5;">{
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">public function </span><span style="color:#8fa1b3;">render</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">if</span><span style="color:#eff1f5;">( </span><span>! $</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">hasPages</span><span style="color:#eff1f5;">())
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span>''</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span style="color:#96b5b4;">sprintf</span><span style="color:#eff1f5;">(
</span><span style="color:#eff1f5;"> </span><span>'</span><span style="color:#a3be8c;"><div class="pagination"><ul>%s %s %s</ul></div></span><span>'</span><span style="color:#eff1f5;">,
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getPreviousButton</span><span style="color:#eff1f5;">(),
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getLinks</span><span style="color:#eff1f5;">(),
</span><span style="color:#eff1f5;"> </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getNextButton</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> );
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">protected function </span><span style="color:#8fa1b3;">getDisabledTextWrapper</span><span style="color:#eff1f5;">(</span><span>$</span><span style="color:#bf616a;">text</span><span style="color:#eff1f5;">)
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span>'</span><span style="color:#a3be8c;"><li class="disabled"><a href="#"></span><span>'.$</span><span style="color:#bf616a;">text</span><span>.'</span><span style="color:#a3be8c;"></a></li></span><span>'</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">protected function </span><span style="color:#8fa1b3;">getActivePageWrapper</span><span style="color:#eff1f5;">(</span><span>$</span><span style="color:#bf616a;">text</span><span style="color:#eff1f5;">)
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span>'</span><span style="color:#a3be8c;"><li class="active"><a href="#"></span><span>'.$</span><span style="color:#bf616a;">text</span><span>.'</span><span style="color:#a3be8c;"></a></li></span><span>'</span><span style="color:#eff1f5;">;
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">protected function </span><span style="color:#8fa1b3;">getDots</span><span style="color:#eff1f5;">()
</span><span style="color:#eff1f5;"> {
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">return </span><span>$</span><span style="color:#bf616a;">this</span><span style="color:#eff1f5;">-></span><span style="color:#bf616a;">getDisabledTextWrapper</span><span style="color:#eff1f5;">(</span><span>'</span><span style="color:#a3be8c;">&hellip;</span><span>'</span><span style="color:#eff1f5;">);
</span><span style="color:#eff1f5;"> }
</span><span style="color:#eff1f5;">}
</span></code></pre>
Middleman Template: bootstrap3, SASS and Slim2013-11-12T00:00:00+00:002013-11-12T00:00:00+00:00https://www.fullstackstanley.com/articles/middleman-template-bootstrap3-sass-and-slim/<p>As quoted from their website, Middleman is "A static site generator using all the shortcuts and tools in modern web development".</p>
<p>I really love using Middleman for simple static websites. Everything I use in my front end stack (SASS and coffeescript) just works out of the box.</p>
<p>Using two commands <code>middleman</code> while developing a website locally and then <code>middleman build</code> when I'm ready to push the static content to my server. It really saves a lot of time.</p>
<span id="continue-reading"></span>
<p>Anyway to the point of this blog post. One of the features of Middleman is the ability to load ready made templates so you don't have to waste time setting up layouts.</p>
<p>I have written a small template for Middleman that sets up Bootstrap 3 with the Slim templating engine (My preference to HTML). This also uses Bower for javascript dependancies (You will need Node and NPM installed for this).</p>
<p>You can view it / download it from my github repo <a href="https://github.com/acoustep/middleman-bootstrap3-sass-slim">available here</a>.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="http://middlemanapp.com/">Middleman</a></li>
<li><a href="http://nodejs.org/">NodeJS</a></li>
<li><a href="https://npmjs.org/">NPM</a></li>
<li><a href="http://bower.io/">Bower</a></li>
</ul>