Views

A view is what we are referring to as an HTML page. They are called views because of the Model View Controller (MVC) design pattern. Actually, the pattern we're using is closer to that of Model, View, ViewModel (MVVM). Typically, a Model is the data that is going to be displayed on a page (again, in our case known as a ViewModel), the View is the page itself, and the Controller is the brain that communicates between the ViewModel and the View.

Our particular application is going to need two views. The first view is the home page, and the second view is the image page.

Note

The HTML in the following section relies heavily on Bootstrap, a popular HTML framework created by Twitter that provides a standard set of user interface elements. These include buttons, fonts, layout grids, color schemes, and a whole lot more. Using Bootstrap allows us to not only present our application with a nice clean UI, but also build it so that it is responsive and will look correct on any device that is viewing it. You can learn more about Bootstrap by visiting http://getbootstrap.com.

Let's start by creating the home page view. Create a new file within the views folder, name it index.handlebars, and insert the following HTML code:

<div class="panel panel-primary">
    <div class="panel-heading">
        <h3 class="panel-title">
            Upload an Image
        </h3>
    </div>

Note

The reason we named our file index.handlebars is purely personal choice, but it is also based on common naming conventions on the Web. Typically, an HTML page that acts as the root file for any website is named index.whatever (.php, .aspx, .html, and so on). Again, this is just common convention and not something you need to specifically adhere to.

Create a basic HTML form and set the method to POST and action to /images. Be sure to set the enctype attribute of the form since we will be uploading files as well as submitting data via form fields:

<form method="post" action="/images" enctype="multipart/form-data">
        <div class="panel-body form-horizontal">
            <div class="form-group col-md-12">
                <label class="col-sm-2 control-label" for="file">Browse:</label>

Here, we have included a standard HTML input field for the file to be uploaded:

                <div class="col-md-10">
                    <input class="form-control" type="file" name="file">
                </div>
            </div>
            <div class="form-group col-md-12">
                <label class="col-md-2 control-label" for="title">Title:</label>
                <div class="col-md-10">

Another standard HTML input field for the title of the file can be whatever the user wants, as shown in the following code:

                    <input class="form-control" type="text" name="title">
                </div>
            </div>
            <div class="form-group col-md-12">
                <label class="col-md-2 control-label" for="description">Description:</label>
                <div class="col-md-10">

And a standard HTML textarea input field to allow for a description is as follows:

                    <textarea class="form-control" name="description" rows="2"></textarea>
                </div>
            </div>
            <div class="form-group col-md-12">
                <div class="col-md-12 text-right">

A standard HTML button is provided that will submit the form to the server. Using Bootstrap classes, we provide btn and btn-success to make this look like a Bootstrap-style button with the default color for success (green):

                    <button type="submit" id="login-btn" class="btn btn-success" type="button"><i class="fa fa-cloud-upload "></i> Upload Image</button>
                </div>
            </div>
        </div>
    </form>
</div>

After the upload form section, we will display a list of the newest images uploaded to the website:

<div class="panel panel-default">
    <div class="panel-heading">
        <h3 class="panel-title">
            Newest Images
        </h3>
    </div>
    <div class="panel-body">
        {{#each images}}
            <div class="col-md-4 text-center" style="padding-bottom: 1em;"><a href="/images/{{ uniqueId }}"><img src="/public/upload/{{filename}}" alt="{{title}}" style="width: 175px; height: 175px;"  class="img-thumbnail"></a></div>
        {{/each}}
    </div>
</div>

There are two important sections in the main home page HTML code. The first is the form we define that will be the main way users will upload images to the website. As we will be accepting image files as well as the details for the image (title, description, and so on), we need to ensure that the form is set up to accept multipart data. We also set the form action to point to the /images route we defined earlier in our routes and image controller modules. When a user completes the form and clicks on the Submit button, the form will send a POST request to http://localhost:3300/images, and our router will catch that and forward it to our image controller. From there, the image controller will handle processing the data and saving it to the database, saving the image file to the filesystem, and redirecting to the image details page. We will actually be writing this logic in the next chapter. For now, nothing will actually happen if you submit the form.

Below the main image uploading form on the home page, we also have a section that performs a Handlebars loop using each and iterates through an image collection, displaying each image as a thumbnail and the link to the image page. The images collection will be populated from our home controller when we build its ViewModel. It's important to take note here that when you are inside an {{#each}} loop in a Handlebars template, your context changes. That is, the path you use to access data inside each is now based on each item in the collection. Here, our ViewModel will have an image collection, and each item in the image collection will have a property for uniqueid, filename, and title. With the home page view out of the way, let's set up the view for the image page.

Create another file in the views folder named image.handlebars. This file is going to have a bit more functionality, so I'm going to break it down into chunks so we can review each section. First, insert the following block of code:

<div class="panel panel-primary">
    <div class="panel-heading">
        <h2 class="panel-title">{{ image.title }}</h2>
    </div>
    <div class="panel-body">
        <p>{{ image.description }}</p>
        <div class="col-md-12 text-center">
            <img src="/public/upload/{{image.filename}}" class="img-thumbnail">
        </div>
    </div>
    <div class="panel-footer">
        <div class="row">
            <div class="col-md-8">
                <button class="btn btn-success" id="btn-like" data-id="{{ image.uniqueId }}"><i class="fa fa-heart"> Like</i></button>
                <strong class="likes-count">{{ image.likes }}</strong> &nbsp; - &nbsp; <i class="fa fa-eye"></i> <strong>{{ image.views }}</strong>
                &nbsp; - &nbsp; Posted: <em class="text-muted">{{ timeago image.timestamp }}</em>
            </div>
        </div>
    </div>
</div>

This block of code defines the bulk of the content that will be displayed on the page for a specific image. The ViewModel for this page is going to consist of an image object that has various properties defined that you see being used throughout the code; properties such as title, description, filename, likes, and views.

You may have noticed a slightly different piece of syntax in there specific to the {{ timeago image.timestamp }} timestamp. That is actually a Handlebars helper. It is a custom function we will write shortly that will do some special string formatting—specifically, converting a timestamp string to how long it was sometime ago (that is, 2 days ago, 12 hours ago, 15 minutes ago, and so on).

We want to allow users to post comments to images, so let's include a simple form for that:

<div class="panel panel-default">
    <div class="panel-heading">
        <div class="row">
            <div class="col-md-8">
                <strong class="panel-title">Comments</strong>
            </div>
            <div class="col-md-4 text-right">
                <button class="btn btn-default btn-sm" id="btn-comment" data-id="{{ image.uniqueId }}"><i class="fa fa-comments-o"> Post Comment...</i></button>
            </div>
        </div>
    </div>
    <div class="panel-body">
        <blockquote id="post-comment">
            <div class="row">

The following is another standard HTML form with the method and action set. This form allows a user to enter, via standard HTML input fields, his/her name, e-mail address, and comments. Another submit button is provided to save the comment:

                <form method="post" action="/images/{{ image.uniqueId }}/comment">
                    <div class="form-group col-sm-12">
                        <label class="col-sm-2 control-label" for="name">Name:</label>
                        <div class="col-sm-10">
                            <input class="form-control" type="text" name="name">
                        </div>
                    </div>
                    <div class="form-group col-sm-12">
                        <label class="col-sm-2 control-label" for="email">Email:</label>
                        <div class="col-sm-10">
                            <input class="form-control" type="text" name="email">
                        </div>
                    </div>
                    <div class="form-group col-sm-12">
                        <label class="col-sm-2 control-label" for="comment">Comment:</label>
                        <div class="col-sm-10">
                            <textarea class="form-control" name="comment" rows="2"></textarea>
                        </div>
                    </div>
                    <div class="form-group col-sm-12">
                        <div class="col-sm-12 text-right">
                            <button type="submit" id="comment-btn" class="btn btn-success" type="button"><i class="fa fa-comment"></i> Post</button>
                        </div>
                    </div>
                </form>
            </div>
        </blockquote>

The form action for comments is set to /images/{{ image.uniqueid }}/comment. Again, if you recall from the routes we set up, we specifically defined a route to handle this.

Finally, we want to display any comments that have been submitted for this image. Our ViewModel includes a collection of comments in addition to the image details, so we can simply iterate over that collection using the Handlebars #each block helper:

        <ul class="media-list">
            {{#each comments}}
            <li class="media">
                <a class="pull-left" href="#">
                    <img class="media-object img-circle" src="http://www.gravatar.com/avatar/{{gravatar}}?d=monsterid&s=45">
                </a>
                <div class="media-body">
                    {{ comment }}
                    <br/><strong class="media-heading">{{ name }}</strong> <small class="text-muted">{{ timeago timestamp }}</small>
                </div>
            </li>
            {{/each}}
        </ul>
    </div>
</div>

Much like the loop we perform on the home page to display a collection of images, here we simply iterate through every comment in the comments collection and display the comment and string-formatted timestamp (again using our timeago global helper). We are also using Gravatar to display universal avatar images for users who have commented (assuming they provided their e-mail addresses).

Note

Gravatar is a service provided by https://wordpress.com/ that allows a user's personal profile image to be provided via his/her e-mail address. Many popular web services rely on Gravatar as a quick and easy way to display a user's personal profile image, without requiring the additional functionality to support such a feature. You can learn more about Gravatar at http://gravatar.com.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.246.47