Quantcast
Channel: Joan Mira
Viewing all 270 articles
Browse latest View live

The best codepens of 2015

$
0
0
The best codepens of 2015

These are the most hearted Pens of 2015. Quite impressive! http://codepen.io/2015/popular/pens/. If you are a front-end developer, I would recommend you to set some time aside to review all these examples. They give a real taste of what's trending at the moment and the kind of stuff that the browsers support nowadays.

I can see there's a lot of material design look and feel experiments going on, which confirms the UI design buzz that we've been hearing last year.

Among all these great examples, I specially liked the animated curved content. Mostly because we built something similar (without the animation) for the Dove project and maybe this animation would have looked great on it.

See the Pen Curved Cut by Hornebom (@Hornebom) on CodePen.

These navigation animations examples are not very impressive but can be quite useful for small websites or microsites:

See the Pen Navigation Animation by EvyatarDa (@EvyatarDa) on CodePen.

Another trend that we have seen in the latest years is the animated hamburguer menu icons... Well, now look at this animated search input icon/field and don't tell me it doesn't look sexy!

See the Pen morphing search input by Gregor Adams (@pixelass) on CodePen.


Site of the year 2015

$
0
0
Site of the year 2015

The Awards for design, creativity and innovation on the internet, aka AWWWARDS, have published the list of nominated projects for 2015. These awards, together with theFWA, are the maximum awards given in the Internet. You can call them the Oscars and Grammys of the Internet.

Anyway, I have a favourite and you probably have seen it before. It's called Species in Pieces. A beautiful CSS-based interactive exhibition by Bryan James.

It's a remarkable project with a technical difficulty beyond what normal people can imagine, as all the animals have been hand crafted manually and purely with CSS. I can see this type of work being recognised in future generations as an example of creative innovation.

Best of luck with that award!

Site of the year 2015

Javascript: understanding the weird parts [Part 1]

$
0
0
Javascript: understanding the weird parts [Part 1]

Looking back and analysing how web technologies have evolved in the latest years, I've realised that Javascript is now the single most important skill every web developer must have. It's everywhere (also in the back-end!) and it's never going away (like Flash...).

So, for this new year 2016, I decided to focus in polishing my Javascript and become a JavaScript Samurai / Master of the Universe, HA, HA, HA! (evil laugh).

I purchased three courses in Udemy and the one I'm going to be talking about in this article is called "Javascript: understanding the weird parts". If you want to take it, you can try with the voucher code NEWYOU015 and see if it gives you the course for £13, otherwise I would suggest to write an email to support asking them to give you a new one ;-) The course has been written by Anthony Alicea and currently has more than 32.700 students.

I think I know JavaScript quite well, but it's always good to refresh the concepts, the vocabulary and of course, learn the new ES 6 stuff! So, if you want to join me in this journey, I will be posting all my learnings in the blog, so feel free to read along and share your thoughts.

Javascript: understanding the weird parts [Part 1]

I'm going to skip the first four lectures, which are mainly focussed in giving some context and setting up the coding environment.

Lecture 6: Syntax parsers, execution contexts and lexical environments.

Syntax parsers: A program that reads your code and determines what it does and if its grammar is valid. Your code isn't magic. Someone else wrote a program to translate it for the computer and they might add "extra stuff" in during that translation.

Lexical environment: where something sits physically in the code your write. 'Lexical' means 'having to do with words or grammar'. A lexical environment exists in programming languages in which where you write something is important.

Where you see things written in the code, it will give you an idea of where they will be sitting in the memory.

Execution context: a wrapper to help manage the code that is running. There are lots of lexical environments. The one which is currently running is managed via execution contexts. It can contain things beyond what you've written in your code.

Lecture 7: Name/Value pairs and objects

Name/Value pair: a name which maps to a unique value. The name may be defined more than once, but only can have one value in any given context. That value can be also a new name/value pairs.

Object: a collection of name value pairs. The simplest definition when talking about Javascript. Don't think any more deeply of an object than this!

Lecture 9: The global environment and the global object

The base execution context is the global one. The thing that is accesible from anywhere in your code. Javascript creates also the reserved word 'this' and in the global context, this represents the window, the browser window, which also can be accessed with the reserved word 'window'. Each tab in the browser has its own execution context.

When we say 'global', in Javascript means 'not inside a function'. Don't think any deeper than that.

Note: If we are running Node.js, the global object will not be the window.

When we create variables and functions that are not sitting inside any other function, they get attached to the global object. So we could access them using window.anyVariable or window.anyFunction.

Lecture 10: The execution context: creation and 'hoisting'

If you are not a native english speaker, you might have found yourself wondering what hoisting means. Hoisting means to bring something to the top, like when using a hoist to lift stuff.

In Javascript, there are situations were we have declared variables and functions at the bottom of a script but we are actually using them before they are declared, which will return undefined (in the case of the variable).

Hoisting means that Javascript brings to the top the variables and functions when the execution context is created, but let's look at it in more detail:

1st phase: the creation phase.

  • Create the global object
  • Create 'this'
  • Create the outer environment
  • Recognise the variables and function that we created and setup memory space for them -> 'hoisting'

So, hoisting means that, in this phase, our stuff will exist in memory and that all variables are set initially to undefined. That's it so far.

Lecture 11: Javascript and 'undefined'

'undefined' is a special keyword. It's a value. It means that the variable hasn't been set. If it wasn't declared, it would throw an 'uncaught ReferenceError'. It's better not to set 'undefined' manually because then, we wouldn't know if it was us or Javascript who set it to undefined.

Lecture 12: The execution context: code execution

In Lecture 10 we talked about the creation phase. Now, in the execution context, we are just going to run line by line the code prepared by the creation phase.

Lecture 13: Single threaded, synchronous execution

Single threaded: one command at a time. Under the hood of the browser, maybe not. But from our perspective, JS is single threaded.

Synchronous: one at a time and ir order...

Lecture 14: Function invocation and execution stack

Invocation: running a function or calling a function. In Javascript, by using parenthesis ()

Every time you execute a function, a new execution context is created and placed on top of the execution stack, where the global execution context is always at the bottom.

Each time the execution context of a function ends, it pops off the execution stack.

Lecture 15: Functions, context and variable environments

Variable environment: where the variables live and how they related to each other in memory.

This is about variable scope and the difference between global vars and local vars scope.

Lecture 16: The scope chain

When looking for variables, each execution context has a reference to its outer environment, and this outer environment is where the code was written physically. So, the Javascript engine will keep moving down (looking for the variable) in the execution stack until it hits the global context.

Lecture 17: Scope, ES6 and let

Scope: where a variable is available in your code and if it's truly the same variable or a new copy

let is a new ES6 way to declare variables, allowing block scoping (declared inside {}) and only creating it in memory when reaching the line where it's defined.

Lecture 18: What about asynchronous callbacks?

Asynchronous: more than one at a time.

The Javascript engine has hooks that link with other browser engines and modules like the rendering engine or HTTP requests.

There's another list that sits outside the execution stack called the 'Event Queue'. This lists stores click events, http requests, etc.

The Javascript Engine looks at that list ONLY when the execution stack is EMPTY! then it looks periodically at the event queue to see if there's anything that needs to be run.

So that means long running functions can block anything else from running, so Javascript can run asynchronous events but in a synchronous way :D

Lecture 19: Types and Javascript

Dynamic typing: you don't tell the Javascript engine what type of data a variable holds, it figures it out while your code is running. Variables can hold different types of values because it's all figured out during execution.

Lecture 20: Primitive types

Primitive type: a type of data that represents a single value. That is, not an object.

