Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Friday, August 15, 2014

How to create an image gallery with file upload into different folders (part 2)

This part is about setting the gallery live.
The configuration will be:

There is the fat cloud which contains my small host with a unique IP-Address.
I've been using digital ocean to setup the system at http://gallery.code-lounge.com.
To map the IP-Address to a more readable name I've booked an address at a DNS-Provider. Mine is hosteurope. Eventually the requested page will be delivered to the user.
The application stack on the server contains NodeJS, node-forever and nginx. Nginx is used as a proxy before nodejs. Forever makes sure the script runs forever and won't stop by an error.
I've chosen the distribution Ubuntu 14.04 for my host and my further description will be related to Ubuntu.

Copy the gallery script to the server

I've used the directory /usr/share/nginx/www/gallery for the gallery.
Clone the repository and create the required symlinks explained in part 1.

nginx

First I've added the recommended repository from the nginx wiki to my sources. This will make sure I have a more current version available than the repository that is included into Ubuntu by default.
apt-get install nginx will install nginx.
Now open the /etc/nginx/nginx.conf file and paste the following code into the http part.


upstream gallery.code-lounge.com {
    server 127.0.0.1:3002;
}

server {
    listen 0.0.0.0:80;
    server_name gallery.code-lounge.com;
    access_log /var/log/nginx/gallery.code-lounge.com;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass http://gallery.code-lounge.com/;
        proxy_redirect off;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    client_max_body_size 10M;
}

Now replace all occurrences of gallery.code-lounge.com with your own hostname. Save the file and reload nginx with service nginx reload. Testing the host will provide a bad gateway response since nodejs is not setup yet.

NodeJS

Same like for nginx I want to have most current version. Therefor I've executed the curl command recommended in the official node js installation instructions.
apt-get install nodejs will do the installation.

Node-Forever

Now install forever with npm install -g forever.
The server can be started now with using forever start /usr/share/nginx/www/gallery/app.js

forever list will show you the currently running scripts
forever stop index will stop the script.

You should the the folders of your folders.json after typing the url into your browser.

Tuesday, August 12, 2014

How to create an image gallery with file upload into different folders (part 1)

You can checkout the github project here.
There is an example page here: gallery.code-lounge.com

Introduction

I wanted to have an easy to use image gallery with upload functionality.
The effort must be reduced to a minimum (since I have no time).
The article is splitted into two parts. In the first I'll explain how to setup the folder and gallery view including the upload.
The second part will be about setting the system live using nginx and securing the project with htaccess.

I decided to use existing projects of blueimp. 
The Bootstrap image gallery will make sure that the gallery is compatible with most devices. JQuery File Upload (also by blueimp) is responsible for a nice user experience during the upload process. The user must be able to use either drag and drop or select multiple files at once to make the upload process as convenient as possible.

The project in screenshots

I discovered (as always) that the complexity is much higher than previously assumed.
The result will look like this:

Up there you can see the gallery view. Folders are listed there. Blue folders are filled with pictures. Grey ones are empty.


This is the folder view. The images are responsively aligned. Also pictures taken in portrait mode should be handled nicely.


The upload process will look like this. As mentioned multiple files are possible with either using drag and drop or the dialog. After uploading the preview picture and loading animation will fly away (or get removed) with a fancy animation.

Technology

I've used twitter bootstrap, jquery and the two mentioned blueimp libraries for the frontend. Fontawsome provides nice icons.
In the backend I decided to use nodeJS or more specific expressJS.

Please keep in mind: I really needed to get this done as fast as possible. You won't find any new hipster technology like angularJS, unit tests or anything other alike.
The frontend part of the project is based on existing example code copied together.
I spend a little bit more time at the backend nodeJS part, but I think there could be lots of improvements there as well.

Folder Structure


Installing npm packages

Create a new folder, open the terminal and enter:
For initializing the project
npm init

For the file upload
npm install blueimp-file-upload --save

For the image gallery
npm install blueimp-bootstrap-image-gallery --save

For handling the webserver in nodeJS
npm install express --save

For creating smaller preview images in nodeJS
npm install gm --save

For handling file uploads in nodeJS
npm install busboy --save

The next part is system dependend.
An image conversion library is necessary. I decided to use imagemagick
For Ubuntu
sudo apt-get install imagemagick

For MacOSX
sudo port install imagemagick
or
sudo brew install imagemagick

Now I've created a public folder which contains static files delivered by the webserver.

mkdir public

Since I want to expose frontend libraries only I create symlinks to the frontend npm packages:
ln -s /Users/<user>/projects/image_gallery/node_modules/blueimp-bootstrap-image-gallery public
ln -s /Users/<user>/projects/image_gallery/node_modules/blueimp-file-upload public