undefined: represents a lack of existence (you shouldn't set a variable to this).

null: represents a lack of existence (you can set a variable to this).

boolean: true or false

number: floating point number (there's always some decimals). Unlike other programming languages, there's only one 'number' type... and it can make math weird.

string: a sequence of characters (both '' and "" can be used)

symbol: used in ES6 (the next version of Javascript).

Lecture 21: Operators

Operator: a special function that is syntactically (written) differently. Generally, operators take two parameters and return one result.

The way we use operators is called infix notation, ie. 3 + 4

Lecture 22: Operator precedence and associativity

Operator precedence: which operator function gets call first when there's more than one. Functions are called in order of preference (Higher preference wins).

Operator associativity: what order operator functions get called in: left-to-right or right-to-left. When functions have the same precedence.

In this table you can find the precedence of the operators.

Lecture 24: Coercion

Coercion: converting a value from one type to another. This happens quite often in Javascript because it's dynamically typed. In example, when we try the following 1 + '2', the result would be 12 rather than 3, just because the JS engine will guess that both numbers are strings.

Lecture 25: Comparison operators

Sometimes, when we have a chain of comparisons, like for example (3 < 2 < 1), the result, rather than false, will be true. In this case, (3 < 2) is returning false and then (false < 1) returns true because false is coerced into 0.

In the same way, when comparing values, like ('3' 3), (false 0), (null < 1), ("" 0), ("" false) or (undefined = 0) it would return true. On the other hand, (null = 0) will return false.

How do we fix it? With the strict equality: =

In this table you can find the sameness comparisons.

Lecture 27: Existence and boolean

If we try to convert null, undefined or "" to boolean, we always get false. Boolean(null) returns false;

We can use this for our advantage. When we put something in a 'if' statement, it's going to try to convert it to a Boolean, so we can use it to check if a variable has content. In example:

var a; // a is undefined
if (a) {
    console.log('Something is there.');
}
The only scenario where a will be coerced into false even if it has content is when a = 0, so we could change the condition to if (a || a = 0). ###Lecture 28: Default values When we use functions with parameters, if we don't pass the parameters when we call the function, these get initialised to undefined and that's it. But there's a neat trick to override this:
function greet(name) {
   name = name || 'Your name here';
   console.log('Hello' + name);
}
greet('Joan');
So, basically it returns the value that can be coerced into true. So if we call greet() without any parameters, 'Your name here' will be reddened because it can be coerced to true. Note: in ES6 there's a new way to do this... ###Lecture 29: Framework default values Let's image we have two libraries (lib1.js and lib2.js) that we are loading beside our app.js. Both libraries are declaring a variable called libraryName and setting it to 'Lib 1' and 'Lib 2' respectively. The problem here is that when we output that variable from app.js, the result will be 'Lib 2' because it overrides the previous one. To avoid this, what most libraries do is to assign the object to the global window object ONLY if there's nothing there:
window.libraryName = window.libraryName || 'Lib 2';
###Lecture 30: Objects and functions In other languages, objects and functions are different, but in Javascript, they are very much the same. An object is a collection of values that are given names. An object can have properties and methods. Properties can be primitives (like booleans, numbers, etc). The property can also be another object and the methods are the functions that the object have. We can create an object like this (there are better ways of doing it, but for the moment let's do it like this):
var person = new Object();
To create a primitive (a string) using a computed member access:
person["firstname"] = "Joan Mira";
The brackets are an operator that looks for that property in the person object. This is useful if we need to precompose the name of the member property. We can also store the primitive name in a variable and use it to locate that primitive in the object:
var firstNameProperty = "firstname";
console.log(person[firstNameProperty]);
We can also use the '.' operator to access the member primitive (which is the recommended way):
console.log(person.firstname);
We can also create an object sitting inside the person object:
person.address = new Object();
person.address.street = "111 Main St.";
person.address.city = "London";
###Lecture 31: Objects and object literals To create object literals, we use the curly braces, which is not an operator. It's just the JS engine assuming that we are creating an object.
var person = {};
We can also set and initialised properties and methods:
var person = { firstname: 'Joan', lastname: 'Mira' };
It's also recommended to use white space and put each property on a different line:
var Joan = {
    firstname: 'Joan',
    lastname: 'Mira',
    address: {
        street: '111 Main St.',
        city: 'London'
    }
};
And we can pass the object to a function:
function greet(person) {
    console.log('Hi ' + person.firstname;
}
greet(Joan);
We can also create objects on-the-fly:
greet({
    firstname: 'Mary',
    lastname: 'Doe'
});
###Lecture 32: Faking namespaces **Namespace**: a container for variables and functions. Typically to keep variables and functions with the same name separate.
var greet = 'Hello!';
var greet = 'Hola!';

console.log(greet); // Renders Hola!
We can prevent that collision by creating containers:
var english = {};
var spanish = {};

english.greet = 'Hello!';
spanish.greet = 'Hola!';
###Lecture 33: JSON and object literals JSON (JavaScript Object Notation) looks a lot to the JS object syntax but let's not fall into that mistake.
var objectLiteral = {
    firstname: 'Mary',
    isAProgrammer: true
};
JSON format:
{
    "firstname": "Mary",
    "isAProgrammer": true
}
In JSON, properties need to be wrapped in quotes. There are also utilities to convert objects into JSON:
JSON.stringify(objectLiteral);
And to parse them (convert from JSON into JS object):
var jsonValue = JSON.parse('{ "firstname": "Mary", "isAProgrammer": true }');
###Lecture 34: Functions are objects **First class functions**: everything you can do with other types you can do with functions. Assign them to variables, pass them around, create them on the fly. Functions don't need a name, they can be anonymous and the code that we write in the function is just one of the properties that we are adding to the function. The special thing is that that property is invocable (); We have to think of functions as objects, whose code happens to be a property of that object. It can be moved around, copied, just like a string or a number or another object.
function greet() {
    console.log('hi');
}

greet.language = 'english';
Yes! we can add properties to a function. FUNCTIONS ARE OBJECTS. ###Lecture 35: Function statements and function expressions **Expression**: a unit of code that results in a value. It doesn't have to save to a variable. For example (a === 3), that's an expression. On the other hand, a statement is something that doesn't return a value, like for example an 'if' statement. With functions there's a similar scenario. The following is a function statement that doesn't return a value:
function greet() {
    console.log('hi');
}
On the other hand, this a function expression:
var anonymousGreet = function() {
    console.log('hi');
}
We are creating an object on the fly and assigning it to a variable. The difference is that anonymousGreet has the ADDRESS in memory of the anonymous function. ###Lecture 36: By value vs by reference When talking about assigning the value of a variable to another one, in the case of primitives, JS COPIES the value into a new memory address. This is **by value**. Now, for objects (all objects), when we are trying to make two the same value, instead of getting a new location in memory, simply points to the same location in memory. There's no copy. So, two names point to the same address. This is called **by reference**. When modifying objects, we often hear these two concepts, which sound much more complicated than what they actually are. **Mutable**: to change something **Immutable**: that cannot be changed ###Lecture 37: Objects, functions and 'this' If you create a function (even a function expression) in the global context, invoke it and console.log 'this' inside that function, you will get the global window as a result. On the other hand, if we declare a method inside an object and we console.log 'this' in that method, we will get as a result the object. A lot of people think that JS has a bug when we create a new method inside that method from the previous object and use 'this' to mutate the object. In this case, 'this' will no longer point to the object, but to the global window WTF! To fix this Bug, we can use this popular trick:
var self = this;
That will create a reference to the right object scope that we can use to target its properties and methods, so we can communicate from inside the method with other properties and methods of the object. ###Lecture 38: Arrays - collections of anything Arrays can be defined with = new Array() or using the literal format with brackets []. They can hold collections of anything, even mixing different types! ###Lecture 39: 'arguments' and spread **Arguments**: the parameters you pass to a function. Javascript gives you a keyword of that same name that contains them all. Example:
function greet(firstname, lastname, language) {
    console.log(arguments);
}
The reserved word arguments will return an pseudo-array with the parameters that the function received. ###Lecture 40: Function overloading Function overloading is to have another function with the same name but different parameters. In Javascript there's no such functionality, but we can replicate it using other patterns, like conditionals inside the function to return one of the other result. ###Lecture 41: Syntax parsers Javascript reads each word character by character. ###Lecture 42: Dangerous! automatic semicolon insertion The syntax parser tries to be helpful by not requiring the semicolon at the end of the line. The Javascript is putting them automatically where he thinks it should be. We don't want the JS engine to be taking those decisions for us. It can cause a BIG problem in our code because it's very difficult to track. ###Lecture 43: Whitespace **Whitespace**: invisible characters that create literal 'space' in your written code. Carriage returns, tabs, spaces. Javascript is quite liberal at accepting whitespace, so we can actually write comments between var and the name of the variables or inside the object literals. Make your code readable, understandable. Write comments! Don't be too bothered with the whitespace. ###Lecture 44: IIFEs (Immediately Invoked Function Expressions) We already know that the parenthesis () are used to invoke a function, so that's basically what we are going to use for IIFEs:
var greeting = function(name) {
    return 'Hello ' + name;
}('John');

console.log(greeting);
That's fine for function expressions, but how can we do IIFEs with normal functions statements like this one:?
function name() {
    return 'Hello ' + name;
}
There's a trick to make the syntax parser think that the function is a expression. We just need to wrap the function in parenthesis. Because they are an operator and we only use them with expressions, the parser treats it as such. Example:
(function name() {
    var greeting = 'Hello';
    return greeting + ' ' + name;
}('John'))
By the way, we can invoke it before or after the wrapping parenthesis. ###Lecture 45: IIFEs and safe code There are scenarios where a variable (in this case 'greeting') can be defined in two different contexts. So that means, we are not overwriting the greeting variable. They both exist in different context.
var greeting = 'Hola';

(function(name) {
    var greeting = 'Hello';
    return greeting + ' ' + name;
}('John'))

console.log(greeting);
In case we want to pass the global object into the wrapped function, we can do it by passing the window parameter. Remember that objects pass by reference, so we are not copying anything, we are just passing a reference to the global object:
var greeting = 'Hola';

(function(global, name) {
    var greeting = 'Hello';
    // we can access the global object here
    global.greeting = 'Hello';

    return greeting + ' ' + name;
}(window, 'John'))

console.log(greeting);
We are just calling it global because we might want to use the code in the server (where there's no browser). ###Lecture 46: Understanding closures This a notorious topic. It's absolutely vital to understand it to advance in the language.
function greet(whattosay) {
    return function(name) {
        console.log(whattosay + ' ' + name);
    }
}

greet('Hi')('Joan');

Here we have a function that returns a function. Then we invoke the function and invoke again the returned function. We could also call it like this:

var sayHi = greet('Hi');
sayHi('Joan');
The question is, how is it possible that whattosay still exists in the second function? It should be gone, because the context of that function is no longer in the execution stack. Well, that's possible thanks to closures. The JS engine released the execution context of the first function, but the whattosay value is still hanging around... So, the execution context might be gone, but the variable is still in memory because the other function still needs it. That's a closure! The second function is traversing down the scope chain to find the stuff it needs. The execution context has closed in its outer variables. Variables that would normally have referenced anyway, even it their execution contexts are gone. This phenomenon is called a closure. It's not something we create, type or tell JS to do. It's just a feature of JS. They just happen. The JS engine will always make sure that whatever execution context is running, the variables will be always accesible. It's just a feature to make sure that when we run a function, everything works as it should be. ###Lecture 47: Understanding closures [part 2] There is a classic example to explain closures:
function buildFunctions() {
    var arr = [];

    for (var i = 0; i < 3; i++) {
        arr.push(function() {
            console.log(i);
        }
    }

    return arr;
}

var fs = buildFunctions();
fs[0]();
fs[1]();
fs[2]();

So we are just creating three functions in an array using a for loop. Then we invoked the functions and render i. What would i be?

What we would normally expect is that i would be 1, 2, 3, but then we get all 3s!

So, what's happening under the hood is that the console.log is not actually being executed inside the for loop, so by the time we start running the console.log of the functions, the value of i has reached 3.

So, in this case, we still have the i variable in memory but it's not holding the values that we were expecting.

So how do we fix it to render the numbers we want?
In ES 6, we could use let to create de-scoped variables, but we can also prevent the value of i by creating a new execution context for each of the functions that we are pushing to the array. So we could do that by using IIFEs:

function buildFunctions2() {
    var arr = [];

    for (var i = 0; i < 3; i++) {
        //let j = i; //ES6 solution
        arr.push(
            (function(j) {
                return function() {
                    console.log(j);
                }
            }(i))
        )
    }

    return arr;
}

var fs2 = buildFunctions2();
fs2[0]();
fs2[1]();
fs2[2]();

Lecture 48: Function factories

A factory means a function that returns and mix something for us.

function makeGreeting(language) {

    return function(firstname, lastname) {

        if (language === 'en') {
            console.log('Hello ' + firstname + ' ' + lastname);
        }

        if (language === 'es') {
            console.log('Hola ' + firstname + ' ' + lastname);
        }
    }
}

var greetEnglish = makeGreeting('en');
var greetSpanish = makeGreeting('es');

greetEnglish('John', 'Doe');
greetSpanish('Laura', 'Diaz');

Here we are taking advantage of closures to create a factory that returns functions to greet in different languages. This helps us to avoid passing the same parameters all the time for the desired language.

Lecture 49: Closures and callbacks

function sayHiLater() {

    var greeting = 'Hi!';

    setTimeout(function() {
        console.log(greeting);
    }, 3000);
}

sayHiLater();
In this case, we are using a closure (the greeting variable) and a first class function inside the timeout that acts like a function expression. Thanks to the closure, we still have access to the greeting 3 seconds later! In jQuery, we are also using the same things type of function expressions and first-class functions
$("button").click(function() {
});
**Callback function**: a function you give to another function, to be run when the other function is finished. So the function you call (i.e. invoke), 'calls back' by calling the function you gave it when it finishes.
function tellMeWhenDone(callback) {
    var a = 1000; // some work
    var b = 2000; // some work

    callback(); // the 'callback', it runs the function I gave it!
}

tellMeWhenDone(function() {
    console.log('I am done!');
});

Lecture 50: Call(), Apply() and Bind()

All functions hace access to a call, apply and bind method.

Call invokes a function with the scope of the object that we pass and let's us pass comma separated parameters.

Apply is the same thing as call but we pass the parameters as an array. An array is more useful specially under mathematical circumstances.

Bind doesn't invoke the function, it actually creates a copy of the function we are calling and passes the context of an object.

var person = {
    firstname: 'John',
    lastname: 'Doe',
    getFullName: function() {
        var fullname = this.firstname + ' ' + this.lastname;
        return fullname;
    }
}

var logName = function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
}
// we can also finish it like this:
// }.bind(person);

var logPersonName = logName.bind(person);
logPersonName('en');

logName.call(person, 'en', 'es');
logName.apply(person, ['en', 'es']);

With bind, we are creating a new copy of logName and assigning it the execution context of person. So, the value of 'this' will be the correct one rather than the global object.

We can also use call and apply for function borrowing:

var person2 = {
    firstname: 'John',
    lastname: 'Doe'
}

console.log(person.getFullName.apply(person2));

We can also do function currying. With bind we create a new copy of the function, so what happens if we pass parameters to it?

Giving the parameters sets the permanent values of these parameters when the copy is made.

function multiply(a, b) {
    return a*b;
}

var multiplyByTwo = multiply.bind(this, 2);
console.log(multiplyByTwo(4));

So, in this example, the variable 'a' will always be a 2, and the 4 will be the second parameter.
If we passed 2 parameters to the bind, then it means those values would always be the same.

Function currying: creating a copy of a function with some preset parameters. Very useful in mathematical situations.

Lecture 51: Functional programming

We can think and code in terms of functions. It introduces an approach that you can't do in other programming languages that don't have first-class functions.

var arr1 = [1,2,3];
console.log(arr1);

var arr2 = [];
for (var i=0; i < arr1.length; i++) {
    arr2.push(arr1[i] * 2);
}

console.log(arr2);
But we can do something better with functions, to be more flexible. In this way, we are segmenting our code in a more clean way:
function mapForEach(arr, fn) {
    var newArr = [];
    for (var i=0; i < arr1.length; i++) {
        newArr.push(
            fn(arr[i])
        )
    };

    return newArr;
}

var arr1 = [1,2,3];
console.log(arr1);

var arr2 = mapForEach(arr1, function(item) {
    return item * 2;
});
console.log(arr2);

var arr3 = mapForEach(arr1, function(item) {
    return item > 2;
});
console.log(arr3);

var checkPastLimit = function(limiter, item) {
    return item > limiter;
}

var arr4 = mapForEach(arr1, checkPastLimit.bond(this, 1));
console.log(arr4);

var checkPastLimitSimplified = function(limiter) {
    return function(limiter, item) {
        return item > limiter;
    }.bind(this, limiter);
}

var arr5 = mapForEach(arr5, checkPastLimitSimplified(1));
console.log(arr5);

Functional programming is what takes Javascript to the next level.

Lecture 52: Functional programming [part 2]

Underscore.js library is one of the most famous libraries and it's a great example of functional programming.

If you open the annotated source code, you can see the comments on how the functions of undescore.js are implemented.

There's another library called lodash which works like underscore. Some people prefer it over underscore, but the first one was underscore (which is always more difficult, to be the first one).

Some things we can do with underscore:

// underscore
var arr6 = _.map(arr1, function(item) { return item * 3; });
console.log(arr6);

var arr7 = _.filter([2,3,4,5,6,7], function(item) { return item % 2 === 0; });
console.log(arr7);

So, play with underscore, learn how is done and try to build those utilities by yourself.

End of the first part

This is the end of the first part of the course. I hope you enjoyed and apologies if some of the lectures are not very clear. These are just notes I'm taking while watching the videos. If there's anything that needs a better explanation, feel free to comment and I will improve it.

The next lectures will be about object-oriented javascript and prototypal inheritance. Stay tuned! ;-)

Tutorial: build a weather app with React

$
0
0
Tutorial: build a weather app with React

Launch React Weather App

In this React tutorial for beginners, we are going to learn how to build a small and simple React app to display the weather of cities in the world. If you are interested in learning React, this beginners tutorial is a good starting point, as it doesn't cover very complex topics. At the same time, once you learn how to connect to an external API and display the results, it can be quite handy to build other types of single-page apps whose only requirement is to fetch data from an external source and display the results in any way.

Before we begin, you should bear in mind that I am not going to publish the source code. It's a very simple app that can be coded in a few hours, so you should try to do it by yourself. That's how you will learn more! If you have problems, you can write a comment and I will try my best to help you ;-)

Functional requirements

  • Display the city name, current weather icon, temperature, humidity and wind speed
  • The background colour changes based on the temperature
  • Loads a city name using the query string '?city=Madrid'
  • Loads comma separated cities and rotates them after 5s
  • Cache the API data and refresh it after 5m
  • Responsive design. It should work well in all devices

Tech stack

Note: due to the simplicity and small size of the architecture, we will omit the use of BEM and ITCSS.

This is how the app should look like by the end of the tutorial:

Tutorial: build a weather app with React

There can be a few differences in the icons or the font (3rd party dependencies), but the general look and feel will be very similar to any of these two screenshots.

Step 1. Setup the dev environment

The first thing we are going to do is install Node.js. I'm going to be using the Mac Os terminal, Brackets and Chrome. You can use whichever tools or operating system you prefer, all you need is a console, a text editor and a browser.

If you decide to use Brackets, I recommend installing also these extensions:

This is how my Brackets looks like with all these extensions installed:

Tutorial: build a weather app with React

Step 2. Conceptual aside: about Node.js modules

As you probably already know, the fundamental Node building block is called a module which maps directly to a file and everything within that module is private (vars only work in that file).

Now, before we look at how to expose things out of a module, let's look at loading a module. This is where 'require' comes in. 'require' is used to load a module, which is why its returned value is typically assigned to a variable:

var moduleA = require('./filenameA');

As long as our module doesn't expose anything, the above isn't very useful. To expose things we use 'module.exports' and export everything we want. We can export objects or primitives in different ways:

var User = function(name, email) { ... }
module.exports = User;
module.exports = function(name, email) { ... }
var x = 5;
module.exports.x = x;

In this app, we are only going to create one module, the API module (api.jsx), which is going to be taking care of fetching the data from the Weather API. We will talk about it more in detail later.

Step 3. Installing NPM and Bower modules

NPM is a package manager that comes with Node.js. It's very useful to install 3rd party Node.js modules that we can use to speed-up our development.

NPM uses a file called package.json as a reference of all the dependencies that the project is going to have. We can create this file manually or by typing 'npm init'.

Let's start by creating a folder called 'react-weather' whichever you prefer in your computer.

Then open the console/terminal, cd to that folder and type 'npm init'. You will be prompted with a few questions which we don't need to answer. Just keep pressing enter until you exit the process.

Now you should have a package.json file in your folder.

Next we are going to download a few packages (which will be saved automatically in the 'node_modules' folder) and save the reference in the package.json file:

Use 'npm install  --save' afterwards to install a package and
save it as a dependency in the package.json file.

We can also download several packages at the same time. So type the following:

npm install --save browserify classnames gulp gulp-concat gulp-react gulp-sass gulp-server-livereload gulp-util gulp-watch node-notifier react react-dom reactify vinyl-source-stream watchify whatwg-fetch

We are also going to install the gulp client globally (not only for this project). We use the option '-g'. We might need to give admin rights using 'sudo':

sudo npm install -g gulp-cli

It might take a while..., but you should end up with a package.json that looks like this:

{
  "name": "react-weather",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "browserify": "^9.0.3",
    "classnames": "^2.2.3",
    "gulp": "^3.8.11",
    "gulp-concat": "^2.5.2",
    "gulp-react": "^3.0.1",
    "gulp-sass": "^2.0.1",
    "gulp-server-livereload": "1.3.0",
    "gulp-util": "^3.0.4",
    "gulp-watch": "^4.2.4",
    "node-notifier": "^4.2.1",
    "react": "^0.14.3",
    "react-dom": "^0.14.3",
    "reactify": "^1.1.0",
    "vinyl-source-stream": "^1.1.0",
    "watchify": "^2.4.0",
    "whatwg-fetch": "^0.11.0"
  },
  "devDependencies": {}
}

Next, we are going to install Bower (another package manager for the web) and download the weather icons. It will create a folder called 'bower_components' and a registry file called 'bower.json':

npm install -g bower
bower install weather-icons

If we were to upload this project into a Git code repository, we would have to create a '.gitignore' file and add 'node_modules/' and 'bower_components/' to it, as we don't want to upload all these dependencies to the repository. New users could type 'npm install' and 'bower install' to download all the dependencies.

Step 4. Folder structure and placeholders

We are going to create a few folders and files. We should end up with the following folder structure:

/react-weather
    bower.json
    package.json
    gulpfile.js
    index.html
    /bower_components
    /node_modules
    /sass
        main.scss
        /partials
            base.scss
            reset.scss
    /src
        app.jsx
        /utils
            api.jsx

The new files are:

  • gulpfile.js: this is where we will define the tasks to be run, like compiling SASS and JSX, bundling the code, watching for changes, reloading the browser, etc
  • index.html: a very minimal markup for our app
  • main.scss: we will use it to set the order in which we want to load the SASS files
  • base.scss: all our CSS styles
  • reset.scss: basic resetting CSS rules
  • app.jsx: the core of our app
  • api.jsx: the module to contact the Weather API

Step 5. Setup Gulp tasks

When talking about React, we are not only looking at the framework itself. We are also learning about the tools that will help us have a smooth and agile development experience. That's when a task runner becomes your best friend :-)
Gulp is a task runner, just like Grunt. I don't have any particular preference for Gulp, actually I am more used to working with Grunt, but for the sake of learning and trying new things, we are going to use Gulp in this tutorial.

First we are going to start by opening the gulpfile.js in the editor and requiring the dependencies:

var gulp = require('gulp');
var gutil = require('gulp-util');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var watchify = require('watchify');
var reactify = require('reactify');
var notifier = require('node-notifier');
var server = require('gulp-server-livereload');
var concat = require('gulp-concat');
var sass = require('gulp-sass');
var watch = require('gulp-watch');

As we mentioned before, we need to compile the SASS and JSX files, bundle the code and watch for changes. We also want to display formatted errors and reload the browser automatically when there's a change in the JS or SASS files.

Let's start with the error messages:

// Format error messages
var notify = function (error) {
    var message = 'In: ';
    var title = 'Error: ';

    if (error.description) {
        title += error.description;
    }
    else if (error.message) {
        title += error.message;
    }

    if (error.filename) {
        var file = error.filename.split('/');
        message += file[file.length-1];
    }

    if (error.lineNumber) {
        message += '\nOn Line: ' + error.lineNumber;
    }

    notifier.notify({title: title, message: message});
};

The module 'node-notifier' creates nice alerts (at least in Mac Os) with the error messages that occurred during the build process. With the snippet above, we are just formatting the error message in a way that could be more readable.

Next step is to create the bundle. For this part we are going to need three modules: watchify, browserify and reactify. The first one is a module to do automatic bundling of browserify-based scripts.

Browserify lets us require('modules') in the browser by bundling up all our dependencies. It looks at a single JavaScript file (in this case app.jsx), and follows the require dependency tree, and bundles them into a new file.

ReactJS uses a special syntax called JSX, not the normal JS one. Usually, when you want to work with ReactJS JSX files, you need to transform them into normal JS files. So we are going to use 'reactify' to transform those JSX into JS files.

Conclusion, we will create a Browserify bundler and add a transformer to transform JSX to Javascript and then bundle everything together into a file called main.js that will sit in the root.

// Bundle settings
var bundler = watchify(browserify({
    entries: ['./src/app.jsx'],
    transform: [reactify],
    extensions: ['.jsx'],
    debug: true,
    cache: {},
    packageCache: {},
    fullPaths: true
}));

// Bundle tasks
function bundle() {
    return bundler
        .bundle()
        .on('error', notify)
        .pipe(source('main.js'))
        .pipe(gulp.dest('./'))
}
bundler.on('update', bundle);

// Create bundle
gulp.task('build', function() {
    bundle()
});

Now we are going to process the SASS files and put them all together (in the order specified in main.scss) in a unique CSS file (style.css) that will sit in the root folder:

// Compile the SASS files from main.scss
gulp.task('sass', function () {
    gulp.src('./sass/main.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(concat('style.css'))
        .pipe(gulp.dest('./'));
});

Next stage is to setup the live reload server. This module will reload the browser automatically each time there's a change in our code. This is a really nice feature! In this case, we are going to pass a test filter to the livereload module, so that it will check our compiled CSS and JS files before reloading the browser. You can read more about the module documentation here.

// Live reload server settings
gulp.task('serve', function(done) {
    gulp.src('')
        .pipe(server({
            livereload: {
                enable: true,
                filter: function(filePath, cb) {
                if (/main.js/.test(filePath)) {
                    cb(true)
                }
                else if (/style.css/.test(filePath)) {
                    cb(true)
                }
            }
        },
        open: true
    }));
});

Finally, we are going to create the watch task for our SASS files and set the order in which all the created tasks need to be run:

// Watch for changes in the SASS files
gulp.task('watch', function () {
    gulp.watch('./sass/**/*.scss', ['sass']);
});

// Run tasks in a specific order
gulp.task('default', ['build', 'serve', 'sass', 'watch']);

At this point, if you are using Git, you should add main.js and style.css to your .gitignore file, as these files will be generated by Gulp and we don't need them in the repository.

Step 6. Create a basic markup

We are going to create a basic HTML file with:

  • A container DIV where we will attach the React component
  • The font loaded from Adobe Edge Fonts
  • The compiled CSS file
  • The weather icons CSS file
  • The compiled JS file

I personally prefer to load fonts using <link> rather than a <script> tag, but for the sake of simplicity, we will go with this method this time.

<html>
    <head>
        <script src="//use.edgefonts.net/league-gothic:n4:all.js"></script>
        <link rel="stylesheet" href="/style.css">
        <link rel="stylesheet" href="/bower_components/weather-icons/css/weather-icons.min.css">
    </head>
    <body>
        <div class="container"></div>
    </body>
    <script src="main.js"></script>
</html>

Step 7. Add the reset CSS

Just copy/paste the following code in /sass/partials/reset.scss

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit;
}

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline; }

/* HTML5 display-role reset for older browsers */

article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
  display: block; }

body {
  line-height: 1; }

ol, ul {
  list-style: none; }

blockquote, q {
  quotes: none; }

blockquote {
  &:before, &:after {
    content: '';
    content: none; } }

q {
  &:before, &:after {
    content: '';
    content: none; } }

table {
  border-collapse: collapse;
  border-spacing: 0; }

Step 8. Start building the React component

Finally we arrive to the moment where you can really start learning React! I'm sorry it took so long, but now we have everything ready and from now on it will be just pure coding :P

First we are going to open /src/app.jsx. This is where we will create our React component. We need to require some modules:

var React = require('react');
var ReactDOM = require('react-dom');
var classNames = require('classnames');
var Api = require('./utils/api');

The two first modules correspond to the React framework. Classname is a 3rd party module (recommended by React) to build class names that contain dynamic data. In JSX we cannot use '+' like in JS to concatenate strings in the class attribute. The Api object is requiring the module that we will use to fetch data from the Weather API. Notice that to load this module, we have to build the relative path, as it's not a module that we have installed with NPM.

Now we are going to define a few variables to handle the cities from the query string:

var query = ''; // Expects something like this ?city=London,Paris,Berlin,Madrid
var cities = []; // Transform query string cities into an array
var citiesWeather = []; // API cache
var currentCity = 0; // Index of current city displayed

Let's not go too deep in trying to explain what we are going to do with these variable. Their purpose will be revealed as we go along building the component.

Now we can define the new React component like this:

var Weather = React.createClass({
    render: function() {

    }
});

// Assign the React component to a DOM element
var element = React.createElement(Weather, {});
ReactDOM.render(element, document.querySelector('.container'));

We basically created a React component called 'Weather' and render it inside the 'container' DIV.

From now on, we are going to work in the methods of the object defined inside the React.createClass().

First method is getInitialState():

// Init data for UI
getInitialState: function() {
    return {
        weather: '',
        temp: 0,
        humidity: 0,
        wind: 0
    }  
},

Here, we are just initialising the props that we are going to use later to hold the values for out weather indicators in the UI.

Now we need to create the HTML structure for our weather component Let's use this simple wireframe to map each box into an HTML element:

Tutorial: build a weather app with React

Inside the render() method, add the following:

// Build class names with dynamic data
var weatherClass = classNames('wi wi-owm-' + this.state.weather);
var bgColorClass = 'weather-widget '; // very-warm, warm, normal, cold, very-cold

// Set the background colour based on the temperature
if (this.state.temp >= 30) {
    bgColorClass += 'very-warm';
}
else if (this.state.temp > 20 && this.state.temp < 30) {
    bgColorClass += 'warm';
}
else if (this.state.temp > 10 && this.state.temp < 20) {
    bgColorClass += 'normal';
}
else if (this.state.temp > 0 && this.state.temp < 10) {
    bgColorClass += 'cold';
}
else if (this.state.temp <= 0)="" {="" bgcolorclass="" +="very-cold" ;="" }="" render="" the="" dom="" elements="" return="" <div="" classname="{bgColorClass}">
    <h1 className="city">{cities[currentCity]}</h1>
    <div className="weather">
        <i className={weatherClass}></i>
    </div>
    <section className="weather-details">
        <div className="temp"><span className="temp-number">{this.state.temp}</span><span className="wi wi-degrees"></span></div>
        <div className="humidity"><i className="wi wi-raindrop"></i>{this.state.humidity} %</div>
        <div className="wind"><i className="wi wi-small-craft-advisory">{this.state.wind} <span className="vel">Km/h</span></div>
    </section>
</div>=>

Let's analyse the code step by step.

To render the big weather icon (the sun, clouds, etc), we need to get the icon ID from the Weather API. Once we have it, we can use the prefix 'wi wi-owm-' (got it from the weather icons API compatibility list) to compose the class name that we need. That's what we are doing with the weatherClass variable.

Next variable, 'bgColorClass' is composing the class name that we will use for the app wrapper background colour. The aim is to have the class 'warm' for temperatures between 20 and 30 degrees and so on. We will then assign a colour to each class later in the SASS file.

In the return statement, first thing that stands out is the use of 'className' rather than 'class'. That's how you add CSS classes in JSX templates. The class names also need to be composed using the classNames module that we required at the beginning of the file.

Then we have variables wrapped in {}, like in Handlebars. This is how we render the content of React variables, states or properties (called props). In this app, we are going to use states. If you want to know more about the difference between props and states, head to this article.

Step 9. Fetch the API data

Let's summarise. So far, we have a React component that initialises and renders its empty data. That's all. So, the next step is to fetch the API data and pass it on to the React component.

Let's open the /src/utils/api.jsx file and write the following code:

var Fetch = require('whatwg-fetch');
var rootUrl = 'http://api.openweathermap.org/data/2.5/weather?q=';
var apiUrl = '&appid=2de143494c0b295cca9337e1e96b00e0';

module.exports = {
    get: function(place) {
        return fetch(rootUrl + place + apiUrl, {
            headers: {
                // No need for special headers
            }
        })
        .then(function(response) {
            return response.json();
        });
    }
};

In this module, we are going to require 'whatwg-fetch', which is a window.fetch JavaScript polyfill. We are also going to use an API key and the API URL. I think you don't need to register to generate a new key, as this one I got it from the API docs and seems to be working fine.

The fetching code is super simple. We compose the final URL by concatenating the variables plus the city's name that we receive as a parameter and pass it to the fetch method. Then we have a 'promise' that will receive the response from the API and we just return it in JSON format.

Step 10. Connect the API module with the React component

Back in /src/app.jsx, we are going to create a new method called 'fetchData' that will try to load the data from our cache and if it cannot find it, then it will call the module we created in the previous step to get new data:

fetchData: function() {

    // Get the data from the cache if possible
    if (citiesWeather[currentCity]) {
        this.updateData();   
    }
    else {
        // Request new data to the API
        Api.get(cities[currentCity])
            .then(function(data) {
                citiesWeather[currentCity] = data;
                this.updateData();
        }.bind(this));
    }
},

The array citiesWeather is our cache object. We are going to store here the JSON responses that we get from the API. Why are we doing this? Because when we have a list of cities rotating, we don't want to keep contacting the API every time we change the city.

When we want to request new data, we just call the get method in the Api module and pass the current city name. In the 'promise', we make sure to update the cache object with the data received and we call the updateData method to set the new value in the states.

Step 11. Update the states

At this point, the React component has just received new data from the API and it's ready to update the UI with this new data. We are going to create a new method called updateData:

updateData: function() {
    // Update the data for the UI
    this.setState({
        weather: citiesWeather[currentCity].weather[0].id,
        temp: Math.round(citiesWeather[currentCity].main.temp - 273.15), // Kelvin to Celcius
        humidity: Math.round(citiesWeather[currentCity].main.humidity),
        wind: Math.round(citiesWeather[currentCity].wind.speed)
    });
},

Modifying this.props or this.state directly is not a good idea, because React will not be able to pick up on the changes. That's because React does a shallow comparison of your post prop to determine if it has changed. So always use 'setState'.

Step 12. Read the query string and create the timers

Before we start with the styling of the app, there's one more step we have to tackle. We are going to create a new method called componentWillMount(), which is called before the render method is executed:

// Called before the render method is executed
componentWillMount: function() {

    // Get the query string data
    query = location.search.split('=')[1];

    // Figure out if we need to display more than one city's weather
    if (query !== undefined) {
        cities = query.split(','); // Get an array of city names

        // Set the interval to load new cities
        if (cities.length > 1) {
            setInterval((function() {
                currentCity++;
                if (currentCity === cities.length) {
                    currentCity = 0;
                }
                this.fetchData(); // Reload the city every 5 seconds
            }).bind(this), 5000);
        }
    }
    else {
        cities[0] = 'London'; // Set London as the default city
    }

    // Create a timer to clear the cache after 5 minutes, so we can get updated data from the API
    setInterval(function() {
        citiesWeather = []; // Empty the cache
    }, (1000*60*5));

    this.fetchData();
},

There's a module called React Router that can be very useful for building single-page apps, but for the sake of simplicity, I decided not to include it. So we are going to use a very simple approach for reading the list of cities: a query string.

In the first lines of the snippet above, we are just splitting the string into an array and checking if the user entered a single city or several separated by commas. If we have several, then we create a timer that will call the fetchData() method every 5 seconds, which will update the data of the current city. Notice that we are also passing the execution context of the React component to the timer, otherwise 'this' wouldn't find the fetchData method.

In the second part of the snippet, we are creating another timer that will be in charge or clearing the cache every 5 minutes, otherwise we would only get LIVE data once (when we launch the app).

Congratulations, you arrived to the end of the Javascript part! Now let's quickly add the CSS and try to run the app.

Step 13. Add the SASS styles

Copy/paste the following code into /sass/partials/base.scss:

// Colours
$very-warm: #FF8500;
$warm: #ffc600;
$normal: #94AF10;
$cold: #06799F;
$very-cold: #233884;

// Breakpoints
$mobile-width: 500px;
@mixin mobile {
    @media (max-width: $mobile-width) {
        @content;
    }
}

// DOM Elements
.weather-widget {
    width: 100%;
    color: white;
    font-family: league-gothic, sans-serif;
    font-weight: 100;
    font-style: normal;
    padding: 5% 10%;

    @include mobile {
        padding: 2%;
    }

    &.very-warm { background-color: $very-warm; }
    &.warm { background-color: $warm; }
    &.normal { background-color: $normal; }
    &.cold { background-color: $cold; }
    &.very-cold { background-color: $very-cold; }
}

.city {
    font-size: 4em;
    text-transform: uppercase;
    letter-spacing: 2px;
    width: 100%;
    text-align: center;
}

.weather{
    display: table;
    height: 415px;
    width: 100%;
    text-align: center;
    border-bottom: 2px solid white;

    @include mobile {
        height: 350px;
    }

     .wi {
        display: table-cell;
        vertical-align: middle;
        font-size: 20em;

         @include mobile {
            font-size: 15em;
         }
    }
}

.weather-details {
    overflow: hidden;
    margin-top: 35px;
    max-width: 550px;
    margin-left: auto;
    margin-right: auto;

    .temp {
        font-size: 13.5em;
        float: left;
        width: 55%;
        max-height: 200px;

        @include mobile {
            font-size: 9em;
        }

        .temp-number, .wi {
            vertical-align: top;
            line-height: 0.85em;
        }

        .wi {
            font-size: 1.5em;
            line-height: 0.8em;
        }
    }

    .humidity, .wind {
        font-size: 5em;

        @include mobile {
            font-size: 3em;
        }

        .wi {
            vertical-align: top;
            width: 70px;

            @include mobile {
                width: 40px;
            }
        }
    }

    .humidity {
        margin-bottom: 20px;
    }

    .wind {
        .wi {
            font-size: 0.82em;
        }
        .vel {
            font-size: 0.6em;
        }
    }
}

The SASS code is quite self-explanatory. It can be improved, but for the purpose of this tutorial, which is to learn React, I think it fulfills its purpose.

Step 14. The moment of truth

Type 'gulp' in the console/terminal and cross fingers!

If it works, congratulations! if it doesn't, try to debug the error messages and find a fix. If you get stuck, then post a comment here and I will try to help you.

This was my first React app and I'm excited to continue learning about Flux, Reflux, the router, etc. So, please, send me your suggestions or let me know if the app could be improved in any way. Thanks and I hope you enjoyed it! :-)

How to create a portfolio in ghost

$
0
0
How to create a portfolio in ghost

I've been a Wordpress developer for quite some time, but at some point, I got tired of the massive attention that it was getting from hackers. I also started to feel tired of the old LAMP stack and wanted to have a fresh start with relevant technologies like Node.js, Nginx, Ember.js, etc. That's how I switched all my personal websites to Ghost.

I've been using the fantastic Ghost platform to run this website since almost a year ago and so far, it has been a great experience. In this article, I'm going to explain how I built the /work section of this website. In a way, it's a bit of a hack, considering that Ghost doesn't have yet a clear way to create pages of a specific type or have custom post fields that we can read in the templates (like in Wordpress).