Folder View

Backend

I kept it very simple: The folders are stored in a JSON file like this:


{
  "folder_1": "Folder 1",
  "folder_2": "Folder 2",
  "folder_3": "Folder 3"
}

The request is done to folder.json but will be catched by expressJS which will look into the photo-folders, check if they are empty and deliver something like this:



{
  "folder_1": {
    "title": "Folder 1",
    "isEmpty": false
  },
  "folder_2": {
    "title": "Folder 2",
    "isEmpty": true
  },
  "folder_3": {
    "title": "Folder 3",
    "isEmpty": true
  }
}


This is needed to show the colors in the frontend.

Frontend

The folder view contains some html and a small js part (which is directly included into html part).
The javascript does an ajax request to request folders.

Gallery View

Frontend

Well I already told you about my copy and paste approach.
So I did:
cp public/blueimp-bootstrap-image-gallery/index.html public/

Edited index.html and replaced lines
<link rel="stylesheet" href="css/bootstrap-image-gallery.css">
<link rel="stylesheet" href="css/demo.css">
<script src="js/bootstrap-image-gallery.js"></script>
<script src="js/demo.js"></script>

with

<link rel="stylesheet" href="blueimp-bootstrap-image-gallery/css/bootstrap-image-gallery.css">
<link rel="stylesheet" href="blueimp-bootstrap-image-gallery/css/demo.css">
<script src="blueimp-bootstrap-image-gallery/js/bootstrap-image-gallery.js"></script>
<script src="blueimp-bootstrap-image-gallery/js/demo.js"></script>

Doubleclicked index.html and check.
For the upload I simply copied lots of basic-plus.html included in the blueimp-file-upload project.
For more information check the github project.

Backend

The backend provides the image names for listing the images and he upload functionionality into different folders.

Setting up a test server

You could just use node app.js but a better approach would be to install nodemon:
(sudo) npm install -g nodemon

Nodemon has the advantage to check if files are modified and restart nodejs atomatically to ensure that the files are always up to date.

nodemon app.js
will start the server.
Open the browser and put http://127.0.0.1:3002 into the address field.

Saturday, January 4, 2014

How to make Array-splice to take an array of values

Did you ever come to a situation where you want use splice with an array of values?
According to w3schools the definition of splice is

array.splice(index,howmany,item1,.....,itemX)

Instead of item1,.....,itemX I'd like to hand over an array of values.
I've used the build in method apply to call splice on the Array prototype directly:


var test = ["1", "4"],
    args = [1, 0, "2", "3"];

Array.prototype.splice.apply(test, args);
console.log(test); // output: [ '1', '2', '3', '4' ]

Saturday, December 14, 2013

Simple jQuery translate3d plugin

Hi,
this article is about my jquery-translate3d github project.

For my current project I need to make a lot of translate3d transformations. The main issue is that every time you call translate3d you must do a calculation with the previous value to avoid that the animation starts at the origin. I made a js fiddle where you can watch the animation here.
And here is the an embedded code pen example :)

See the Pen mFpJc by Florian Biewald (@flodev) on CodePen

The first animation moves the element 100px on x and y axis (or left and top).
Now the second animation starts and wants to move the element 200px on x. Since the second animation has no knowledge about the first transformation. The element pops back to left 50px and top 50px and then moves 200px to the left completely ignoring the previous animation.

$('#element').css({
    '-webkit-transform': 'translate3d(200px, 10px, 0px)'
});

Now my (really simple) jquery plugin stores the values of the previous transformation directly on the element itself means I can focus on my transformation without thinking about the last transformation.
Use it like this:

$('#element').translate3d({
    x: 10,
    y: 10
});

See the Pen edGoc by Florian Biewald (@flodev) on CodePen


As you can see the div remains on the the same y-level.
You can also use rotate to rotate the element (which leads the name jquery-translate3d to absurdity, but who cares:)).
Rotate doesn't calculate internally so every time you use rotate you are overriding the previous value.

$('#element').translate3d({
    x: 10,
    y: 10,
    rotate: 20
});
The plugin is save for use with every browser that supports CSS-transform. It uses browser prefixes to ensure this (-moz-, -webkit- etc.).

Sunday, November 10, 2013

Requirejs test boilerplate

This time I'd like write about executing unit tests in a require js AMD environment.
You can find the complete code at github.
Given are the following two modules:
coffee/app/Playground.js
define(
    [
        'jquery'
    ], ->
        class Playground
            constructor: ->
                @$el = $ '.playground'
            add: (el)->
                @$el.append el
)