To make this work, we are going to use:

  • The tag system: to categorise our portolio works
  • A new page-work.hbs template: to display the portfolio grid and navigation
  • The page.hbs template: to create the HTML structure of the portfolio pages
  • The new {{#get}} helper: to search for portfolio entries among all our Ghost posts
  • The Isotope library: to create the interactive animated responsive masonry layout

You can read more about the mentioned Ghost features in the documentation. Notice that the {{get}} helper is still in beta.

The way it works is very simple, we are going to use normal Ghost tags (like web, mobile, video, design, etc) to categorise our portfolio items and we will also use the 'work' tag to identify the pages that need to be treated as portfolio pages.

This approach has at least one limitation:

If we are going to use the page.hbs template for the portfolio entries, that means we cannot create new pages on the fly because that template is used by default for every new page we create. For the rest of static pages of our site, we will have to use specific new templates. For example, the about page will require a new template called page-about.hbs, the contact page will require a new template called page-contact.hbs, etc. Which means, this approach is more appropriated for small sites that don't have many static pages and the new content is usually going to be either a blog post or a new portfolio entry.

Step 1. Create a new HTML template to display the portfolio grid

First we are going to create a new template. I called it page-work.hbs (because my URL is /work), but you can call it whatever you prefer, ie. page-portfolio, page-projects, etc. In this template, we are going to have:

  • Some intro copy (entered with the markdown editor)
  • The portfolio main navigation
  • The grid with the portfolio items

And this is the code we will use:

<section>
    {{#post}}
        {{content}}
    {{/post}}
</section>

<main>
    <div class="work-navigation">
        <div id="filters" class="button-group">
            <button class="btn is-checked" data-filter="*">ALL</button>
            <button class="btn" data-filter=".web">WEB</button>
            <button class="btn" data-filter=".desktop">DESKTOP</button>
            <button class="btn" data-filter=".mobile">MOBILE</button>
            <button class="btn" data-filter=".prototype">PROTOTYPE</button>
            <button class="btn" data-filter=".installation">INSTALLATION</button>
            <button class="btn" data-filter=".open-source">OPEN SOURCE</button>
            <button class="btn" data-filter=".consultancy">CONSULTANCY</button>
            <button class="btn" data-filter=".design">DESIGN</button>
            <button class="btn" data-filter=".ux">UX</button>
            <button class="btn" data-filter=".video">VIDEO</button>
            <button class="btn" data-filter=".photo">PHOTO</button>
        </div>
    </div>

    <div class="work-grid clearfix">
        <div class="grid-sizer"></div>
        {{#get "posts" limit="all" include="tags" filter="tag:work+page:true"}}
            {{#foreach posts}}
                <a href="/{{slug}}" class="{{tags separator=" " autolink="false"}}">
                    <div class="work-thumb"></div>
                    <h2 class="name">{{title}}</h2>
                    <p class="meta">{{date published_at format="YYYY"}}</span><span class="country">{{#has tag="uk"}}UK{{/has}}{{#has tag="spain"}}Spain{{/has}}{{#has tag="multiple-regions"}}Multiple regions{{/has}}</span></p>
                </a>
            {{/foreach}}
        {{/get}}
    </div>
</main>

The first part of the code will render the content that we enter in the markdown editor. Then we define the portfolio navigation buttons, each one of them has a filter attribute with a class name. When clicked, the isotope library will display only the portfolio entries that have the class name specified in the filter attribute of the button.

Finally, in the work-grid block, we are going to use the {{get}} helper to get a collection of posts that have the tag 'work' and are marked as 'page'. That will skip all the normal blog posts and all the pages that don't have the 'work' tag.

Then we are going to loop through the collection (using {{#foreach}} and render a anchor tag with the metadata of each post in the collection. Notice that to render the post tags, we use the helper {{tags}} inside the class attribute of the anchor tag. That is the key point of this approach.

The content inside the anchor tag is not enforced. You can style it however you prefer. I'm just rendering the post date and a country string or another depending on the post tags.

Step 2. Setup the isotope configuration

Now that our markup is ready, we need to download the Isotope library and load it in our page. There are many different ways to do this, depending on what type of task manager you are using, if you are bundling and minifying the code and how your Ghost theme is structured. So I will leave that for you. The only thing to bear in mind is that we need the library to be loaded in the page!

Once we are sure that the library is loading, we need to set it up. Once again, the place where you should put the following code, depends on how your theme is structured, but you should have a Javascript file somewhere in your theme that you can use:

// init Isotope
var $grid = $('.work-grid').isotope({
    itemSelector: '.work',
    percentPosition: true,
    masonry: {
        columnWidth: '.grid-sizer'
    }
});

// bind filter button click
$('#filters').on('click', 'button', function() {
    var filterValue = $(this).attr('data-filter');
    $grid.isotope({ filter: filterValue });
});

// change is-checked class on buttons
$('.button-group').each( function(i, buttonGroup) {
    var $buttonGroup = $(buttonGroup);
    $buttonGroup.on('click', 'button', function() {
        $buttonGroup.find('.is-checked').removeClass('is-checked');
        $(this).addClass('is-checked');
    });
});

In the first part of the code, we are just attaching Isotope to the work-grid block defined in our HTML template. Then we are telling Isotope that our portfolio thumbnails will have the class name 'work'. The rest of the settings are the ones indicated by the Isotope documentation to make the grid responsive.

The next bit takes care of the navigation click events. It basically tells Isotope to rearrange the items in the grid based on the selected filter.

Finally, the last snippet updates the 'checked' class names in the navigation buttons when they are clicked. Notice that we are targeting the buttons inside the 'button-group' blocks. That's because you might decide to have different sets of navigations, one for filtering and another one for sorting. You can find out about how to sort items in the Isotope library documentation.

Step 3. Create new entries

The next step is to create a few new entries in your Ghost admin panel and prepare them to be portfolio entries. Remember that all you have to do is to check the option 'Turn this post into a static page' and assign at least the 'work' tag.

Step 4. Decide what to do with the post images

Regarding the thumbnail images that will be used in the Isotope grid, there are at least a couple of options.

The first one (which I didn't use) would be to add a post image using the post sidebar settings in the admin panel. Then you would retrieve that image during the {{foreach}} loop in the 'page-work.hbs' template and render it as an How to create a portfolio in ghost or as a CSS background-image. This option is the best if you only need one image for the thumbnails, no background colours or other stuff and you are not going to use the post image in the portfolio entry page (page.hbs).

The other option would be more time-consuming (in terms of maintenance) but more flexible in terms of presentation. I chose this option because I wanted to have specific CSS for every single thumbnail in my portfolio grid. That means, every time I want to add a new item to my portfolio, I have to manually update my CSS with the project logo. Why did I complicated my life in such way? Just because I wanted to have nice roll-over animations with background changing colours and keep the post image for the page.hbs template :-)

So, if you just want to display normal project thumbnails as images, I would go with the first option. This way you could add new portfolio items directly from the admin panel without the need to touch a line of code!

Step 5. Modify the page.hbs template

We are going to use this template as the base for every new portfolio page:

{{#post}}

    {{#if image}}
        <section class="hero" style="background-image: url({{image}})"></section>
    {{/if}}

    <main class="content {{#if image}}{{else}}no-hero{{/if}}>
        <article class="{{post_class}}">
            <h1 class="post-title">{{{title}}}{{#if tags}}<time datetime="{{date format="YYYY-MM-DD"}}">{{date format='YYYY'}}</time>{{/if}}</h1>
            <section class="post-content">
                {{content}}
            </section>
        </article>
    </main>

{{/post}}

Depending on which route you decided to take in the previous step and if you want to display the post image at the top of the portfolio entry page, you would need the first condition or not.

The rest of the code is just setting a basic HTML structure to render the content of the portfolio entry.

Step 6. Set the basic styles for the grid

In your CSS, add the following styles. I'm not including all the parts that relate only to my specific website, like the hover animations, background images, etc, but if you are interested, let me know in a comment and I will add them:

.work-grid {
    .grid-sizer,
    .work {
        width: 16.67%;

        @media screen and (max-width: 1500px) {
            width: 20%;
        }

        @media screen and (max-width: 1200px) {
            width: 25%;
        }

        @media screen and (max-width: 900px) {
            width: 33.34%;
        }

        @media screen and (max-width: 700px) {
            width: 50%;
        }

        @media screen and (max-width: 380px) {
            width: 100%;
        }
    }

    .work {
        position: relative;
        box-sizing: border-box;
        float: left;
        height: 200px;
        overflow: hidden;

        .work-thumb {
            position: absolute;
            height: 100%;
            width: 100%;
            background-repeat: no-repeat;
            background-position: center;
        }

        .name, .meta {
            opacity: 0;
            position: relative;
            color: white;
        }

        .name {
            padding-left: 40px;
            padding-right: 40px;
            font-size: 1.5em;
            white-space: pre-wrap;
            overflow: hidden;
            text-overflow: ellipsis;
            max-height: 60px;

            @media screen and (max-width: 700px) {
                font-size: 1.2em;
                max-height: 70px;
            }
        }

        .meta {
            .date {
                margin-right: 5px;
            }
        }

        /* If you decided to go with option 2 in the previous step,
           you will need to manually link your portfolio thumbnail CSS
           by adding a tag with the name of the project */
        &.project-name {
            background-color: #c60c30; // this is optional
            .work-thumb {
                background-image: url(/assets/work/project-name/logo.png);
            }
        }
    }
}

Step 7. Ready to go!

At this point, you should be ready to start adding your portfolio entries, content and images. If you find something missing in my code or there's anything that doesn't make much sense, let me know in a comment and I will refine it.

Good luck! and keep blogging with Ghost ;-)

Javascript: understanding the weird parts [Part 2]

$
0
0
Javascript: understanding the weird parts [Part 2]

In the previous part of this article, we learned about execution contexts, types and operators, functions, etc. In this part, we are going to learn more about object oriented programming with Javascript.

Lecture 53: Classical vs prototypal inheritance

Inheritance: one object gets access to the properties and methods of another object.

Classical inheritance: (most popular) is in C++, Java, etc. It's very verbose. We can end up with a massive tree of objects and relationships. Many keywords: friend, protected, private, interface,...

Prototypal inheritance: simple. Extensible. Easy to understand.

Lecture 54: Understanding the prototype

All objects have a "special property" called the proto {} property. That's the prototype of the object. It can also have its own properties. When we request a property of an object, JS first looks into the object itself to find that property, if it cannot find it, then it looks for the property inside the prototype.

That prototype can also contain another prototype object and JS will always go down the chain. That's called the prototype chain.

If we have an object2, it can also point at the same prototype of object1. Objects can share all the same prototype.

Javascript: understanding the weird parts [Part 2]

Example:

var person = {
    firstname: 'Default',
    lastname: 'Default',
    getFullName: function() {
        return this.firstname + ' ' + this.lastname;
    }
}

var john = {
    firstname = 'John'.
    lastname: 'Doe'
}

// Don't do this EVER! for demo purposes only!!!
// This is a browser way to access the prototype but with very bad performance
john.__proto__ = person;
console.log(john.getFullName());
console.log(john.firstname); // It returns John's name, not Person's name because of the prototype chain priority.

Lecture 55: Everything is an object (or a primitive)

var a = {};
var b = function() {};
c = [];

console.log(a.__proto__); // returns the base object and we can access toString, etc

console.log(b.__proto__); // returns function Empty() {} and we can access apply, call, bind,...

console.log(c.__proto__); // returns push, pop, indexOf, length, etc

console.log(c.__proto__.__proto__); // that returns the base object

Everything leads to the base object. That's the bottom of the prototype chain.

Lecture 56: Reflection and extend

Reflection: an object can look at itself, listing and changing its properties and methods. We can use that to implement the extend pattern. Let's look at how reflection works:

var person = {
    firstname: 'Default',
    lastname: 'Default',
    getFullName: function() {
        return this.firstname + ' ' + this.lastname;
    }
}

var john = {
    firstname = 'John'.
    lastname: 'Doe'
}

// loop through every member in the john object
for (var prop in john) {
    console.log(prop + ': ' + john[prop]);
}

// The previous code will also output getFullName and the function. To avoid that we do:

for (var prop in john) {
    // it will only list it if it's on john's object
    if (john.hasOwnProperty(prop)) {
        console.log(prop + ': ' + john[prop]);
    }
}
Conceptual aside: look at the "_extend" method in the Underscore library. Analyse the 'createAssigner' method to understand how reflection is used. It basically uses two loops to assign the properties and methods of the objects passed as parameters to the first object passed as a parameter. Extend is used in many libraries and frameworks. We could pull that method from Underscore and use it in our own library/project. In ES6, we have also 'extends', but that's used for a different functionality. ###Lecture 57: Building objects Function constructors, 'new' and the history of Javascript. It was called Javascript to attract Java developers. The same way, Microsoft created VBScript to attract their own developers. So, Java developers were used to create objects like this:
var john = new Person();
Although, ES6 will introduce the class keyword, Javascript doesn't really have classes. So, Java developers thought Javascript was like Java and they recommended it.
function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

var john = new Person('John', 'Doe;);
console.log(john);

var jane = new Person('Jane', 'Doe;);
console.log(jane);
'new' immediately creates an empty object. Then it calls the function. Then 'this' will point to that empty object. So, the function becomes the constructor of that object. ###Lecture 58: Function constructors and '.prototype' Functions have special properties, aside from name, code, etc, they also have a prototype property, which starts its life as an empty object and it's ONLY used by the new operator.
function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

Person.prototype.getFullName = function() {
    return this.firstname + ' ' + this.lastname;
}

var john = new Person('John', 'Doe;);
console.log(john);

var jane = new Person('Jane', 'Doe;);
console.log(jane);
Person.prototype.getFormalFullName = function() { return this.lastname + ', ' + this.firstname; } console.log(john.getFormalFullName()); So, we can add features to all those objects that we create by using the prototype. In good code, the methods of an object are set with prototype. Why? Because if we add getFullName to every object, it means they are using a lot of memory. If we add it to the prototype, we only have it once. We just use one copy for all the instances of the object. We are saving memory space, because there's only one prototype for all the objects. ###Lecture 59: Dangerous aside, using 'new' and functions If we forget to use 'new', the function constructor will return undefind. It's a good practice to use capital letters for constructors. In that way, if we see the new keyword is missing, we will notice it's wrong. In ES6, function constructors are likely going away. ###Lecture 60: Built-in function constructors
var a = new Number(3);
That creates an object of the type Number with some special methods. We can use a.toFixed();
var a = new String('John');
Same thing and we can use a.indexOf('o'); We can also do "John".length They both store the value in a property called 'PrimitiveValue'. So they are not primitives, they are objects with special methods. In the same way, we can do the same for dates:
var a = new Date('10/12/2010');
We can also do things like:
String.prototype.isLengthGreaterThan = function(limit) {
   return this.legth > limit;
}
console.log('John'.isLengthGreaterThan(3));

String is an object and we are adding a method to the prototype. We just enhanced the JS language just like that! We have to be careful not to overwrite an existing method.

Number.prototype.isPositive = function() {
    return this > 0;
}

console.log(3.isPositive()); // Returns error
Javascript doesn't return a number into an object, so we have to do:
var a = new Number(3);
a.isPositive();
So, it's a good feature, but it gets a bit confusing, because not everything works the same way. ###Lecture 61: Dangerous aside. Built-in function constructors
var a = 3;
var b = new Number(3);

a == b // returns true because of coercion
a === b // returns false
So, as you can see, that's not a very recommended situation. It's better not to use new to create primitives. The same way, if we are going to work a lot with dates, it is recommended to use the library [Moment.js](http://momentjs.com). ###Lecture 62: Dangerous aside. Arrays and for..in
Array.prototype.myCustomFeature = 'cool!';

var arr = ['John', 'Jane', 'Bob'];
for (item in arr) {
    console.log(item + ': ' + arr[item]);
}
// That will render also myCustomFeature

So, in the case of arrays, don't use for..in. Use the for..i classic loop.

Lecture 63: Object.create and pure prototypal inheritance

This is a new feature for new browsers. If we need to support older browser, we use a polyfill, which is code that adds a feature which the engine may lack.

var person = {
    firstname = 'Default',
    lastname = 'Default',
    greet = function() {
        return 'Hi' + this.firstname;
    }
}

var john = Object.create(person);
console.log(john);
That creates an empty object with a prototype with all the methods indicated above. So, if we want to override those default values, we can do:
john.firstname = 'John';
john.lastname = 'Doe';
So, the big advantage of prototype vs classic inheritance, is that we can add new methods on the fly and mutate things easily, without complex layers and interactions. ###Lecture 64: ES6 and classes
class Person {
    constructor(firstname, lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    greet() {
        return 'Hi ' + firstname;
    }
}

var john = new Person('John', 'Doe');
That is an OBJECT. To set the prototype, we do it like this:
class InformalPerson extends Person {
    constructor(firstname, lastname) {
        super(firstname, lastname);
    }

    greet() {
        return 'Yo ' + firstname;
    }
}
Syntactic sugar: a different way to type something that doesn't change how it works under the hood. ###Lecture 65: Odds and ends. Initialisation Just talking about common syntax errors when creating big literal objects with arrays and functions. Nothing to highlight here. ###Lecture 66: Odds and ends. Typeof, intanceof and figuring out what something is We can use typeof to figure out the type of primitive or object we are dealing with, but in the case of arrays, we have to use something like this:
var d = [];
console.log(Object.prototype.toString.call(d));
That would output [Object Array] In the case of objects:
function Person(name) {
    this.name = name;
}
var e = new Person('Jane');

With instanceof Person, we are looking for an object of the type Person down the prototype chain.

There's a very known bug. If you type typeof null, it returns an object.

And typeof functionName returns function.

Lecture 67: Odds and ends. Strict mode

This tells the JS engine to process the code in a stricter way. For example, in the following case, we mistyped the variable but without the strict mode, it will not throw an error.

var person;

persom = {};
console.log(persom);
If we put "use strict"; at the beginning, it will throw an error because we are forced to declare a variable in order to use it. For more info, check [the strict mode reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode). ###Lecture 69: Learning from other's good code An open source education. Github.com contains a great collection of source code where we can learn. So, it's a good practice to occasionally take a look at some of the methods of the libraries we use. ###Lectures 70-72: Deep dive into famous source code. jQuery These lectures are quite dense in terms of code reviewing, so I will skip commenting about them. You are more than welcome to download the unminified version of jQuery and dive into the code to try to understand how the library it's initialised (without the need of using 'new') and how all the methods are stored in the prototype of fn. I just like to mention the **method chaining**, which is a very useful way of chaining calls to methods. If you use jQuery, then very probably you already know about this. Like when you add a class and remove another class in the same line:
$('.selector').addClass('a').removeClass('b');
To achieve that, we only have to 'return this;' in the methods we are calling. ###Lectures 73: Let's build a a framework / library. Requirements * We are going to call it 'Greetr', an app to greet users * When given a first name, last name and optional languages, it generates formal and informal greetings * Support English and Spanish languages * Reusable library / framework * Easy to type 'G$()' structure * Support jQuery ###Lectures 74: Let's build a a framework / library. Structuring safe code First, create a file called Greetr.js. First we are going to create a new execution context with a self-invoking function.
(function(global, $) {

}(window, jQuery))

Lectures 75: Let's build a a framework / library. Our object and its prototype

Create a file called app.js. We are going to imitate jQuery structure. So we don't want to use 'new', we want to use G$() like in jQuery and get an object as a result:

var g = G$('John', 'Doe');

Then, in Greetr.js:

(function(global, $) {

    var Greetr = function(firstName, lastName, language) {
    return new Greetr.init(firstName, lastName, language);

    Greetr.prototype = {};

    Greetr.init = function(firstName, lastName, language) {
        var self = this;
        self.firstName = firstName || '';
        self.lastName = lastName || '';
        self.language = language || 'en';
    }

    Greetr.init.prototype = Greetr.prototype;

    global.Greetr = global.G$ = Greetr;
}

}(window, jQuery))

Lectures 76: Let's build a a framework / library. Properties and chainable methods

Now we are just going to create methods in the prototype and return this in some of them to make then chainable.

(function(global, $) {

    var Greetr = function(firstName, lastName, language) {
    return new Greetr.init(firstName, lastName, language);

    var supportedLangs = ['en', 'es'];

    var greetings = {
        en: 'Hello',
        es: 'Hola'
    };

    var formalGreetings = {
        en: 'Greetings',
        es: 'Saludos'
    };

    var logMessages = {
        en: 'Logged in',
        es: 'Inició sesión'
    }

    Greetr.prototype = {

        fullName: function() {
            return this.firstName + ' ' + this.lastName;
        },

        validate: function() {
            if (supportedLangs.indexOf(this.language) === -1) {
                throw "Invalid language";
            }
        },

        greeting: function() {
            return greetings[this.language] + ' ' + this.firstName + '!';
        },

        formalGreeting: function() {
            return formalGreetings[this.language] + ', ' + this.fullName();
        },

        greet: function(formal) {
            var msg;

            if (formal) msg this.formalGreeting();
            else msg = this.greeting();

            if (console) console.log(msg);
            return this;
        },

        log: function() {
            if (console) {
                console.log(logMessages[this.language] + ': ' + this.fullName();
            }
            return this;
        },

        setLang: function(lang) {
            this.language = lang;
            this.validate();
            return this;
        }
    };

    Greetr.init = function(firstName, lastName, language) {
        var self = this;
        self.firstName = firstName || '';
        self.lastName = lastName || '';
        self.language = language || 'en';
        self.validate();
    }

    Greetr.init.prototype = Greetr.prototype;

    global.Greetr = global.G$ = Greetr;
}

}(window, jQuery))

so now we can call it like this:

var g = G$('John', 'Doe');
g.greet().setLang('es').greet(true);

Lectures 77: Let's build a a framework / library. Adding jQuery support

Imagine we have an HTML form for login users. We just need a dropdown with the two languages supported and a login button. We also need an H1 with the id greeting.

Now we are going to add a method that accepts a jQuery selector and updates whatever the selector is.

To do this, we just need to add the following method in the prototype:

    HTMLGreeting: function(selector) {
        if (!$) throw 'jQuery not loaded';

        if (!selector) throw 'Missing jQuery selector';

        var msg;
        if (formal) msg this.formalGreeting();
        else msg = this.greeting();

        $(selector).html(msg);
        return this;
    }

Lectures 78: Let's build a a framework / library. Good commenting

This is specially important in JS because is not very verbose and we could make things very slick but not easy to read.

It's also good to get other developers to check your code and see if it's readable.

Lectures 79: Let's build a a framework / library. Let's use our framework

Sometimes libraries also use a semi-colon before the self-invoked function as a sanity check (just in case another library wasn't closed properly).

The rest of the lecture is just about connecting the HTML form with the library, which is not particularly adding much value, so I will skip it.

Lecture 81: Typescript, ES6 and transpiled languages

Transpile: convert the syntax of one programming language to another. In this case languages don't really ever run anywhere, but instead are processed by 'transpilers' that generate Javascript.

Typescript by Microsoft is quite popular. It provides types for variables! i.e. message: string. It also uses class and constructors.

Traceur by Google is also another popular ES6 library.

A lot of teams with long term Javascript projects are using these tools, so that they can write ES6 code (future proof) and at the same time be compatible with the current browsers.

As a personal opinion, I've heard of BabelJs more than any of the previous libraries. Some people recommend Babel over Traceur if support for JSX is a requirement or if the resulting code quality is also important to you over function.

Lectures 83: EcmaScript 6.0. Existing and upcoming features

This is probably the best resource out there to learn about the ES6 features: https://github.com/lukehoban/es6features

And that's all. Here is the certificate that you will get if you make the course in Udemy:

Javascript: understanding the weird parts [Part 2]

Build a social website aggregator using Meteor

$
0
0
Build a social website aggregator using Meteor

Launch Demo App Source code

This tutorial is the result of my final assignment for the Introduction to Meteor.js Development course by Dr Matthew Yee-King (University of London & Goldsmiths) at Coursera. This course is part of a Responsive Website Development and Design specialisation that covers the basics of modern full stack web development, from UX design, to front-end coding, to custom databases.

In that course, I learned how to create a complete, multi-user web site using the Meteor.js framework and MongoDB. It's divided in four weeks and has a couple of assignments and several quizzes. All and all, it was a very good introduction to the framework and I hope this tutorial will show everything I learned.

Requirements

The purpose of the application is to allow users to share, discuss and rate pages they find on the internet. The app also needs to have the following features:

  • Use Bootstrap
  • Users can register and login
  • Users can post new websites if they are logged in. Websites posted by users should have a URL and a description
  • Users can up and down vote webpages by clicking a plus or a minus button.
  • Websites should be listed with the most up voted site first
  • The listing page shows when the website was added and how many up and down votes it has
  • Users can move to a detail page for a website (using routing)
  • On the detail page, users can post comments about a webpage, and they are displayed below the description of the webpage
  • Use the HTTP package for Meteor to pull in information about the posted web links automatically, so the user does not need to enter anything other than the URL
  • Implement a search function that allows the user to search within the listed sites for keywords
  • Recommend websites to users based on things they have up voted and commented on. E.g. if I up vote a site entitled ‘Tofu recipes’, it would recommend other sites with ‘tofu’ and ‘recipe’ in their titles or descriptions
  • Deploy the application using the Meteor deploy command

Part 1. Installing Meteor and creating the app

Go to meteor.com and follow the instructions to install Meteor in your OS.

To create the app, open your terminal, go to the folder where you want to save the app and type:

meteor create siteace

This will create a new folder called siteace (the name of the app we are building) with all of the files that a Meteor app needs:

  • siteace.js: a JavaScript file loaded on both client and server
  • siteace.html: an HTML file that defines view templates
  • siteace.css: a CSS file to define your app's styles
  • .meteor: internal Meteor files (hidden folder)

To run the newly created app:

cd siteace
meteor

Open your web browser and go to http://localhost:3000 to see the app running. If that's working, then you can stop it by pressing Ctrl+C.

Part 2. Organising the folder structure

Meteor is a client and server framework, which means we have code for the front-end and code for the back-end. Both use Javascript. The back-end code console logs are rendered in the operating system terminal/console and the front-end console logs are rendered in the browser's console.

One way of deciding which code is going to run in the front-end or the back-end is to use the following conditional statements:

if (Meteor.isClient) {
}
if (Meteor.isServer) {
}

That is fine for very small apps, but there's a better way of dividing the code using folders:

  • /server: put all the Javascript files with code that need to be run on the server here
  • /client: put all the Javascript files with code that need to be run on the client here
  • /lib: all the Javascript files that have shared code and need to be run before anything else
  • /public: all the public assets, like images, sounds, JSON, etc

So, let's go ahead and create those folders in our app.

Now rename siteace.js to main.js, siteace.css to style.css, siteace.html to index.html and place them inside the client folder.

Then we are going to create a file called collections.js and place it in the lib folder. That file will hold the definition of the Mongo collections for our DB.

Finally, create a file called startup.js and place it in the server folder. We will use this file to initialise the DB with some dummy data when the app starts.

Once we run meteor again in the console, it will take care of the minification of the files

Part 3. Routing and defining the markup and templates

Meteor uses Blaze and Spacebars (a modified version of Handlebars) to produce reactive Meteor templates when compiled. Wait a minute... reactive? Yes, Meteor does update the interface automatically whenever there's a change in the data bound to that UI. At this point you might be thinking: is that like Facebook's React? In a way yes. Should I use React instead? Probably yes, but that's a topic you might want to read more about here.

For the sake of simplicity, we are going to stick with Meteor's default front-end tools: Blaze and Spacebars.

First let's start by installing the router. Type the following in the terminal:

meteor add iron:router

Now we are going to define the application layout (the main placeholders) and the nav bar template. We use 'yield' to define the placeholder where later we will render the chosen templates in the routes. Open index.html and add the following:

<head>
  <title>Site Ace by Joan Mira
</head>

<body>
</body>

<template name="ApplicationLayout">
    {{> yield "navbar"}}
    <div class="container">
        {{> yield "form"}}
        {{> yield "main"}}
    </div>
</template>

<!-- template that displays the header with the nav bar -->
<template name="navbar">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">Site Ace, a social website aggregator by Joan Mira
        </div>
          {{> loginButtons align="right"}}
      </div>
    </nav>
</template> 

Now we are also adding three more templates, website_form, website_list and website_item. The first one will render a form to allow the user to submit new URLs to the app. The second one will render a list of websites already in the DB and the third one is a partial to render an individual list item in the list of websites:

<template name="website_form">
    <a class="btn btn-default toggle-website-form js-toggle-website-form" href="#">
          <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
    </a>
    <div id="website_form" class="hidden_div">
        <form class="js-save-website-form">
          <div class="form-group">
            <label for="url">Site address</label>
            <input type="text" class="form-control" id="url" placeholder="http://www.mysite.com">
          </div>
          <button type="submit" class="btn btn-default">Submit</button>
        </form>
    </div>
</template>

<!-- template that displays several website items -->
<template name="website_list">
    <ol>
    {{#each websites}}
    {{>website_item}}
    {{/each}}
    </ol>
</template>

<!-- template that displays individual website entries -->
<template name="website_item">
<li>
    <a href="{{_id}}">{{title}}
    <p>
        {{description}}
    </p>
    <a href="#" class="btn btn-default js-upvote">
        <span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
    </a>
    <a href="#" class="btn btn-default js-downvote">
        <span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>
    </a>
    <!-- you will be putting your up and down vote buttons in here! -->
</li>
</template>

Notice that instead of url, we used _id to compose the URL of the website link. That will be useful later when we are creating the detail page...

Now we are going to define the Router configuration and the homepage/default route. Open main.js and add the following at the top:

Router.configure({
    layoutTemplate: 'ApplicationLayout'
});

Router.route('/', function () {
    this.render('navbar', {
        to: 'navbar' // The name of the main placeholder in applicationLayout
    });
    this.render('website_form', {
        to: 'form'
    });
    this.render('website_list', {
        to: 'main'
    });
});

Part 4. Define the collection and the initial data

Open collections.js and create a new one by typing:

Websites = new Mongo.Collection("websites");

Now open startup.js and set some dummy data:

// start up function that creates entries in the Websites databases.
Meteor.startup(function () {
    // code to run on server at startup
    if (!Websites.findOne()){
        console.log("No websites yet. Creating starter data.");
          Websites.insert({
            title:"Goldsmiths Computing Department", 
            url:"http://www.gold.ac.uk/computing/", 
            description:"This is where this course was developed.", 
            createdOn:new Date()
        });
         Websites.insert({
            title:"University of London", 
            url:"http://www.londoninternational.ac.uk/courses/undergraduate/goldsmiths/bsc-creative-computing-bsc-diploma-work-entry-route", 
            description:"University of London International Programme.", 
            createdOn:new Date()
        });
         Websites.insert({
            title:"Coursera", 
            url:"http://www.coursera.org", 
            description:"Universal access to the world’s best education.", 
            createdOn:new Date()
        });
        Websites.insert({
            title:"Google", 
            url:"http://www.google.com", 
            description:"Popular search engine.", 
            createdOn:new Date()
        });
    }
});

Part 5. Add some CSS

The form to submit new URLs that we specified in the markup is hidden by default. It only opens when the user clicks in the '+' button. To make this form hidden, we just have to add the following CSS:

.hidden_div {
    display: none;
}

ol {
    padding: 0;
    list-style-type: none;
    counter-reset: section;
}

ol li,
.info {
    counter-increment: section;
    border: 1px solid #CCC;
    border-radius: 5px;
    margin-bottom: 20px;
    padding: 10px;
    background-color: #F8F8F8;
}

ol li::before {
    content: counter(section);
    margin-right: 5px;
    font-size: 80%;
    background-color: #3388BB;
    color: white;
    font-weight: bold;
    padding: 3px 8px;
    border-radius: 3px;
}

.info {
    background-color: #3388BB;
    color: white;
    text-align: center;
}
.info a {
    color: white;
    text-decoration: underline;
}

.website-meta {
    float: right;
    line-height: 35px;
}

.website-meta span {
    font-weight: bold;
}

.comment-meta {
    text-align: right;
    margin: 5px 0 0 0;
}

.toggle-website-form,
#website_form,
.info {
    margin-bottom: 10px;
}

#login-buttons {
    float: right;
    margin-top: 15px;
}

#url {
    float: left;
    width: 50%;
    margin-right: 5px;
}

#search {
    float: right;
    max-width: 150px;
}

Part 6. Add basic events

In order to show/hide the form, we are going to need to capture the click event. Open the main.js file and add the following:

Template.website_form.events({
    "click .js-toggle-website-form":function(event){
        $("#website_form").toggle('slow');
    }
)};

Here we are just targeting the click event of the .js-toggle-website-form element and toggling its visible state.

At this point, the app should look similar to this (probably a bit better ;-)

Build a social website aggregator using Meteor

Part 7. Add new URLs to the DB

Before we start coding, we are going to need a Meteor package called HTTP to retrieve the title and description from the website we are adding. You can read more about the package here. Type the following in the terminal to install it:

meteor add http

Due to CORS restrictions, we need to contact the website from the server. So open the startup.js file and create a new method (inside the startup method) to get the title and description from the URL:

Meteor.methods({

        getWebsiteData: function (url) {
            this.unblock();
            return Meteor.http.call("GET", url, {"npmRequestOptions" : {"gzip" : true}});
        }
    });

The GZIP option is to decompress the data in case the server returns it compressed.

No we have to call that method from the front-end when the user submits the form. Open main.js and in the same function we were working in the previous part, add the following event to capture the form submit:

    "submit .js-save-website-form":function(event){

        // here is an example of how to get the url out of the form:
        var url = event.target.url.value;
        console.log("The url they entered is: "+url);

        //  put your website saving code in here!    
        Meteor.call("getWebsiteData", url, function(error, results) {

            // Dump the markup into a dummy element for jQuery manipulation
            var el = $('
'); el.html(results.content); // Get the meta data var title = $('title', el).text(); var description = $('meta[name="description"]', el).attr('content'); // Add the new website in the Websites collection Websites.insert({ title: title, url: url, description: description, createdOn:new Date() }) }); return false; // stop the form submit from reloading the page }

You can try to add a few URLs and then reload the page. They new ones should remain there. If you want to reset the DB, just type in the terminal meteor reset.

Part 8. User authentication

There two Meteor packages that take care of user registration and authentication. To install them type this in the terminal:

meteor add accounts-ui accounts-password

And then add the following partial to the navbar (beside the Site Ace title):

{{> loginButtons }}

By default, the only enabled fields for user registration are the email and password. If we also want to have a username field, we have to specify it in the package config. Open main.js and add the following at the top:

Accounts.ui.config({
    passwordSignupFields: "USERNAME_AND_EMAIL"
});

Also, from now on, if we need to check if the user is logged in or we want to access its data, we can do it like this:

if (Meteor.user()) {
    Meteor.user().username;
}

Part 9. Allow only logged in users to post new websites

We could do it by hiding the form for not logged in users, but then this could be easily hacked by manipulating the DOM from the console. So we are going to use a form validation task instead. Open main.js and wrap everything inside the submit form event with the approach we specified in the previous part. Also add an else condition and display an alert window with an error message if the user is not logged in:

"submit .js-save-website-form":function(event){

    if (Meteor.user()) {
        (...)
    }
    else {
        alert('You need to be logged in to submit websites!');
    }

    return false;
}

Part 10. Display the date and add votes

In the listing page, we are going to display the date the website was added. We need to install a new package called Moments.js, a popular library to work with dates in Javascript:

meteor add momentjs:moment

We also need to create a new template function to parse the date. In this case, we are going to make it global, so other templates can use it as well. Open main.js and add this:

// format the date
Template.registerHelper('formattedDate', function() {
     return moment(this.createdOn).format("MM/DD/YYYY");  // or whatever format you prefer
});

Then, in index.html add a placeholder for the date and the votes right after the voting buttons:

<p class="website-meta">{{formattedDate}} | <span class="js-votes-up">{{up}}</span>↑, <span class="js-votes-down">{{down}}</span>↓

We also have to initialise the up and down fields for each website entry in the DB. Open startup.js and refactor the initial items like this. Do it as well in the form submit event in main.js!:

Websites.insert({
    title:"Coursera", 
    url:"http://www.coursera.org", 
    description:"Universal access to the world’s best education.", 
    createdOn:new Date(),
    user: "Anonymous", // Use Meteor.user().username in main.js
    up: 0,
    down: 0
});

Finally, we have to save the votes in the DB. To do it, we have to use the 'update' method of the Websites collection. In this case, we are going to define the events for the parent template 'ApplicationLayout'. We do it like this to be able to use these events later in the detail page. Open main.js and add the following:

Template.ApplicationLayout.events({
    "click .js-upvote":function(event){
        // example of how you can access the id for the website in the database
        // (this is the data context for the template)
        var website_id = this._id;
        console.log("Up voting website with id "+website_id);

        // put the code in here to add a vote to a website!
        Websites.update({_id: website_id},
                        {$set: {up: this.up + 1}});

        return false;// prevent the button from reloading the page
    }, 
    "click .js-downvote":function(event){

        // example of how you can access the id for the website in the database
        // (this is the data context for the template)
        var website_id = this._id;
        console.log("Down voting website with id "+website_id);

        // put the code in here to remove a vote from a website!
        Websites.update({_id: website_id},
                        {$set: {down: this.down + 1}});

        return false;// prevent the button from reloading the page
    }
})

Part 11. Sort items by votes up

This is an easy one. We know Meteor templates are reactive, meaning the UI gets updated automatically every time something changes. We are going to take advantage of that by defining a sorting in the website_list template in main.js:

Template.website_list.helpers({
    websites:function(){
        return Websites.find({}, {sort: {up:-1}});
    }
});

Part 12. Implement a detail page using routing

Now we need to create a new route in main.js that will take the website id as a parameter in the URL path and query the DB to get the data of that id. We will also render a new template in the main placeholder:

Router.route('/:_id', function () {
    this.render('navbar', {
        to: 'navbar'
    });
    this.render('website_detail', {
        to: 'main',
        data: function() {
            return Websites.findOne({_id: this.params._id});
        }
    });
});

Now let's create the new template in index.html:

<!-- template that displays a website detail -->
<template name="website_detail">

    <h1><a href="{{url}}">{{title}}</a></h1>
    <p>
        {{description}}
    </p>
    <a href="#" class="btn btn-default js-upvote">
        <span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
    </a>
    <a href="#" class="btn btn-default js-downvote">
        <span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>
    </a>
    <p class="website-meta">Votes: <span class="js-votes-up">{{up}}</span>↑, <span class="js-votes-down">{{down}}</span>↓

<h3>Comments</h3> </template>

Part 13. Adding comments to the detail page

First we are going to create a new Mongo collection in collections.js:

Comments = new Mongo.Collection("comments");

Then two new main placeholders in the ApplicationLayout template and three new templates (very similar to the ones we already have) in index.html:

{{> yield "comments"}}
{{> yield "comment"}}

(...)

<!-- template that displays several comments -->
<template name="comments_list">
    <ol>
    {{#each comments}}
    {{>comment_item}}
    {{/each}}
    </ol>
</template>

<!-- template that displays individual comment entries -->
<template name="comment_item">
    <li>
        {{comment}}
        <p class="comment-meta">{{formattedDate}} by {{user}}</p>
    </li>
</template>

<!-- template that displays the form to submit a new comment -->
<template name="comment_form">
    <div id="comment_form">
        <form class="js-save-comment-form">
          <div class="form-group">
            <input type="text" class="form-control" id="comment" placeholder="Type your comment here...">
          </div>

          <button type="submit" class="btn btn-default">Submit</button>
        </form>
    </div>
</template>

Then, we are going to update the detail page route (in main.js) and render the new templates:

this.render('comments_list', {
    to: 'comments'
});
this.render('comment_form', {
    to: 'comment'
});

Now we have to insert the new comments into the comments collection whenever a logged in user submits the comment form. The schema for this collection is going to store the ID of the website where the comment belongs, the comment itself, the date and the user who wrote it. Notice that to get hold of the website ID, we are going to use the Router params...

Template.comment_form.events({
    "submit .js-save-comment-form":function(event){

        if (Meteor.user()) {

            // here is an example of how to get the comment out of the form:
            var comment = event.target.comment.value;
            console.log("The comment they entered is: "+comment);

            Comments.insert({
                website: Router.current().params._id, 
                comment: comment, 
                createdOn: new Date(),
                user: Meteor.user().username
            });
        }
        else {
            alert('You need to be logged in to submit comments!');
        }

        return false; // stop the form submit from reloading the page

    }
});

Now that we have the comments stored in the DB, we need a template helper to render the list of comments. We will filter the query by finding only the comments that have a website ID equal to the one of the current page:

Template.comments_list.helpers({
    comments:function(){
        return Comments.find({website: Router.current().params._id});
    }
});

Los antecedentes de los medios interactivos

$
0
0
Los antecedentes de los medios interactivos

El siguiente artículo es una reflexión sobre la importancia y significación de la vida cotidiana, la globalización y la inteligencia colectiva para el nacimiento de los medios de comunicación en masa y la consolidación de la sociedad de la información.

Además, este artículo es un trabajo de la asignatura de Medios interactivos del Grado Multimedia de la UOC.

La vida cotidiana

Recientemente, mi padre publicó una nota en Facebook, en la cual decía lo siguiente:

Creo que la obsesión tecnológica se está convirtiendo en una pesadilla ¿Nos libera la hipertecnología? ¿Tal vez de nosotros mismos? ¿Será un lujo tener un YO en el mundo que estamos o están...construyendo? ¿Crea la hipertecnología puestos de trabajo o más bien los destruye a un ritmo cada vez mayor? En fin, a mi personalmente no me gusta un pelo el mundo que viene. Creo que es más bien terrorífico, deshumanizador..., eso sí... de una manera ligera (light, soft, etc). Para que no veamos la cara del monstruo. Pero ya se va viendo algo y aquí tenemos al androide sonriente...

Es una opinión crítica contra la tecnología de una persona de 65 años. Licenciado en Filosofía, catedrático de Historia y usuario de nuevas tecnologías desde que tiene uso de razón. En cualquier caso, encaja bastante bien dentro del perfil de una persona jubilada de su actividad laboral y que en teoría tiene tiempo libre para aprender a usar las nuevas tecnologías y a participar en los medios interactivos.
Su opinión no era nueva para mi, ya que en otras ocasiones habíamos hablando del tema. Mi reacción inicial fue defender los beneficios de la tecnología para la humanidad. Repliqué en Inglés:

Because of technology, a lot of people have access to information, a lot of diseases are being cured, the universe is being explored and we are having this conversation. How technology can be a bad thing? Just because kids use their phones in the table while having lunch with their parents?

La conversación continuo con varios intercambios de opiniones, hasta que al final, me reveló el motivo de su frustración:

Entre 1987 y 1992 yo tenia entre 35 y 40 años y pertenecía a la generación de "los reyes del mambo" o "los putos amos" (como dicen ahora). Con los cassettes, los VHS y el Fax (ultima maravilla tecnológica) nos sentíamos de puta madre. Llegan los 90 y con ellos el PC e Internet y, de ser los putos amos, nos vamos convirtiendo en "material reciclable". Es una historia que se repite siempre. De ahí que nadie de mi generación flipe con las tecnologías que nos destronaron ni les haga reverencias. Las usamos en lo que podemos, sabiendo que cada vez nos será mas difícil estar al día e incluso participar. En todo esto también exagero pero es una manera de llamar la atención y desahogar una cierta frustración.

En cierta medida, no le falta razón. Las nuevas tecnologías han redefinido muchos aspectos de nuestra vida y siguen haciéndolo a un ritmo exponencial. De hecho, para los profesionales que trabajamos en algo relacionado con Internet o las nuevas tecnologías, no hay ningún año que pase que no tengamos que aprender un nuevo paradigma, framework, sistema, plataforma, librería, software o herramienta. El aprendizaje es continuo y constantemente tenemos que reciclar nuestro conocimiento del medio para poder seguir siendo útiles en nuestra profesión.

La vida cotidiana ha cambiado muchísimo con respecto a los anos 60 y es normal que la gente que no ha crecido en esta vorágine de adelantos tecnológicos tan rápidos, se vea abrumada y frustrada. Por muy cultos e intelectuales que puedan ser, el mundo digital utiliza unos códigos, metáforas, sistemas y entornos virtuales que requieren de un aprendizaje. Es necesario invertir tiempo y esfuerzo, de lo contrario, te ves abocado al ostracismo tecnológico o a una participación simbólica y poco fructífera.

Por otro lado, los millenials y gran parte de la generación X nos hemos adaptado a los nuevos tiempos sin mayores complicaciones. Al fin y al cabo hemos crecido jugando a las maquinitas, asistiendo al nacimiento de Internet y siendo los pioneros en consumo y producción de todo lo digital y virtual. Actos tan sencillos como comprar la revista de videojuegos en el quiosco fueron remplazados por una suscripción a una revista online. Napster marco un antes y un después en el intercambio de música. Lo de grabar el cassette del vecino quedo relegado inmediatamente al pasado.

Hay infinidad de ejemplos de nuestra vida cotidiana que fuimos adaptando uno a uno a la sociedad de la información, hasta llegar al presente, donde prácticamente todas las acciones susceptibles de ser incorporadas al mundo digital, ya lo han hecho o lo van a hacer pronto (léase fintech). A este proceso de reconversión de una actividad analógica comercial o industrial se le conoce con el termino anglosajón disruption. Ya lo hemos ido viendo recientemente en el caso de AirBnB o Uber, los cuales siguen teniendo tensiones con los profesionales que aun se ganan la vida con el modelo tradicional.

La globalización

Los medios de comunicación en masa y la sociedad de la información también contribuyeron a acelerar una mayor integración de las naciones del mundo, el intercambio de ideas, productos y culturas. A este proceso se le conoce como la globalización.
Internet ha propiciado que la gente de países aislados tenga acceso a la mayor fuente de información del mundo y pueda aprender y observar lo que esta pasando en otras partes del planeta. Los medios de transporte también han ayudado a que las personas podamos viajar y confirmar todo aquello que conocemos a través de Internet. Por tanto, es un sistema que se retroalimenta. Los usuarios buscan y comparten información en las redes y luego comprueban que esa información les es útil en la vida real. Por ejemplo, el caso de TripAdvisor, una aplicación que reúne miles de opiniones de usuarios sobre hoteles, restaurantes y lugares, de forma que los viajeros puedan tomar decisiones informadas para su beneficio durante sus viajes.
Hoy en día, las modas ya no son fenómenos aislados. Las noticias ya no son solo locales. Los cambios en las economías afectan a todos los países. Todo es global. Todo es instantáneo. Todos los datos fluyen y nos afectan en mayor o menos medida. Las personas que habitamos el mundo moderno y conectado ya no estamos aisladas y dependemos unas de otras.

La cantidad ingente de datos que estamos generando está dando pie a que aparezcan nuevas disciplinas científicas, como por ejemplo el Big Data, cuyo objetivo es analizar cantidades masivas de datos en busca de patrones para obtener conclusiones que puedan luego reportar luego beneficios.
La globalización hace que la gente cada vez consuma más información. Ya no solo consumimos el periódico local y conversamos con los vecinos o compañeros de trabajo. Hoy en día, la gente se mueve de un lado a otro, habla varios idiomas y se comunica con colegas y conocidos en varias zonas horarias del planeta. Nuestro círculo de acción se ha expandido notablemente y por tanto, cada vez necesitamos mejores medios de comunicación y maneras de interactuar mas entretenidas, productivas y efectivas.

La inteligencia colectiva

Los medios de comunicación masivos también se han retroalimentado a partir de otro movimiento muy importante. El de la inteligencia colectiva. Este movimiento está mas respaldado por la gente joven, ya que requiere un nivel de asimilación alto sobre el funcionamiento de Internet y las redes sociales. También es el medio de expresión más popular entre la gente en posición de luchar por cambios drásticos a nivel social y político.
La inteligencia colectiva emerge de la colaboración y los esfuerzos colectivos de muchos individuos con el objetivo de tomar decisiones conjuntas y consensuadas. Es un fenómeno que se puede apreciar en su mayor esplendor en las actividades de crowdfunding, en la Wikepedia (una enciclopedia gratuita mantenida por los usuarios de Internet), en las peticiones de firmas online, redes sociales, sistemas de votos online, foros y comunidades online como StackOverflow, etc.

En los últimos anos, hemos podido observar como la gente se ha organizado para crear movimientos tan importantes como la primavera árabe o el 15M. Estos movimientos también tienen una base de inteligencia colectiva, ya que las redes sociales tuvieron un papel principal en su organización y difusión. Estos sucesos son únicos y novedosos en la historia de la humanidad, ya que sin los medios de comunicación masiva, no podrían haber llegado a ese nivel de repercusión. También el hecho de que los dictadores y represores censuraran y cortaran el uso de Internet durante la primavera árabe, nos indica el nivel de poder e influencia que ha llegado a tener este medio para desestabilizar todo un país y llegar a derrocar gobiernos.

El anterior punto me lleva a hablar de otro tema de gran actualidad: las elecciones presidenciales en EEUU. Si tenemos en cuenta que Internet se ha convertido en un medio de vital importancia, es normal que los gobiernos y las grandes corporaciones lo quieran controlar. Por este motivo, hoy en día es muy importante informarse sobre los intereses de los diferentes partidos políticos. ¿Quién subvenciona sus campanas electorales? ¿Qué objetivos tienen respecto a la neutralidad de la red? ¿Qué opinión les merece organizaciones como Wikileaks o personajes como Edward Snowden…? Todos estos aspectos se discuten en las redes sociales como Facebook o Twitter y acaban moldeando la conciencia colectiva y las opiniones de la gente mediante la inteligencia colectiva. Entre todos, se obtienen los datos objetivos y transparentes. Es una forma de desvelar la verdad. De destapar a los mentirosos y manipuladores. Es la nueva política de participación ciudadana. Creada a partir de la inteligencia colectiva y el intercambio de datos en las redes sociales.

Conclusión

Todos los fenómenos de los que hemos hablado se retroalimentan entre ellos y sus causas/efectos no están detalladamente limitados. Otro de los aspectos que ha llevado al éxito de los medios de comunicación masivos y la sociedad de la información es su naturaleza bidireccional. Ya no estamos hablando de TV, radio o prensa. Medios unidireccionales. Internet nos permite convertirnos en productores de contenidos. No solo en consumidores. Todos los usuarios tenemos una voz y espacios donde compartir información. La manipulación de la sociedad ya no es tan sencilla. Ahora es más fácil poder obtener una perspectiva más objetiva juntando las opiniones de cientos de publicaciones (incluyendo blogs). Podemos decir que Internet ha democratizado la información y la ha hecho más viva y rápida.

Seguramente, la neutralidad de la red y la bidireccionalidad de las comunicaciones, sean los factores mas importantes para su éxito, ya que son la esencia, los principios que permiten que se desarrollen otros fenómenos como la globalización y la inteligencia colectiva. Por tanto, nuestro objetivo como ciudadanos defensores de la libre información, la democracia y la justicia social es esforzarnos para que los gobiernos no legislen para favorecen los intereses de unos pocos y las grandes corporaciones no intenten comprar a los gobiernos para que favorezcan sus intereses.


Open Source LMS with React and Node.js

$
0
0
Open Source LMS with React and Node.js

If everything goes as expected, next semester I will start my final project for my university degree. I decided to take advantage of that "obligation" to make something useful for the community and at the same time improve my React and Node.js skills. That's how I arrived to the idea of building an Open Source Learning Management System.

Another reason why I chose to build an LMS is because I keep seeing how things could be done better in my university's virtual campus. I particularly have a lot of things to say regarding the way students interact with each other and with the teacher. The current system does not provide an agile communication. It feels slow, with popup windows, cluttered with signatures and other non-relevant data. I want to build a platform that takes the best out of other successful products (that I use in my work), like Slack or Trello and adapt them for educational environments.

In the last days, I've been searching the web and the GitHub repositories for JS LMS projects, trying to see if there's anything like that already going on, but I haven't found any with a strong presence (which is good news). I'm not sure if I would start the project if somebody else already did. Maybe I would anyway! :)

Of course there are other LMS with APIs and modern stacks, like Canvas LMS or Blackboard (41% of market share), D2L, Kaanu, but they are not using the same stack I want to use and they are not targeting developers. At the same time, I feel that having more open source options out there would be better for everyone.

I know it sounds like a very strong commitment for just one person and a humongous side-project (as I'm still working full-time), but this is going to be like a playground for me, where I can learn about the tech I like and at the same time produce something useful.

Here are some of the requirements I already thought about:

  • The final goal is to offer something to the community that feels as the Wordpress of the LMS. Something that is flexible enough to suit the majority of needs by being very opened and easy to extend / scale

  • So far, I want to use a similar tech stack to the one used in project Wordpress Calypso. The increasingly popular React and React Native, Flux, Babel.js for ES6, Webpack as the bundler, Node.js as the backend platform and perhaps Loopback for building the API

  • The UX and responsive plain design have to be spot-on. This is a very important requirement, as I don't want to create something that feels like Moodle (23% of market share), which has a very old-school UI

  • The homepage will display a list of available courses, the same way Udemy does it

  • It needs to be real time, with agile communication like Slack. No more forums, emails or other slow and cluttered systems to talk to each other

  • I want to include quizzes, something similar to what I did with Quizwars and probably get some inspiration from QuizUp

  • It needs to integrate easily with Google Docs, Trello, Dropbox and other external tools. I want to use the Internet as a CMS!

  • It needs to have an open REST API, so users could create their own front-ends

  • It has to be social and implement learning analytics

  • It needs to have a catchy name with a free .com and .org domain (this is going to be hard)

Libros especiales para mí

$
0
0
Libros especiales para mí

He de reconocer que no soy un gran lector. No quiero poner excusas, pero mi generación ha tenido muchas distracciones: ordenadores, videojuegos, Internet, televisión,...

Aunque no haya leído todo lo que me habría gustado (algo que quiero poner remedio), soy un gran defensor de la literatura. Es sin lugar a dudas el mejor medio para aprender (en general) de forma profunda sobre muchos temas. Los grandes pensadores, artistas e intelectuales son todos amantes de los libros. ¿Eso tiene que significar algo, verdad?

¿No te has parado a pensar nunca, el grandísimo trabajo que hay detrás de un libro? A veces es el trabajo de toda una vida el que acaba condensado en un libro. De forma que, cuando lo leemos, estamos adquiriendo (de forma resumida) el conocimiento de la persona que lo escribió. Esa es la grandeza de los libros. Es como cuando en la película Matrix, a Neo le enchufaban la cabeza a un cable y le empezaban a cargar programas de artes marciales...

Libros especiales para mí

Durante mi vida, he ido leyendo diferentes tipos de libros. Cuando era pequeño, solía leer novelas y libros de ciencia ficción. Luego empecé a interesarme por la psicología, los libros de auto-ayuda, filosofía y religión. Luego me pico el gusanillo con los libros de viajes y de arte. Actualmente, los libros que más leo son los relacionados con mi trabajo. Cosas de programación, tecnología, ciencia y algo relacionado con los emprendedores y los negocios.

La verdad es que es complicado sacar tiempo para poder leer libros de todo tipo. Por tanto, no puedo culpar a nadie de no hacerlo! Lo entiendo perfectamente.

El pasado viernes, mi vuelo de Alicante a Londres se retrasó, así que se me ocurrió la idea de comprar un libro para ir haciendo tiempo hasta que llegara la hora de embarcar. Encontré una novela de Haruki Murakami. Se llama 'Kafka en la orilla' y es la historia de un chico joven que se va de casa a los 15 años. La verdad es que me ha enganchado! He empezado a recordar el placer que se siente cuando encuentras un libro que realmente te gusta mucho y que no puedes dejar de leer! Por eso, he decidido hacer un poco de retrospección y revisar algunos de los libros que he leído durante mi vida y me han marcado de algún modo.

A continuación, he preparado una pequeña lista de libros que han sido especiales para mí por alguna razón. Podría incluso llegar a decir que algunos de estos libros me han cambiado la vida! No esperéis nada del otro mundo. Los tochos mega-intelectuales (filosofía y religión) muchas veces me dan sueño, así que tengo un montón de libros pendientes de terminar ¯\(ツ)

El alquimista (Paolo Coelho) y El monje que vendió su Ferrari (Robin Sharma): estos dos libros que leí en el verano de 2007 fueron el caldo de cultivo de la ruta samurai. Fueron una gran inspiración para mi y me ayudaron a visualizar la forma en la que debía prepararme para aquel gran viaje. El alquimista también me inspiró a realizar un viaje a lo mochilero por Marruecos, donde sucedieron multitud de aventuras.

En el filo de la navaja (William Somerset Maugham): este libro lo leí en mis viajes de metro cuando vivía solo en París. En cierto modo, amplificó ese sentimiento de aventura que estaba sintiendo al vivir por primera vez en un país distinto.

En el camino (Jack Kerouac): este libro lo leí durante mi viaje por el sur de España y luego Marruecos. Leer libros de viajes mientras se viaja es muy excitante.

Zen, it's history and teachings (Osho): este libro lo encontré en la casa de mis suegros en Manila, Filipinas. Era mi último día allí antes de volver a Londres, así que le pedí a mi suegro que me dejara llevármelo. Me gustó mucho leer sobre el Zen y descubrir como al final todo se concentra en soltar una carcajada! ¿Te has quedado desconcertado/a? Pues ya sabes... :)

Un geek en Japón (Héctor García): llevo siguiendo el blog de Kirai desde su comienzo, allá por el año 2005. Desde entonces, ya estaba entusiasmado con las historias que publicaba sobre sus vivencias en Japón. Por tanto, no es de extrañar que su primer libro lo disfrutara igual o más que las entradas en su blog. Aún tengo pendiente leer su último libro, Ikigai, del cual he leído un artículo en el periódico La Vanguardia y tiene muy buena pinta!

The dream (Gurbaksh Chahal): este fue el primer libro que leí relacionado con los emprendedores. Me quedé fascinado por la historia de Gurbaksh y de como su determinación y ambición le habían llevado a hacerse millonario siendo muy jóven.

Tus zonas erróneas (Wayne Dyer) y La brújula interior (Alex Rovira): estos dos libros son de la época cuando descubrí los libros de auto-ayuda. Me flipé un poco con el tema y estuve leyendo otros relacionados con la inteligencia emocional, el positivismo, etc. En general, me fueron muy útiles para poner en práctica algunas cosas en mis relaciones con los demás. Quieras o no quieras, cuando sales por primera vez de tu casa y te enfrentas al mundo, hay cosas que tienes que aprender para desenvolverte mejor en la sociedad, y estos libros son sin duda una gran ayuda en esos momentos.

Siddharta (Herman Hess): llamándome Joan Siddharta, habría sido un pecado gordo no haber leído este libro! En cualquier caso, es una historia muy bonita que recomiendo a todos leer. Además, tiene unas enseñanzas que bien me gustaría que todo el mundo pusiera más en práctica. Como por ejemplo, el deshacerse de las posesiones materiales o el tratar la naturaleza y los animales con amor y respeto. Quién sabe..., quizás alguno de vosotros llegue a experimentar el nirvana? :)

Congreso de futurología (Stanislaw Lem): este fue el primer libro de ciencia-ficción que leí. No recuerdo la edad, pero sería alrededor de los 12 o 14 años. Seguramente no le saqué todo lo que podría, pero recuerdo haberme quedado bastante flipado.

Seguro que hay alguno más que ha sido especial, pero como la mayoría de mis libros los tengo en Alicante, no consigo acordarme. Lo que voy a hacer es ir actualizando esta entrada del blog a medida que me vaya acordando de otros libros.

How to set up a Node.js (React ES6) app for production on Ubuntu with Nginx and basic auth

$
0
0

Introduction

How to set up a Node.js (React ES6) app for production on Ubuntu with Nginx and basic auth

Node.js is an open source JavaScript runtime environment for easily building server-side and networking applications. The platform runs on Linux, OS X, FreeBSD, and Windows. Node.js applications can be run at the command line, but we'll focus on running them as a service, so that they will automatically restart on reboot or failure, and can safely be used in a production environment.

In this tutorial, we will cover setting up a production-ready Node.js environment on a single Ubuntu 16.04 server. This server will run a Node.js application managed by PM2, and provide users with secure access to the application through an Nginx reverse proxy with basic auth.

Prerequisites

This guide assumes that you have an Ubuntu 16.04 server (it also works with Ubuntu 14). If you don't have one yet, I do recommend Digital Ocean, OVH or Amazon AWS.

It also assumes that you have a domain name, pointing at the server's public IP address.

Let's get started by connecting to the server via SSH.

Connect to the server via SSH

Once your server is up and running, you must have an IP address or DNS your can use to connect to the server. In this example, we are going to use the DNS of a Ubuntu micro instance from Amazon AWS EC2.

During the process of setting up the server, you should create or use an existing key. Download it to a folder in your computer (usually ~/.ssh/) and run the following command from your terminal:

ssh -i ~/folder/to/your/ssh/key.pem ubuntu@ec2-28-28-82-82.eu-central-1.compute.amazonaws.com

That should give your access to your server!

Note: make sure that your instance accepts HTTP traffic. In Amazon AWS you have to go to 'security groups', and add HTTP / TCP / Port 80 to the inbound rules of the security group of your instance.

Install Node.js

We will install the latest current release of Node.js, using the NodeSource package archives.

First, you need to install the NodeSource PPA in order to get access to its contents. Make sure you're in your home directory, and use curl to retrieve the installation script for the Node.js 6.x archives:

cd ~ curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh

And run the script under sudo:

sudo bash nodesource_setup.sh

The PPA will be added to your configuration and your local package cache will be updated automatically. After running the setup script from nodesource, you can install the Node.js package in the same way that you did above:

sudo apt-get install nodejs

The nodejs package contains the nodejs binary as well as npm, so you don't need to install npm separately. However, in order for some npm packages to work (such as those that require compiling code from source), you will need to install the build-essential package:

sudo apt-get install build-essential

The Node.js runtime is now installed, and ready to run an application!

Clone your app

Make sure that git is installed:

sudo apt-get install git

Next, clone your app from GitHub (or any other repository) to /opt/your_app. The /opt/ directory is a standard location for software that's not installed from the distribution's official package repositories:

sudo git clone https://github.com/your_user/your_app /opt/your_app

Change to your app directory:

cd /opt/your_app

Run npm install, bower install or any other command you need to set up your app. Make sure that there are no build errors and once you are done, close your app and proceed to the next step.

Set Up Nginx as a Reverse Proxy Server

Now that your application is working, you need to set up a way for your users to access it. We will set up an Nginx web server as a reverse proxy for this purpose. This tutorial will set up an Nginx server from scratch. If you already have an Nginx server setup, you can just copy the location block into the server block of your choice (make sure the location does not conflict with any of your web server's existing content).

First, install Nginx using apt-get:

sudo apt-get install nginx

Now open the default server block configuration file for editing:

sudo nano /etc/nginx/sites-available/default

Delete everything in the file and insert the following configuration. Be sure to substitute your own domain name for the server_name directive. Additionally, change the port (8080) if your application is set to listen on a different port:

server {
    listen 80;

    server_name example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

This configures the server to respond to requests at its root. Assuming our server is available at example.com, accessing http://example.com/ via a web browser would send the request to your app, listening on port 8080 at localhost.

Once you are done adding the location blocks for your applications, save and exit.

Next, restart Nginx:

sudo service restart nginx

Assuming that your Node.js application is running, and your application and Nginx configurations are correct, you should now be able to access your application via the Nginx reverse proxy. Try it out by accessing your server's URL (its public IP address or domain name).

Set up basic authentication

Sometimes, we don't want everyone to see our app until it's not completely ready. For that and other reasons, we might like to implement a simple user authentication system that will request for a username and password.

First we are going to create the password file using the OpenSSL utilities. We will create a hidden file called .htpasswd in the /etc/nginx configuration directory to store our username and password combinations.

You can add a username to the file using this command. We are using 'pepe' as our username, but you can use whatever name you'd like:

sudo sh -c "echo -n 'pepe:' >> /etc/nginx/.htpasswd"

Next, add an encrypted password entry for the username by typing:

sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"

You can repeat this process for additional usernames. You can see how the usernames and encrypted passwords are stored within the file by typing:

cat /etc/nginx/.htpasswd

Configure Nginx password authentication

Now that we have a file with our users and passwords in a format that Nginx can read, we need to configure Nginx to check this file before serving our protected content.

Begin by opening up again the server block configuration file that we previously opened:

sudo nano /etc/nginx/sites-enabled/default

To set up authentication, you need to decide on the context to restrict. Among other choices, Nginx allows you to set restrictions on the server level or inside a specific location. In our example, we'll restrict the entire document root with a location block, but you can modify this listing to only target a specific directory within the web space:

Within this location block, use the authbasic directive to turn on authentication and to choose a realm name to be displayed to the user when prompting for credentials. We will use the authbasicuserfile directive to point Nginx to the password file we created:

server {
    listen 80;

    server_name example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

Save and close the file when you are finished. Restart Nginx to implement your password policy:

sudo service nginx restart

The directory you specified should now be password protected.

Install PM2

PM2 is a process manager for Node.js applications. PM2 provides an easy way to manage and daemonize applications (run them in the background as a service).

We will use npm, a package manager for Node modules that installs with Node.js, to install PM2 on our server. Use this command to install PM2:

sudo npm install -g pm2

The -g option tells npm to install the module globally, so that it's available system-wide.

PM2 is simple and easy to use. We will cover a few basic uses of PM2.

Start Application

The first thing you will want to do is use the pm2 start command to run your application, hello.js, in the background:

pm2 start hello.js

In some cases, your app might use 'npm start' to start its execution. If that's the case, you can start your app with PM2 like this:

pm2 start npm -- start

Note: the production settings of each app might be very different, so we will not cover that in this tutorial. Just make sure to run the command that will run the production tasks to bundle and run your app.

This also adds your application to PM2's process list, which is outputted every time you start an application:

Output
[PM2] Spawning PM2 daemon [PM2] PM2 Successfully daemonized [PM2] Starting npm in fork_mode (1 instance) [PM2] Done. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ npm │ 0 │ fork │ 3524 │ online │ 0 │ 0s │ 21.566 MB │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app

As you can see, PM2 automatically assigns an App name (based on the filename, without the .js extension) and a PM2 id. PM2 also maintains other information, such as the PID of the process, its current status, and memory usage.

Applications that are running under PM2 will be restarted automatically if the application crashes or is killed, but an additional step needs to be taken to get the application to launch on system startup (boot or reboot). Luckily, PM2 provides an easy way to do this, the startup subcommand.

The startup subcommand generates and configures a startup script to launch PM2 and its managed processes on server boots. You must also specify the platform you are running on, which is ubuntu, in our case:

sudo pm2 startup ubuntu

This will create a systemd unit which runs pm2 for your user on boot. This pm2 instance, in turn, runs 'npm start'

Other PM2 Usage (Optional)

PM2 provides many subcommands that allow you to manage or look up information about your applications. Note that running pm2 without any arguments will display a help page, including example usage, that covers PM2 usage in more detail than this section of the tutorial.

Stop an application with this command (specify the PM2 App name or id):

pm2 stop app_name_or_id

Restart an application with this command (specify the PM2 App name or id):

pm2 restart app_name_or_id

The list of applications currently managed by PM2 can also be looked up with the list subcommand:

pm2 list

More information about a specific application can be found by using the info subcommand (specify the PM2 App name or id):

pm2 info example

The PM2 process monitor can be pulled up with the monit subcommand. This displays the application status, CPU, and memory usage:

pm2 monit

Now that your Node.js application is running, and managed by PM2, let's set up the reverse proxy.

Disclaimer

This tutorial is based on the great work of Digital Ocean community tutorials. IMHO one of the best resources in the Internet in terms of sys-admin related stuff.

VueJS: first impression and how to work with SVGs

$
0
0
VueJS: first impression and how to work with SVGs

After a delightful year working with React, I decided to explore a new framework. I was looking at Ember (not so popular at the moment), Elm (although is not a framework, it still lacks a lot of stuff), Angular2 (not interested to learn TypeScript yet) and Vue (gaining a lot of momentum). At the end, I choose Vue!

The first impression was very good. The Vue docs are really good and their website is so clear and helpful. Then I learned about the awesome resources, where I found a couple of boilerplates that work with Electron, which is a library from Git used to build desktop apps. Do you use the Git Atom editor or the Slack desktop app? Then you should know that those are built with Electron!

Anyway, Electron has nothing to do with Vue, but it was just a nice discovery and I wanted to share it.

The target of this article is to show you how I managed to setup SVGs with the Vue webpack boilerplate. By the way, if you don't know that boilerplate, I encourage you to really check it out. I was very impressed by its quality and the ridiculous simplicity when it comes to creating a new project. It takes just 5 lines to do it!

My intention was to replicate the setup that I had with my previous React boilerplate, where I had a folder with all the SVG files and I could import them into my React components whenever I require them.

To do so, in your newly created Vue project, you need to install this webpack loader called svg-sprite-loader. Then, in build/webpack.base.conf.js we just have to declare the new loader (line 88 to 92 aprox.):

loader: 'svg-sprite?' + JSON.stringify({  
    name: '[name]_[hash]',
    prefixize: true
})

Also, in the same file, you have to remove the svg format from line 72: test: /\.(png|jpe?g|gif)(\?.*)?$/,. If we don't do it, this loader would try to load the SVG and the svg-sprite loader wouldn't do anything.

That's all we need as far as webpack configuration. The next step is to create a new component called Icon. This component will be useful to render inline SVGs in our pages. Remember that, this is the only way we can change the colors of the SVGs using fill or stroke. If you load them as CSS backgrounds or <img> tags, then you will not be able to alter their colors.

Create a new file called Icon.vue inside your src/components folder and paste the following code:

<template>  
  <svg :class="className" :width="width" :height="height">
    <use :xlink:href="glyph" />
  </svg>
</template>

<script>  
export default {  
  name: 'icon',
  props: ['className', 'glyph', 'width', 'height'],
};
</script>

<style scoped>  
.icon {
  display: inline-block;
}
</style>  

This is a basic implementation. You can can expand it with more CSS code or props.

Finally, to load the SVGs, I'm going to show you a simple example of how to load a logo icon and a close icon for the main App component, where we have the app layout. If you haven't modified the boilerplate yet (which is unlikely), you will have an App component. If that's not the case, don't worry, this example applies to any component.

Let's see first the code and then we can review it:

<template>  
  <div id="app">
    <icon width="100" height="100" :glyph="Logo"></icon>
    <icon width="100" height="100" :glyph="Close"></icon>
  </div>
</template>

<script>  
import Icon from './components/Icon';  
import Logo from './assets/logo.svg';  
import Close from './assets/close.svg';

export default {  
  name: 'app',
  components: {
    Icon,
  },
  data() {
    return { Logo, Close };
  },
};
</script>  

Whenever you want to add a new SVG to your template, you have to add code in 4 different places:

  1. Import the file from the assets folder: import Logo from './assets/logo.svg';

  2. Add the Icon component to the components object

  3. Return the imported SVG in the data function

  4. Call the Icon component and pass the appropriate props: <icon width="100" height="100" :glyph="Logo"></icon>

That's all!

If you find a better way to do this. Please let me know. Thanks.

A few more VueJS 2 tweaks for the beginners

$
0
0
A few more VueJS 2 tweaks for the beginners

This is my second blog post about VueJS 2. In the first one, I covered my initial impressions and how to work with SVGs. In this second post, I'm going to talk about some bits and bobs that I've discovered and that it wasn't that straight forward to figure them out.

Before you continue reading, remember that I'm using the Vue webpack boilerplate, so all my tweaks are customised for it. Nonetheless, if you are not using this boilerplate, you might be able to grasp the ideas and apply them to yours.

How to setup SASS with global files

One of the first things you might want to do is to structure your Vue app with proper SASS global mixins, variables, elements, etc. To do so, you need to create a central scss file with all the @import statements to other global or common files like variables.scss, mixins.scss. There are several ways of doing that (as usual), but I've found the following one, the easiest:

  1. Open build/utils.js and go to line 43. That's where the SASS loader is. Then replace the line with this: scss: generateLoaders(['css', 'sass?data=@import "~assets/styles/app";'])

  2. The previous change will load the assets/styles/app file and that's where you have to put all your @imports.

  3. You can put other path, but I'm saving all my generic SASS files inside src/assets/styles

How to send data from a child component to its parent or other components

From the official Vue docs:

All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to reason about.

So, it seems, in previous versions of Vue, there were two methods, called dispatch and broadcast, that would allowed us to communicate between components, but as you can see in the Vue docs, they have been deprecated because they don't scale well.

So, what they proposse is to, use a Flux implementation like Vuex, which is explained here, or if your app is not going to be very complex, you can use an event hub or bus. The event hub example is explained here and the bus example is explained here. I believe they are both the same, but the event hub example is more thorough.

If you decide to go with the event hub, then, one aspect that the docs don't cover, is how to inject and the eventHub object into all the child components from the root component.

In the following example, you can see how to implement the eventHub so that every child component can change a page heading:

  1. In main.js, create the eventHub and assign it to Vue:
const eventHub = new Vue();  
Vue.prototype.$eventHub = eventHub;  
  1. Then, pass the variable to Vue:
new Vue({  
  router,
  eventHub,
  ...
  1. Now you can start using emit and on in your child components. Every time you emit a value, it will be sent to all components and only those who have a listener (on) for that event, will get the value.
this.$eventHub.$emit('whateverChanged', this.passThisValue);  
this.$eventHub.$on('whateverChanged', this.callThisFunction);  

Useful VUE 2 videos and libraries

Move your React JSON API project from Redux to MobX

$
0
0
Move your React JSON API project from Redux to MobX

After a few projects using Redux, I've realised that it might not be the best solution for all kind of projects. Don't get me wrong, redux works great, but I tend to find myself procrastinating a bit whenever I have to add a new value to the state tree. Perhaps is due to the amount of code required to do it.

Anyway, this post is going to be about MobX. I will explain step by step the changes I had to do to make it work. Note that I am also using JSON API, so I will cover this aspect as well.

First of all, you need to remove all the redux packages and references from your codebase. Then you have to install the following babel plugins to allow the use of decorators.

yarn add babel-plugin-transform-decorators-legacy -D  
yarn add babel-plugin-transform-class-properties -D  

And then add them to the plugins array in your .babelrc file:

"plugins": ["transform-decorators-legacy", "transform-class-properties"]

Now we have to use babel as the ESLint parser. Add this package:

yarn add babel-eslint -D  

Then, update the parser in the .eslintrc file:

"parser": "babel-eslint"

Now let's install the following MobX packages:

yarn add mobx -S  
yarn add mobx-jsonapi-store -S  
yarn add mobx-react -S  
yarn add mobx-react-router -S  

That's all the dependencies we need so far. Now let's look at some code.

First of all, we are going to create a store to handle the app global states, like the loader, notifications alerts and other common flags.

Create a new file called store.jsx and add the following code:

import { autorun, observable } from 'mobx';

class MainStore {  
  @observable isLoading = true;
  @observable isFetching = false;
  @observable isDesktop = true;
  @observable notification: { message: '', type: '' };
  @observable apiReady = false;
  @observable isDesktop = false;
  @observable isDesktop = false;
}

const store = new MainStore();

autorun(() => {  
  // eslint-disable-next-line
  console.log(store);
});

export default store;  

In this file, we are just creating the state variables and making them observable. We are also using autorun to automatically console log any changes in the store (just for debug purposes).

Now, let's refactor the index.jsx file. We are going to be using the latest version of react router (v4) and the Material UI framework, so bear that in mind.

import React from 'react';  
import ReactDOM from 'react-dom';  
import createBrowserHistory from 'history/createBrowserHistory';  
import { Provider } from 'mobx-react';  
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';  
import { Router } from 'react-router';  
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';  
import mainStore from './store';  
import App from './components/app';  
import './components/bundle.scss';

const browserHistory = createBrowserHistory();  
const routingStore = new RouterStore();

const stores = {  
  routing: routingStore,
  app: mainStore
};

const history = syncHistoryWithStore(browserHistory, routingStore);

ReactDOM.render(  
  <Provider {...stores}>
    <Router history={history}>
      <MuiThemeProvider>
        <App />
      </MuiThemeProvider>
    </Router>
  </Provider>,
  document.getElementById('react-root')
);

The important bit to mention here is the object that contains the stores, one for the router and the other one that we created before. We then pass these stores to the MobX provider and that's it!

Now let's look at the app.jsx file, which will contain the routes and other common components:

import React, { Component } from 'react';  
import { inject, observer } from 'mobx-react';  
import { Route } from 'react-router-dom';  
import injectTapEventPlugin from 'react-tap-event-plugin';  
import Helmet from 'react-helmet';  
import Notification from './common/notification/notification';  
import Loader from './common/loader/loader';  
import Home from './home/home';  
import PageNotFound from './pageNotFound/pageNotFound';

injectTapEventPlugin();

@inject('routing') @observer
class App extends Component {  
  render() {
    const title = this.props.routing.title
      ? `${this.props.routing.title} | App name`
      : 'App name';

    return (
      <section className="app-container">
        <Switch>
          <Route exact path="/" component={Home} />
          <Route component={PageNotFound} title="Page not found" />
        </Switch>
        <Helmet title={String(title)} />
        <Loader />
        <Notification />
      </section>
    );
  }
}

export default App;  

All we are doing here is creating the routes and telling the component to be an observer, so that anytime the state variables change, the component will update. Notice also that we are reading the title from the route to know which page title to set using the Helmet package.

Remember to use Switch inside the Router and set the root path with exact, otherwise the page not found won't work.

Another example of how to use MobX, is for the loader component. We need to know when to display or hide the loader, so we are going to use the isLoading flag from the store we created. If the flag is true then the loader will be visible, otherwise not.

Let's look at the loader component:

import React, { Component } from 'react';  
import { inject, observer } from 'mobx-react';  
import classnames from 'classnames';  
import Icon from '../lib/icon/icon';  
import Logo from '../../../assets/svg/logo.svg';

@inject('app') @observer
class Loader extends Component {  
  render() {
    return (
      <section
        className={classnames('loader', {
          'fade-in': this.props.app.isLoading,
          'fade-out': !this.props.app.isLoading
        })}
      >
        <div className="loader__circle" />
        <div className="loader__line-mask">
          <div className="loader__line" />
        </div>
        <Icon glyph={Logo} className="loader__logo" />
      </section>
    );
  }
}

export default Loader;  

All we are doing is setting a fade-in or 'fade-out' class depending on the value of the isLoading state.

Now, from any component in the app, we can change this value by doing this.props.app.isLoading = false and the loader will hide.

Another thing that wasn't working with the new router, is the update of the page (with the new component) when moving from one page to another. After digging a bit about the issue, I found this stack-overflow answer that fixed it.

When you do @inject('routing') to a component, you get access to this.props.routing, so you can push new URLs to the browser history. That was working fine by doing something like this: this.props.routing.push(/leads/231234).

The problem was that the page was not refreshing, so I had to wrap the export of the components with withRouter(): export default withRouter(Home). You can import it from the react-router package.

Finally, let's look at how to integrate JSON API with MobX. This is a bit more difficult, but we'll get there!. The package we are using is mobx-jsonapi-store.

A simple example of how to request data from the API and asign it a store would be the following:

import {Store, config} from 'mobx-jsonapi-store';  
const teststore = new Store();  
config.defaultHeaders = {'xxxxxx': 'xxxxxxxxxx'};

teststore.request('http://localhost:3000/xxxxxxxxxxx')  
  .then((response) => {
    const Data = teststore.sync(response.data);
    console.log(Data);
  });

Article pending to be finished. To be continued soon...

Curriculum vitae

$
0
0
Last updated on January 2019

Summary

A pixel-focused, creative and proactive all-around front-end engineer / interactive developer / creative technologist / UX designer with 18 years of experience.

Loves to learn new stuff, organise and make things look pretty and cool, be challenged on ambitious projects or code beautiful interactive and innovative experiences.

Skills

In the past I have worked as a full-stack developer and web designer, but the current complexity of the web industry led me to focus primary in the front-end and the UX, although I still like to play with servers and design interfaces sometimes.

My interests and abilities are more aligned with the creative tracks (the visual, artistic, interactive and UI/UX side of the front-end work). Although I’m also experienced and comfortable with all the other aspects, like dealing with APIs, tooling/configuration, architecture, testing, performance, etc.

Currently, ReactJS is my favourite framework. I’m also learning GatsbyJS, GraphQL, Lambda functions on Netlify, Apollo, FaunaDB and would like to learn more about the WebGL and WebVR ecosystems…

tech

Front End

I will omit web browsers, sub-modules, polyfills, plugins, presets, loaders and minor modules.

Back End

Software engineering

Design

  • UX: IA (sitemaps), wireframes, storyboards, target audience/Personas, user testing sessions, clickable prototypes
  • Software: Invision, Sketch, Zeplin, Adobe CC (Photoshop, Illustrator, Premiere, After Effects, XD, Audition), 3dS Max

Systems administration

Creative Technologies

Experience

Agile Prototyping Analyst

Mar 2016 - Feb 2019Vodafone Global EnterpriseNewbury (UK) & Alicante (Spain)

  • Conceptualised, designed, built, tested and supported web apps (mostly SPAs) for the sales & digital operations of the Vodafone Global Enterprise division. Some of them were intended to aid the sales team with the visualisation of the pipeline, revenue and sales forecast, data quality, sales opportunities and other data related with performance. Others were more related with internal comms, problem solving and HR.

  • Worked 95% of the time remotely from different countries and used tools like slack, github and skype to communicate and manage our agile work methodology

  • Collaborated with data scientists, business analysts, back-end developers and designers to improve sales performance & productivity in the organisation

  • Successfully led the migration from jQuery/Angular to a React based architecture for all apps by creating a custom boilerplate with Redux state management, Webpack, JSON API integration, SASS and other modern technologies

  • Helped the rest of the front-end team to embrace the new React architecture

  • Owned the front-end development of 8 prototypes and participated in the development of a few others.

  • Led the redesign and development of a new dashboard app with widgets for the main website of the department

  • Identified the need of improving the UI and UX consistency of our apps and led the creation of a UI library (based on React and Styled Components) and a design system based on Vodafone’s design guidelines

  • Also worked with VueJS, Webpack, Highcharts, D3, MaterialUI, WebRTC, Express, CircleCI, GhostJS, HoneyBadger, CodeClimate, Jest, React testing library, JSON API, REST, etc

vodafone home desk
My home desk except in winter season :-)

Senior interactive developer

Jul 2013 - Nov 2015SapientNitroSpitalfields, London (UK)

SapientNitro was the number #1 digital agency in the UK at the time of my tenure. It’s also a division of Sapient corporation, which belongs to the Publicis group.

October 2015: worked on a responsive front-end for the insurance quote journey in Travelers. Tech involves lot’s of vanilla JS, mustache and path.js.

July - October 2015: co-led the front-end development of Unilever’s new global digital platform (building reusable white-label components) and Dove’s new website. We were a team of 8 front-end developers, working with a bespoke Node.js & Backbone framework and Adobe Experience Manager as CMS.

Aside from web development, I also helped with the management of the dev team, owning the deliverables of the team for a specific track, presenting the progress to the client, preparing prototypes for user testing, and updating the QA team.

May - July 2015: led a team of developers working on Save the children’s Drupal website. The tech stories were based on a technical audit I wrote and presented to the stakeholders with recommendations for the website.

June - July 2015: lead developer for the creation of microsites for a high street bank pitch and incubation design service. Worked with Handlebars, Assemble.io, a custom static site generator, LESS, Grunt, etc.

May 2015: (individual work) created an artistic installation that lets users throw fireworks using their hands. The demo was built with Kinect and OpenFrameworks for a creative technology event in SapientNitro’s Spitalfields office. The demo was installed in Eden House’s exhibit area:

April - May 2015: lead developer for the creation of a new mobile journey for the car insurance services of SAGA. Using MS Visual Studio 2012, .Net, LESS, JavaScript, HTML5, CSS3, jQuery, Knockout.js and Grunt.

Mar 2015: Flash developer for a custom build of an iPad prototype with Adobe Air for Barclays.

Feb 2015: lead developer for the creation of a 2D HTML5 animation for Vitality/Pruhealth using different technologies: Box2d + RUBE, HTML5 Canvas API, JavaScript and SVG manipulation.

Feb 2015: contributed to a mobile responsive web prototype for Dyson.

Jan 15: lead developer for an internal web app to manage the technical skills of Sapient employees with Node.js, Sails.js and MongoDB.

Nov 2014: (individual work) built a real time multiplayer game with Sails.js (Node.js, Waterline ORM, Express.js, Socket.io), Grunt, Bootstrap, LESS, jQuery, Parsley.js, Heroku, Git,…)

Apr - Nov 2014: senior/lead developer for the end to end redesign of a responsive front-end for the UK’s biggest telecommunications company with millions of customers. Using Angular.js, SEO, IE8 support, LESS, jQuery, Node.js, Grunt, Handlebars, JSON, Assemble.io, CSS3, Modernizr, SVN+Git, Vector icons font, iOS retina and iOS iOS compatible HTML5 canvas animations made with Adobe Flash CC.

Jun 2014: lead developer for a Volvo TrucksHTML5 prototype. Also worked in the Social Stock Ticker project using the PHP framework Laravel and Adobe Air.

May 2014: speaker at the Ember.js meetup (Introduction to the JavaScript port of Box2d and augmented reality with OpenCV realtime shape recognition with JavaScript).

Sep 2013 - Apr 2014: participated as a key member in the iPad frontend development team of the new Marks & Spencer’s website. Tech used includes: CSS3, Pub/Sub, Mustache, PHP, jQuery, Javascript, Modernizr, HTML5, etc.

SapientNitro has lead M&S through quite literally the biggest multi-channel retail re-platform in history with more than 600 SapientNitro people on the project that have worked more than 1.1 million hours!

Jul - Sep 2013: worked on a microsite for the ICA (Institute of Contemporary Art) in London called The Art Rules. I was mainly focussed working on the physics and animations. Tech used includes: Ruby on Rails (RoR), HAML, Heroku, Github (including issue tracking), SASS, CSS3 animations and Javascript Box2d 2D physics. It got shortlisted in theFWA and showcased for a few months on Eden House’s coffee & exhibit space.

sapient devs
With my co-workers, Owen and Mark during 'frinks' (Friday drinks)

sapient toys
We had many toys...

Creative Technologist

Aug 2012 - Jun 2013WCRSOxford Circus, London (UK)

WCRS belongs to the Engine Group, which was the number #5 digital agency in the UK at the time of my tenure.

During my tenure at WCRS, I worked on these accounts: BMW, MINI, Santander, Sky, Subway, Bupa, Unilever, Warburtons, Royal Navy, Churchill, Artemis and B&Q.

Achievements:

  • Pushed the technical boundaries and created innovative solutions
  • Advised and worked with creative teams on proposals and pitches
  • Built Facebook apps (mainly contests and promotions)
  • Built responsive HTML5 prototypes, microsites, blogs and websites
  • Built internal tools, demos and small games

Projects:

  • A Twitter sentiment extraction app
  • Several Kinect driven (hand tracking) particle systems
  • A Kinect driven (hand tracking) DJ sound mixing app with virtual vinyls and multi-screen support. It includes sound scratching and reverse playback
  • A Kinect driven demo (tracking the body) that forwards a video based on the user movement and position
  • Several demos with [Box2d](Box2d and OpenCV
  • An augmented reality car racing game with real-time obstacles and level editor

Some of the technologies used: Zend, C++, OpenFrameworks, OpenNI, Epoc Emotiv, Arduino, Android SDK, AndEngine, JAVA, Titanium SDK, Wordpress, Drupal,3rd party APIs, etc.

My articles in the WCRS blog:

UPDATE: the articles are no longer available at WCRS’ blog, so I replaced the links to relevant publications from other media outlets.

wcrs tech team
My co-worker, Silvia Rebelo, showing our new Tech Team area

Digital developer

Feb 2011 - Sep 2012Royal Opera HouseCovent Garden, London (UK)

I joined the newly created development team under the digital media department with a very important objective: to completely rebuild the ROH website from scratch. A business critical project that required a major overhaul in the ticketing system, server infrastructure, information architecture, user experience, content management and online shop to match the high standards of the organisation.

The development team was small; two full-stack developers, one design manager and a CTO. This scenario allowed me to have considerable influence in the application architecture and the overall development of the website.

As a result, the online ticket sales increased to 60% - no more waiting room - and all the digital content and user experience improved thanks to the robust framework and work methodology stablished by the digital media team.

I also developed an app to display the schedule of the Royal Ballet rehearsals in TV screens

Technologies used (in no particular order): HTML5, CSS3, Javascript, jQuery, PHP5, MySQL, Apache, Zend Framework, Doctrine ORM, Scrum, Trac, Agile, XSLT, Flickr API, Youtube API, Delicious API, Restaurant Diary API, Facebook API, SoundCloud API, Google+ API, QAS API (UK address validation), Wordpress (including plugin dev.), CDN, SSH, SSL, SQL injection, XSS, Varnish, APC, SOAP, REST, Basecamp, Confluence, Jira, Semantic markup, Domain-driven design, Open Data (XML, JSON, RDF, RSS, ATOM, ICS), Linux (Ubuntu 11), Windows7, Firebug, IE, Firefox, Opera, Chrome, Safari, ODBC, MS SQL Server 2008 (TSQL), Amazon AWS (EC2, SES, IAM, CloudFront, S3,…), Rackspace, Tessitura, IIS, Isapi Rewriter, WinSCP, Tortoise, SVN, Putty, Netbeans, Eclipse,…

Relevant articles:

roh dev team
With my co-workers, Aaron and Jamie

Read the full ROH case study

Co-founder, CTO & Web developer

Sep 2006 - Jul 2012Webmarket S.C.Alicante (Spain)

Co-founded a small digital agency specialised in design and development of multimedia applications and websites based on Adobe Flash (AS2), MdM Zinc, Wordpress and front-end technologies.

Brands we worked for: Estrella Galicia, Santillana, Editex, Philippines government, Grupo Soledad, IBCmass, Cogersa, Digital Toy Shop, IES Miguel Hernández, etc

Some of the bespoke products we created:

  • TiendaFlash: a Flash, AMFPHP& MySQL e-commerce CMS with unlimited products, VISA/Master Card and Paypal integration
  • InmoFlash: a Flash, AMFPHP& MySQL real-state CMS with unlimited properties
  • FinanFlash: a Flash, AMFPHP& MySQL finance CMS with dynamic PDF generator (FPDF)

We also provided web hosting with cPanel/WHMCS and digital marketing services to our clients (mainly SMEs) and collaborated with other freelance designers, developers and agencies in Spain.

Web design teacher

Feb 2009 - May 2009ESUMAAlicante (Spain)

Web design teacher in the Master of Marketing and Advertising of ESUMA

Joomla web designer / developer

Mar 2008 - Sep 2008WebempresaBarcelona (Spain)

Web development and design using Dreamweaver, Fireworks, Photoshop, Joomla CMS, Joomla Components, HTML, CSS, PHP, MySQL, JavaScript and Google Apps.

Some of the projects I worked on include: Escuela de cocina Hoffman, Hoyesarte.com, Gimnasio femenino 30 minutos, Aarcs, Altair consultores, Aurall, Aitor Aurrekoetxea, Baldirialeu, Dimas, BGT Musics, Fama Systems, Geograma, Infolimpieza, Lluisa Sallent, Lodisoft, LOPDYA, Segurodelhogar, Torques, Noelia Compte, Trabajos y reformas, Mongrafic, Norma3, NRC Courier, Orbitel, Lexicos traducciones, Agrocesped, ByPerson, Circulo hostelero, Training home,…

Web designer / developer

Sep 2001 - Sep 2006FreelanceMúltiple locations

Freelance web design and development for local SMEs using Frontpage, Photoimpact, Sound Forge, Power Director, Premiere, Dreamweaver, Fireworks, Photoshop, Freehand, Flash, ActionScript 1 and 2, XML, HTML, CSS, PHP, MySQL, JavaScript and PHP-Nuke.

Software Engineer

Sep 2003 - Jul 2005Slater Software Laboratories S.L.Cuzco, Madrid (Spain)

Participated in the development of three desktop applications for real-time TV production, from initial conceptualisation to final development (HP business partner). Based on C++, QT, DirectX 9 and other API’s.

Headed the development of the audio and video mixers (major features in these applications) to support high quality computer media formats, capture cards, cameras, image projection systems and other audiovisual devices.

Solid experience in C++ OO programming, QT 3.2, DirectX 9 (DirectMusic, DirectAudio, DirectShow, DirectInput), ASIO 2.0, analog-digital television production systems, DSP, image projection systems, MS Visual Studio 2003 and Source Safe.

Working experience in DSP (Sound effects, spectrum analysers, Oscilloscopes, sound editing programming, multi Channel (I/O) audio engines.

IT computer technician

Oct 2001 - Jul 2002PC City Sverige ABAlicante (Spain)

IT support for customers and custom builds of desktop computers

CTO & Network Administrator

Sep 2001 - Nov 2001Times CafeAlicante (Spain)

Designed a technical implementation for a local area network in a cyber coffee shop. Purchased the equipment and software. Installed all the machines and programs. Managed the day to day computer rental operations and maintenance.

Junior web designer / developer

May 2001 - Aug 2001Grupo Odessa S.L.San Juan, Alicante (Spain)

Built websites for SMEs using XHTML, CSS, Flash 5, Photoshop and Javascript

Computer technician

Jan 2000 - May 2000BEEPAlicante (Spain)

IT support for customers, retail assistant and custom builds of desktop computers

Computer technician

Oct 1999 - Jan 2000NecomplusAlicante (Spain)

IT support to update the company software installed on the customers machines to avoid the “Y2K effect”.

Education

BA & Sc in Multimedia, minor in web engineering (4 years)

Oct 2006 - 2017Universitat Oberta de CatalunyaOnline (4 years, 240 ECTS)

Homologated in the EU. Euro-Inf certified. 60 ECTS = 1700 hours

Multimedia foundations, Video, English I, II, Programming, Mathematics I, II, Interactive narrative, Information architecture, Administration and management of organisations, Languages ​​and Web Standards, Graphic Design, Image and visual language, Web Programming, 3D graphics, Physics, Animation, Design of interfaces, Integrating digital content, Networks, Database Design, Interactive Media, Processing and publication of image and video, Audio editing and publishing, Digital composition, Project Management, Market and legislation, Methodology and project development, Creativity and aesthetics, Digital Photography, Advanced Web Programming, Safety and quality in web servers, User Testing, Usability, Virtual Reality, Interaction Design, Content Management Systems, Publication and distribution platforms, Audiovisual documentation, Software Engineering, OO Design and programming, Analysis and design patterns, Entrepreneurship of organisations.

Certificate in profesional videogames creation (1 year)

Oct 2002 - Jun 2003Universitat Pompeu FabraBarcelona (Spain)

C++, OpenGL, Direct3D, Quadtree, Octree, PVS, Clipping with LOD’s, BSP’s, Portals, ROAM and 3D Studio SDK, IA (FSM, DFA and FA programming experience. Syncronized IA’s programming using Rules Sytem. Theoretical Knowledge in Boids algorithm and Path Finding A*), Gameplay programming (Coldet), Motion Capture systems, Scripting with LUA, Skeletton animation, Cal3D. Working Knowledge in EAX HD 4.0, BASS, PortAudio and FMOD

HND in Computer Science (2 years)

Oct 1998 - Jun 2000Instituto Mare NostrumAlicante (Spain)

Pascal, Assembler, Cobol, Delphi, SQL (Access), C, OO programming, Linux, Network Management, Business Administration, English language

High School Diploma (3 years)

Oct 1994 - Jun 1997IB Bahía BabelAlicante (Spain)

Courses, events, conferences and certifications

  • Sep 2018: React Alicante, Spain
  • Jun 2018: Alicante Frontend: agile development in real life
  • Dec 2017: Alicante Frontend: codePen official meetup
  • Sep 2017: Alicante Frontend: optimal way of loading images on the web
  • Sep 2017: React Alicante, Spain
  • Sep 2017: FullStackFest Barcelona, Spain
  • May 2017: JSDayES Madrid, Spain
  • Feb 2016: HackerRank - 7 Days of JavaScript
  • Feb 2016: Introduction to Meteor.js Development, University of London (Coursera)
  • Feb 2016: Learn and Understand AngularJS (Udemy)
  • Jan 2016: Build Web Apps with React JS and Flux (Udemy)
  • Jan 2016: JavaScript: Understanding the Weird Parts (Udemy)
  • Oct 2015: FullStack conference, London
  • Oct 2015: Big Data, University of San Diego, California (Coursera)
  • Jul 2015: Harry Roberts (CSSWizardry) workshop
  • Aug 2015: British Airways Open Day 2015
  • Mar 2015: Reasons to be creative. London, Old Street
  • May 2014: jQuery UK 2014, Oxford
  • Apr 2014: Sapient Advanced Presentation Skills
  • Apr 2014: London JS Night Class: CSSFlex
  • Several dates: EmberJS & AngularJS meetups
  • Mar 2014: London JS Night Class: D3.js with Tim Ruffles
  • Mar 2014: London JS Night Class: BackboneJS
  • Mar 2014: Sapient MEP (Negotiating expectations)
  • Feb 2014: White Pencil & Swam. Climate Change President Lecture - Geek Out
  • Feb 2014: jQuery Conference in Oxford. AngularJS workshop with Peter Bacon Darwin
  • Nov 2013: Full Frontal 2013. Debug workshop with Remy Sharp
  • Nov 2009: iWeekend Alicante 2009 (40 hours)
  • Sep 2007: UA, Advanced Flash 8, Web development (8 hours)
  • Nov 2006: Certified Macromedia Flash MX 2004 designer
  • Oct 2003: DeepBlue TV production workshop
  • Feb 2002: Advanced Shaders (cg) programming
  • Mar 2002: Business Management of the videogames industry, ArtFutura Festival - Ubi Soft

Recognitions

  • June 2018: Top performer. Recognised by my line manager as one of the two awarded top performers in a team with dozens of employees at Vodafone Global Enterprise

  • May 2017: Winner of the Knowledge Management Innovation award. One of the apps that my team and I developed, won this prestigious award in the UK legal industry. eiseverywhere.comlegalweek.com

  • January 2017: EduTECH Emprèn. My final project was selected and I was granted a course financed by the Catalunya and EU governments for mentoring entrepreneurs and accelerate their eLearning projects

  • November 2016: Recognised by my line manager with the innovation award at Vodafone Global Enterprise

  • February 2014: the Art Rules project were I was heavily involved in the front-end was shortlisted for a prestigious FWA award

The following are some recognitions from my former co-workers, partners and clients. Some of them know me as “Pach” (my nickname).

Core Value: Creativity Nominator: Marisa Parsons (UX Manager at SapientNitro) Date: 8-Jan-2016

“Joan is a talented developer with creative flair. Working with him is always a pleasure even when there are tight timelines and tricky pages to build. Joan always embraces challenges with a smile on his face and determination to find a solution. Through his experimentation with code, attention to detail and dedication to crafting elegant solutions, he is an invaluable member to any creative team.”

Core Value: Creativity Nominator: Owen Cowdry (Senior Developer at SapientNitro) Date: 28-Nov-2015

“Pach is a top quality developer. This guy has been working with computers and programming for a very long time. He has run his own web development and hosting agency. His programming experience spans both front-end to back-end. His love of art and creative thinking drives his passion for creative technology. As if that wasn’t enough, he’s lovely chap, very easy to get along with. I would jump at the chance to work with Pach again, so should you!”

Core Value: Creativity Nominator: Denise Neves Santos (Manager of Interactive Development at SapientNitro) Date: 26-Oct-2015

“Joan is an extremely talented developer and technologist: no technology is a problem! Whether you are looking for a Vanilla JS, Angular, ReactJS, [insert library/framework/tech here], I’m positive Joan will deliver it, high quality, on time.

His knowledge and attitude makes him one of the best developers I had the pleasure to work with, as he’s not only committed to the quality of the code, but to the overall delivery of the project, which can make all the difference when delivering large-scale projects. Having Joan in the team is a joy, I wholeheartedly recommend Joan.

Joan is also a very good fußball player, although not as good as myself :)”

Core Value: Leadership Nominator: Hadleigh Smith (Account Director at SapientNitro) Date: 30-Sep-2015

“I brought Pach (Joan) on board to work on Dove 2.0, having worked with him previously on BT. Pach was part of a front-end development team of seven people, and very early in the project you could see that Pach was a front-runner and was willing to lead the team. In the end we split the development and build work in to two tracks, and asked Pach to lead one of them. From start to finish Pach was calm, lead from the front, was a problem solver, and helped deliver the project with minimal defects and on time. His qualities were also recognized by the wider team and he became a trusted and valuable member of the overall delivery.”

Core Value: Creativity Nominator: Marisa Parsons (UX Manager at SapientNitro) Date: 30-Sep-2015

“I would like to nominate Joan for his work on the Dove project. Working with him on this project we had tight timelines and tricky pages to try and build but Joan always embraced these challenges with a smile on his face and a determination to find a solution to the design teams requests. Not only is he a talented developer he also brings his own creative flair to a build. Through his experimentation with what was possible with code, his attention to detail and dedication to crafting elegant solutions he made an invaluable contribution to the animations and interactions of the new Dove site.”

Core Value: Leadership Nominator: Daniel De Oliveira (Senior Interactive Developer at SapientNitro) Date: 29-Sep-2015

“I’ve had the pleasure of working with Pach on the recent Dove 2.0 project, during this time he has gone above and beyond what was asked of him. He remains calm and focused in stressful situation and is brilliant at managing other developers. The team looks to him for guidance and he as show true leadership qualities. His knowledge on all things digital and the industry make him a valuable asset in any team. Pach is a agile master!”

Core Value: Creativity Nominator: Yandis Ying (Creative Director at SapientNitro) Date: 29-Sep-2015

“Pach is a very creative and design-aware developer, his motion coding skills is unreal and really had inspired the UX, Design and his FE team digital team and of course clients. As a person he is so easy to work with for he’s polite, well mannered and focussed on getting the job done. He had lots of great ideas which really add values to the experiences. He created the ‘Curtains Up’ motion transition on the Dove 2.0 homepage which everyone in the team and the clients love. Pach’s contagious enthusiasm contribution making my time on Dove 2.0 a delight. I am sure everyone will agree that it was truly a pleasure working Pach!”

Core Value: Creativity Nominator: Angie Yuanmalai (Design Manager at SapientNitro) Date: 17-Sep-2015

“For me creativity is the ability to solve a problem but in a way that delights people in new and different perspectives. We tend to forget that creativity takes on many forms and in this case, Pach has rightfully reminded me so. Pach has been an absolute joy to work with. Where an animation or difficult task is presented, the usual response from developers would be a quizzical look and a shake of the head. Pach has been nothing but enthusiastic to tackle animations and other challenges full on, constantly coming up with better, improved solutions to the code and researches and suggests his own ground breaking ideas on animations and possible renditions to the creative work. On top of this, he has stepped in as a wonderful and reliable leader within the team and displayed commendable organisational and management skills. Finding a developer than can code exceptionally is very, very difficult, but finding one that also has wonderful people and leadership skills that greets problems with smiles is practically impossible - I’m so glad we’ve got Pach in the company. He has been an invaluable asset to the team and I couldn’t stop singing his praises. If anyone deserves this award it would definitely be Pach.”

Core Value: People Growth Nominator: Shaun Wallace (Senior Developer at SapientNitro) Date: 01-Dec-2014

“I have only been a part of the development team here in London for a few weeks but I have seen on multiple occasions Joan’s committed efforts in building up and training others within our team. He has worked hard to share his level on knowledge with others more junior than himself while remaining teachable and working to grow his own skills. He continues to provide important feedback with regards to developmental processes and the work of others. I have seen his effort over the last few weeks, even while on the bench, enable others to learn and grow in their skills and he has brought people into his research efforts and helped to grow our team.”

Core Value: Client focus delivery Nominator: Josep Manen (Artist and Sound Designer at TensionStudio) Date: 04-Oct-2015

“There is a special thing that I love from Joan, he is extremely amazing caching the fist idea from your project included in a difficult steps, changes or corrections. Your company will be blessed with an amazing programmer.”

Core Value: Client focus delivery Nominator: Jose Luis Marron (Account Director at Narcea Multimedia) Date: 22-Feb-2009

“He is a great person to work with, always gets the work done and on time. I will hire him again for other projects.”

Core Value: Creativity Nominator: Tuesday Gutierrez (Art blogger at Momardi.com) Date: 29-Sep-2008

“Joan is a multimedia guru. Always pushing the boundaries of his pixel-focused mind, Joan never runs out of creative ideas and the enthusiasm to get things done. He is full of passion for his craft.”

Core Value: Client focus delivery Nominator: Carlos Ocaña (Graphic designer at Slater Labs) Date: 30-Sep-2008

“Joan es una persona seria y responsable, ante la aparición de cualquier problema o duda no para hasta obtener la solución al mismo. En definitiva es una persona con gran talento.”


Statistics

$
0
0
Last updated on January 2019

Audience overview

  • The average number of unique users per month is 4.000
  • The average number of page views per month is 6.000
  • The average session duration is 55 seconds
  • 70% of the users speak Spanish and 25% English
  • 80% of the traffic comes from organic search, 15% access directly and 5% from referrals

Most popular pages

  1. /las-50-mejores-peliculas-de-los-anos-80/ (38%)
  2. /1001-pelis-para-ver-antes-de-morir/ (23%)
  3. /tutorial-build-a-weather-app-with-react/ (8%)
  4. /open-source-lms-with-react-and-node-js/ (7%)
  5. /vuejs-first-impression-and-how-to-work-with-svgs/ (5%)
  6. / (4%)
  7. /how-to-set-up-a-react-es6-app-for-production-on-ubuntu/ (2%)
  8. /peliculas-sobre-mongolia-que-tienes-que-ver/ (1%)
  9. /50-animes-para-ver-this-summer/ (1%)
  10. /a-few-more-vuejs-2-tweaks-for-the-beginners/ (1%)

Page audit

page speed report

Page audit provided by Google Lighthouse

La Ruta del Samurái (The Samurai Route)

$
0
0

Launch archived website

In January 2010 I had a crazy idea: to travel by motorbike from Spain to Japan in 3 months (around 20.000Km) and then spend 2 months travelling around Japan. We called it “La Ruta del samurai” (The Samurai Route).

I’ve been riding motorcycles since I was 17 but never really travelled long distances with one of them, not even 500 Km!. I also wanted to explore my limits, get away from the computer for some time, feel more in contact with nature and of course, visit Japan!

I passed the exam for the “big motorcycles” license and bought a Yamaha XT660Z Teneré. It wasn’t my favourite model, but at the end, it turned out to be a great choice for that kind of trip. I spent a few months preparing the trip, found some kind sponsors and a partner. Finally, on June, I left my hometown and started this great adventure :-) [ view pictures ]

1
Loading the bike in Tokyo, ready to start the trip and the project's logo

There are also a few blog entries related with the trip (in Spanish)

Loading the bike in Tokio
Loading the bike in Tokyo

Entrevista en Radio Euskadi

Reportaje de TV Giralda

Sponsored by

sponsors

Bagster designs and manufactures increasingly practical and innovative items for motorcycle travels. Trades in virtually 100% of the outlets and facilities for motorcycles. For the Samurai Route, Bagster sponsored us with mittens, deposit bags and backpacks.

Winter Mountain / Casbas Creations is the 6th Generation of mountain clothing fashion designers and manufacturers. They produce garments for the best and most representative firms nationally and internationally, such as Mango, Nike, Kikers, Trango among others. Blog post about the sponsorship

Explora Sur is a shop with items for: climbing, caving, canyoning, hiking, cycling and running, textile, camping, etc. They are totally reliable and have very good prices. The best that can be found on the Internet!

Pionono creates delicious treats that cannot be explained. You have to try them!. They are proud to offer a home-made craft product of Santa Fe, Granada. Check the promo video for the Samurai Route.

Midland is the famous company behind the Bluetooth Walkie intercom that we used and gave us everything we needed! GPS connection, Walki, telephone, MP3, PMR446 and PTT.

Roerich Museum House is managed by Leonardo and Petri. They maintained it with great effort since the non-profit ADA Roerich Association was founded in 1997. Its objective is to bring inspiration, beauty, contemplation and education about the Roerich to the current society. They are leaders in Spain in the Roerich culture and philosophy and their success depends on the good will of those who have awakened the vision, understanding and compassion. This is the challenge today. If you appreciate their efforts will understand the need for extensive financial support from those who are committed to peace, service and culture of synthesis. Your contribution will be well used and gratefully received. Thank you.

The council house of Coria del Rio helped us prepare the trip. They also gave us a gift and a letter for the council of the Japanese city of Sendai.

EstampAlicante specializes in t-shirt printing and provided the official Samurai Route t-shirts, available is the following sizes: XS, S, M, L and XL.

Altaïr helped us promote the Samurai Route story and gave us copies of the magazine.

Km Zero provided us with maximum coverage motorcycle insurance in Russia and Mongolia. They also offered us a large space in their magazine to publish promote the adventure and gave us some shirts, anti-puncture foam, patches for clothing, backpacks, scarves, earplugs,…

Privacy policy

$
0
0

Privacy matters but it can be confusing. This page explains my approach to privacy on all my websites and how it affects you.

Short version

  • I collect anonymous statistics about your visit, like which of my pages you viewed.
  • Some 3rd parties like Facebook, Twitter and Disqus may know you visited this website, if you use their services. I can’t control them but I don’t believe this knowledge poses any threat to you.
  • If you sign up with me, I take great care to keep your information safe and I’ll never share it with others without your express permission.
  • I never share your data with 3rd parties except to help me deliver my own services.

These are just the key points. If you need detail, keep reading.

Measuring the visitors

I measure visitors to my website using Google Analytics. This records what pages you view within my site, how you arrived at my site and some basic information about your computer. All of that information is anonymous – so I don’t know who you are; just that somebody visited my site.

The information I collect from analytics helps me understand what parts of my sites are doing well, how people arrive at my site and so on. Like most websites, I use this information to make the website better.

You can learn more about Google Analytics or opt out if you wish.

Facebook, Twitter and other social networks

These services provide social buttons and similar features which I use on my website – such as the “Like” and “Tweet” buttons.

To do so, I embed code that they provide. Their buttons generally know if you’re logged in; for example Facebook sometimes say “x of your friends like this”. I do not have any access to that information, nor can I control how those networks use it.

Social networks therefore could know that you’re viewing this website, if you use their services (that isn’t to say they do, but their policies may change). As my website is remarkably inoffensive, I imagine this is not a concern for most users.

Discussion comments

To allow visitors to discuss my blog articles and some web pages, I use a discussion system called Disqus.

I embed code that Disqus provide and I cannot control it. Disqus anonymously tracks visitors to pages like I do. They also remember who you are if you login to any Disqus service, so you can comment on any website using their tool.

Logging in to Disqus can be done in many ways, including via Facebook. If you login via social network, Disqus will be able to link your activity to that network. In this way, your Disqus activity may be personally identifiable.

Disqus will know what pages you viewed in my site and what you wrote on those comments. Of course all comments you leave are also publicly visible on the Internet alongside your name, so I do not imagine this is a concern for many people.

If you sign up for the newsletter

When you sign up for my newsletter, I will record specific personal information about you, such as your name and email address.

You have the ability to opt out of any of this communication at any time.

I will never provide your personal information or email address to any third parties except where they are specifically employed to help deliver my own service, as detailed above.

Updates to this policy

I may update this privacy policy from time-to-time, particularly as technology changes. You can always check this page for the latest version. I may also notify you of changes to our privacy policy by email.

Any questions?

If you have any questions about this privacy policy or your personal data, please write to me by email to hello [at] joanmira [.] com.

Things I would like to do

$
0
0
  • Ride a motorcycle in a track
  • Create a funny, long video game
  • Exhibit a beautiful art installation in a gallery
  • Build a useful mobile app
  • Write a book
  • Work on a great open source project
  • Embark on an epic motorcycle adventure (done)
  • Ride in another long motorcycle trip :-)
  • Drive a classic car in California
  • Be able to have conversations in Japanese (working on it)
  • Be a great programmer (working on it)
  • Work in Google
  • Live somewhere outside Spain (done)
  • Visit Japan (done)
  • Have my own cat
  • Finish watching the 1001 movies to watch before die (working on it)
  • Build a website with high traffic (done)
  • Visit California, Singapore, Australia and HongKong
  • Work in a big company (done)
  • Work in a start-up (done)
  • Create my own company (done)
  • Develop an interest in keep learning new things every day (done)
  • Climb Fuji san (almost done)
  • Work in a Japanese company
  • Live more than one year in London (done)
  • Live more than one year in USA
  • Live more than one year in Japan
  • Live more than one year in Singapore
  • Finish my university degree (done)
  • Be comfortable with 2d and 3d maths and physics (working on it)
  • Produce a movie
  • Make my own wine
  • Start a company related with motorcycles
  • Be in zero gravity
  • Build my own motorcycle
  • Know how to take the best photo on every situation (working on it)
  • Master the english language (working on it)

Credits and tech stack

$
0
0

Like other creative people, I get inspiration from many different sources: art, music, cinema, science, computers, technology, etc. My work and artistic expression is an elaborate interpretation of these things - sometimes it can be a slight modification or a pure integration into another module or piece. Other times it can be the canvas from where I start to create. In any case, I am grateful to credit the authors and share their valuable work with everyone.

Viewing all 270 articles
Browse latest View live