coffee/app/Player.js
define(
    [
        'Playground'
        'jquery'
    ], (Playground)->
        class Player
            constructor: ->
                @playground = new Playground

            scream: ->
                @$el.text 'waaaaaaaaaaaa'
                @

            render: ->
                @$el = $ '<div class="player"></div>'
                @playground.add @$el
                @
)

coffee/app/Zombie.js
define(
    [
        'Playground'
        'jquery'
    ], (Playground)->
        class Zombie
            constructor: ->
                @playground = new Playground

            moan: ->
                @$el.text 'uuuuuaaaarrr'
                @

            render: ->
                @$el = $ '<div class="zombie"></div>'
                @playground.add @$el
                @
)

As you can see player and zombie requires both playground and executing a function.
I want to test player and zombie independently without playground.
Therefor I'd like to mock the functions of playground.
Requirejs provides a map property to support annother version of a module:
requirejs.config({
    map: {
        'some/newmodule': {
            'foo': 'foo1.2'
        },
        'some/oldmodule': {
            'foo': 'foo1.0'
        }
    }
});
This means I would have to create two versions of a playground mock since I want to return different things with getCoordinates.
But I don't want to create different files of the same object every time I need a new behavior.
I've created a setup where every module can have its own mocks and you can change them dynamically without creating different version files.
Using my boilerplate from github I'm able to mock modules using the test configuration file:


define(
    [

    ], ->
        [
            path: 'Player', defineModules:
                'Playground': ->
                    define 'Playground', ->
                        class FakePlayground
                            add: -> console.log "mocked playground->add for Player has been called"

        ,
            path: 'Zombie', defineModules:
                'Playground': ->
                    define 'Playground', ->
                        class FakePlayground
                            add: -> console.log "mocked playground->add for Zombie has been called"
        ]
)

Friday, February 17, 2012

Wednesday, February 15, 2012

Release of class.js

Today I like to present my new JS lib for prototype based inheritance.
class.js is inspired by javascriptMVC.
You can get it at github.

There is also a page with examples. Just click on Class.js in the main navigation.

Features
  • namespaces
  • constructor method
  • inheritance
  • call parent with _super()
  • static methods
  • private methods
  • optional use of $.Interface
Feel free to post your feeedback.

Saturday, November 5, 2011

How to organize ExtJS 4 in huge projects

My first blog post ... yehaaa.
Ok back to topic.

Background

In my recent project I use ExtJS 4.0.2a to obtain a unify clean user interface.
The structure of ExJS should be conform to the PHP backend which is structured in different modules. This is necessary to provide a consistent ACL.

Getting started with ExtJS 4

Javascript always excited me with the freedom to script functional and object oriented with different inheritance approaches, so I know how to debug JS.
I'm not real beginner with ExtJS but far from being experienced. I was using a few components at version 2.
Sooo for getting started it was the best to take a closer look at the tutorials on sencha.com.
The MVC tutorial was the best entry point for getting some know how.
After that set up the project wasn't very difficult.

In this tutorial ExtJS pretends to use the following folder structure:
project/app/
controller
model
store
view

This doesn't fit with the requirement to use modules.
Then I did a little research how to organize ExtJS with modules and didn't got the right solutions.

So I did a little debugging session at the ExtJS autoloader and found out that if I use absolute Class Names the autoloader will find my classes also if i put them into module folders...

Example

Let's say we have the following folders:


We have three modules each contains controller, model, store and view folders.
The project folder contains the extjs bootstrap file app.js with the following code:


Ext.application({
    name: 'Project',

    appFolder: '/project/app',

    controllers: [
        'Poject.blog.controller.Index',
        'Poject.forum.controller.Index',
        'Poject.administration.controller.Index'
    ],

    launch: function()
    {
        Ext.create('Project.blog.view.Viewport');
    }
});

As you can see I'm using absolute names starting with the project name (which is imaginative "Project" in this case).

And this should do the trick. When you keep this convention through all classes within your project all files could be loaded by ExtJS autoloader.

Easy isn't it?
Enough for my first post ... hopefully :)

Class example:


Ext.define('Project.blog.view.Viewport', {
    extend: 'Ext.container.Viewport',
    ...
    ...
    ...
});

Controller Example:


Ext.define('Project.blog.controller.Index', {
    extend: 'Ext.app.Controller',

    models: ['Project.blog.model.SomeModel'],

    stores: ['Project.blog.store.SomeStore'],

    views: ['Project.blog.view.Viewport'],

    init: function() { ... }
});