74
ORGANIZANDO O Nando Vieira http://nandovieira.com.br JavaScript

Evento Front End SP - Organizando o Javascript

Embed Size (px)

DESCRIPTION

PDF do evento de Front-end São Paulo. Disponibilizado pelo site http://tableless.com.br. Palestra do Nando Vieira @fnando

Citation preview

Page 1: Evento Front End SP - Organizando o Javascript

ORGANIZANDO O

Nando Vieira http://nandovieira.com.br

JavaScript

Page 2: Evento Front End SP - Organizando o Javascript

@fnando

[email protected]

nandovieira.com

Page 3: Evento Front End SP - Organizando o Javascript

http://hellobits.com

Page 4: Evento Front End SP - Organizando o Javascript

http://howtocode.com.br

howto.

Page 5: Evento Front End SP - Organizando o Javascript

http://codeplane.com.br

Page 6: Evento Front End SP - Organizando o Javascript
Page 7: Evento Front End SP - Organizando o Javascript

JavaScriptÉ, atualmente, uma das linguagens de programação mais importantes do mundo.

Page 8: Evento Front End SP - Organizando o Javascript

Dos 10 repositórios mais populares do Github, 7 repositórios* são relacionados a JavaScript.*twitter bootstrap, node.js, jquery, html5 boilerplate, impress.js, backbone.js, chosen.

Page 9: Evento Front End SP - Organizando o Javascript

FamaMas mesmo com essa explosão, ainda temos códigos muito ruins.

Page 10: Evento Front End SP - Organizando o Javascript

DicasVocê verá algumas dicas que podem ajudar a escrever códigos melhores, e torná-lo um *rockstar.

*Embora isso seja possível, não é uma garantia. Além disso, é melhor ser um profissional que rockstar.

Page 11: Evento Front End SP - Organizando o Javascript

#1 Aprenda JavaScript

Page 12: Evento Front End SP - Organizando o Javascript

JavaScriptUma linguagem extremamente poderosa e flexível.

Page 13: Evento Front End SP - Organizando o Javascript

Conheça a linguagem*Saiba closures, funções, escopo de variáveis, this e como modificá-lo, pseudo-orientação a objetos, prototype e, provavelmente, muito mais coisas.

*Ninguém disse que a vida seria fácil. Quando você decidiu se tornar um desenvolvedor web, assumiu o compromisso de não se tornar um dinossauro.

Page 14: Evento Front End SP - Organizando o Javascript

*jQuery não é JavaScriptÉ apenas um framework que abstrai e facilita a manipulação do Document Object Model.

*Quero morrer quando pergunto para alguém se ele sabe JavaScript e a resposta é “Eu sei jQuery”. Pretty... jQuery não é JavaScript!

Page 15: Evento Front End SP - Organizando o Javascript

Aprenda a linguagemEla não é uma linguagem tão grande e difícil como você pensa.

Page 16: Evento Front End SP - Organizando o Javascript

http://developer.mozilla.org

Page 17: Evento Front End SP - Organizando o Javascript

http://howtocode.com.br

Page 18: Evento Front End SP - Organizando o Javascript

http://w3scho... melhor não!

Page 19: Evento Front End SP - Organizando o Javascript

http://w3fools.com

Page 20: Evento Front End SP - Organizando o Javascript

#2 JavaScript Patterns

Page 21: Evento Front End SP - Organizando o Javascript

Patternsvs

Standards

Page 22: Evento Front End SP - Organizando o Javascript

Patterns não são regras.São apenas repetições conhecidas que podem ser documentadas.

Page 23: Evento Front End SP - Organizando o Javascript
Page 24: Evento Front End SP - Organizando o Javascript

Module patternPermite emular a visibilidade de métodos e atributos.

Page 25: Evento Front End SP - Organizando o Javascript

var Counter = { count: 0 , increment: function() { this.count += 1; } , decrement: function() { this.count -= 1; } , reset: function() { this.count = 0; }};

O atributo Counter.count pode ser manipulado indiscriminadamente.

Page 26: Evento Front End SP - Organizando o Javascript

A variável `count` só pode ser manipulada através de nossa API pública.

var Counter = (function(){ var count = 0;

return { increment: function() { count += 1; } , decrement: function() { count -= 1; } , reset: function() { count = 0; } , count: function() { return count; } };})();

Page 27: Evento Front End SP - Organizando o Javascript

Module patternPermite injetar dependências.

Page 28: Evento Front End SP - Organizando o Javascript

<script type="text/javascript" src="jquery.js"></script>

<script type="text/javascript"> jQuery.noConflict();</script>

<script type="text/javascript" src="jquery.plugin.js"></script>

Page 29: Evento Front End SP - Organizando o Javascript

$.fn.plugin = function() { // do something};

jQuery.noConflict() restaura o valor anterior da variável global $.

Page 30: Evento Front End SP - Organizando o Javascript

Injetando o jQuery como dependência garantimos o funcionamento do plugin.

;(function($){ $.fn.plugin = function() { // do something };})(jQuery);

Page 31: Evento Front End SP - Organizando o Javascript

Facade patternPermite criar APIs mais simples e desacopladas, abstraindo a implementação original.

Page 32: Evento Front End SP - Organizando o Javascript

// jquery$("p").css({color: "red"});

// mootools$$("p").setStyle("color", "red");

// prototype$$("p").invoke("setStyle", {color: "red"});

// dojotoolkitdojo.query("p").style({color: "red"});

Page 33: Evento Front End SP - Organizando o Javascript

function dom(selector) { this.selector = selector;};

dom.prototype.css = function(style) {};dom.prototype.remove = function() {};dom.prototype.addClass = function(className) {};dom.prototype.removeClass = function(className) {};

dom.find = function(selector) { return new dom(selector);};

exemplo utópico

Page 34: Evento Front End SP - Organizando o Javascript

Não importa qual framework você esteja usando, a API foi abstraída.

dom.find("p").css({ color: "red"});

Page 35: Evento Front End SP - Organizando o Javascript

A abstração pode ser extremamente complexa e trabalhosa.

dom.find("p").css({ color: "red"});

Page 36: Evento Front End SP - Organizando o Javascript

Mediator patternFaz a intermediação entre diferentes componentes, de modo que eles possam interagir indiretamente.

Page 37: Evento Front End SP - Organizando o Javascript
Page 38: Evento Front End SP - Organizando o Javascript

var Chat = {};Chat.channel = new Channel();Chat.participants = new Participants(Chat.channel);Chat.messages = new Messages(Chat.channel);Chat.inputMessage = new InputMessage(Chat.channel);Chat.connection = new Connection(Chat.channel);

Page 39: Evento Front End SP - Organizando o Javascript

function Participants(channel) { this.channel = channel; // Listen to the connected signal and add a new // user to the participants list. this.channel.on("connected", this.onConnected); // Listen to the disconnected signal and remove // user from the participants list. this.channel.on("disconnected", this.onDisconnected);}

Page 40: Evento Front End SP - Organizando o Javascript

function Messages(channel) { this.channel = channel; // Listen to the new message signal and add message // to the list. this.channel.on("new message", this.onNewMessage); // Listen to the connected signal and tell everybody // that somebody has joined the room. this.channel.on("connected", this.onConnected);}

Page 41: Evento Front End SP - Organizando o Javascript

function InputMessage(channel) { this.channel = channel;}

InputMessage.prototype.send = function(message, user) { // Send message through WebSockets maybe // Then notify that a new message has been sent this.channel.publish("new message", message, user);};

Page 42: Evento Front End SP - Organizando o Javascript

function Channel() { this.events = {};}

Channel.prototype.on = function(event, callback) { this.events[event] || (this.events[event] = []); this.events[event].push(callback);};

Channel.prototype.publish = function(event) { var args = [].slice.call(arguments, 1); this.events[event] || (this.events[event] = []); this.events[event].forEach(function(callback){ callback.apply(null, args); });};

Page 43: Evento Front End SP - Organizando o Javascript

Uma coisa de cada vezO seu código deve fazer uma coisa de cada vez e deve fazê-la bem!

Page 44: Evento Front End SP - Organizando o Javascript

"invite_friends" : function() { var resizeLoader = function() { $("#loader").css("width", $(".places").width()); $("#loader").css("height", $(".places").height()-18); } resizeLoader(); var resizeTimer; $(window).bind('resize', function() { clearTimeout(resizeTimer); resizeTimer = setTimeout(resizeLoader, 50); }); $("a[href=#automatic_invite]").click(function(e){ SomeApp.utils.stopPropagation(e); if(!$(this).parents(".tab_title:first").is(".active")) { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } }); var suffixes = { "gmail": "@gmail.com", "yahoo": "", "live": "@hotmail.com", "other": "" }; // reset fields (firefox)

$('#service-suffix').html(suffixes['gmail']); $("p#service_instructions").addClass("hidden"); $("#service-select").addClass("hidden"); // add radio button events // when is clicked, should change e-mail suffix and // change fieldset class // shows or hides warning message and dropdown on 'others' service $("#services :radio").click(function() { $("#service-suffix").html(suffixes[this.value]); $("#services fieldset").attr("class", this.value); $("p#service_instructions").addClass("hidden"); $("#service-select").addClass("hidden"); if(this.value == "yahoo") { $("p#service_instructions").removeClass("hidden"); } else if (this.value == "other") { $("#service-select").removeClass("hidden"); } }); // set submit event $("#retrieve-list-button").click(function(){ var user = $('#user').val(); var pass = $('#pass').val(); var service = $('#services :radio:checked').val(); if (!user || !pass) { SomeApp.utils.message("warning", "Você precisa informar seu usuário e senha."); return; } // display logos $('img.service-logo').addClass('hidden'); $('img.' + service).removeClass('hidden'); // build email // gmail, yahoo, hotmail (live), others if (service == "live") { var email = user + suffixes[service]; } else if (service == "yahoo") { if (user.indexOf('@') == -1) { SomeApp.utils.message('warning', 'Você precisa informar um email do Yahoo! valido!'); return; } else { // check if we're handling real Yahoo! emails var regex = /\@((yahoo)|(ymail))\..+/ if (!regex.test(user)) { SomeApp.utils.message('warning', 'Você precisa informar um email do Yahoo! valido!'); return; } else { var email = user; } } } else if (service == "gmail") { var email = user + suffixes[service]; } else { // other services var email = user + suffixes[service]; } $("#loader").removeClass("hidden"); resizeLoader(); $("#loader-message").text("Estamos carregando sua lista de contatos e este processo pode demorar um pouco."); $.ajaxSetup({timeout: 60000}) // syncronize with grabber (time in m$) $.getJSON("/async/contacts", {email: email, password: pass}, function(data){ // any error if (!data) { SomeApp.utils.message('error', 'Não foi possível carregar os contatos. Por favor, tente novamente mais tarde.'); $('#loader').addClass('hidden'); return; } // request returned false if (!data.success) { SomeApp.utils.message('error', data); $('#loader').addClass('hidden'); return; }

// user is not logged if (SomeApp.utils.requireAuth(data)) { $('#loader').addClass('hidden'); return; } // got no contacts, probably user provided invalid credentials if (!data.contacts) { $('#loader').addClass('hidden'); SomeApp.utils.message('warning', data); return; } // got no contacts at all if (data.contacts.length == 0) { $('#loader').addClass('hidden'); SomeApp.utils.message('warning', 'Sua lista não possui nenhum contato.'); return; } $('#loader, #services-block').addClass('hidden'); $('#invite_list').removeClass('hidden'); var contacts = ""; var labels = { 'SomeApp_friend': 'usuário SomeApp já adicionado como amigo', 'SomeApp_user': 'usuário SomeApp', 'none': 'não é usuário SomeApp' } var total_contacts = data.contacts.length; var current_permalink = null; var used_permalinks = {}; for(var i = 0; i < total_contacts; i++) { var contact = data.contacts[i]; var css_status = contact.status; var li_id = ""; var permalink = (contact.permalink == "")? "outros" : contact.permalink;

used_permalinks[permalink] = true; if (contact.status == "none") { css_status = 'new_user'; } if (current_permalink != permalink) { current_permalink = permalink; li_id = 'id="' + permalink + '"'; }; contacts += '<li ' + li_id + ' class="clearfix ' + css_status + ' ' + permalink + '">\ <span class="user_name" title="' + contact.name + '">\ <input type="hidden" name="contacts[' + i + '][name]" value="' + contact.name + '" />\ <input type="hidden" name="contacts[' + i + '][email]" value="' + contact.email + '" />\ <input type="hidden" name="contacts[' + i + '][status]" value="' + contact.status + '" />\ <input type="checkbox" name="selections[]" value="' + i + '" checked="checked" ' + ((css_status == 'SomeApp_friend') || (css_status == 'SomeApp_user' && $('#invite-with-question').val()) ? 'disabled="disabled" style="visibility:hidden" ' : '') + ' />\ <label>' + contact.name + '</label>\ </span>\ <span class="email" title="' + contact.email + '">' + contact.email + '</span>\ <span class="user_type icon_sprite" title="' + labels[contact.status] + '">' + labels[contact.status] + '</span>\ </li>'; }; // disable sidebar links without correspondent items var items = ["outros", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

for (var i = 0; i < items.length; i++) { var item = items[i];

if (!used_permalinks[item]) { var span = '<span>' + $('#found_users_alphabet_list li.' + item + ' a').text() + '</span>'; $('#found_users_alphabet_list li.' + item) .addClass('no-items') .html(span); } }

// inject html $('#contacts-list').html(contacts); // set found contacts total var possible_connections = $('#contacts-list li').not('.SomeApp_friend').length; $('#total-contacts').html(possible_connections); // set boxes event $('#contacts-list :checkbox').not('[disabled]').click(function() { var total_selected = $('#contacts-list :checkbox:checked').not('[disabled]').length; var text = total_selected + ' contato(s)'; $('#total-selected-contacts').html(text); $('#select_SomeApp').removeAttr('checked'); if (total_selected == total_contacts) { $('#select_all').attr('checked', 'checked'); } else { $('#select_all').removeAttr('checked'); }; }); $('#total-selected-contacts').html($('#contacts-list :checkbox:checked').not('[disabled]').length + ' contato(s)'); $('input.send-invitations').click(function(){ $('#loader').removeClass('hidden'); resizeLoader(); $("#loader-message").text("Estamos enviando convites para os amigos selecionados. Por favor, aguarde."); var send_data = $('#contacts-form').formSerialize(); $.post('/users/invite_friends', send_data, function(data){ // try to parse the response as json try { var data = $.parseJSON(data); } catch (e) { var data = false; } // hide loader $('#loader').addClass('hidden'); // couldn't parse response, so probably got an error if (!data) { SomeApp.utils.message('error', 'Não foi possível enviar estes convites. Tente novamente.'); return; } // user is not logged if (SomeApp.utils.requireAuth(data)) { return; } if (data.info.invites) { // hide invite list and display confirmation screen $('#invite_list').addClass('hidden'); $('#invite-confirm').removeClass('hidden');

if (data.info.SomeApp_users_invites > 0) { $("#invitation-status") .append('<li><strong>' + data.info.SomeApp_users_invites + '</strong> pedido(s) de amizade para usuários do SomeApp</li>'); }; if (data.info.non_SomeApp_invites > 0) { $("#invitation-status") .append('<li><strong>' + data.info.non_SomeApp_invites + '</strong> e-mail(s) para amigos fora do SomeApp</li>'); } if ($('#invite-with-question').val()) { var title = (data.info.invites > 1) ? 'Foram enviadas ' + data.info.invites + ' indicações de pergunta.' : 'Foi enviada 1 indicação de pergunta.'; } else { var title = (data.info.invites > 1) ? 'Foram enviados ' + data.info.invites + ' convites.' : 'Foi enviado 1 convite.'; } $('#invitation-title').html(title); } else { SomeApp.utils.message('warning', data.flash_messages.warning); } }); }); }); }); $('#select_all') .attr('checked', 'checked') .click(function(){ if (this.checked) { $('#select_SomeApp').removeAttr('checked'); $('#contacts-list :checkbox').not('[disabled]').attr('checked', 'checked'); } else { $('#contacts-list :checkbox').not('[disabled]').removeAttr('checked'); } $('#total-selected-contacts').html($('#contacts-list :checkbox:checked').not('[disabled]').length + ' contato(s)'); }); $('#select_SomeApp') .removeAttr('checked') .click(function(){ if (this.checked) { $('#select_all').removeAttr('checked'); $('#contacts-list :checkbox').not('[disabled]').removeAttr('checked'); $('#contacts-list li.SomeApp_user :checkbox').attr('checked', 'checked'); } else { $('#contacts-list li.SomeApp_user :checkbox').removeAttr('checked'); } $('#total-selected-contacts').html($('#contacts-list li.SomeApp_user :checkbox:checked').not('[disabled]').length + ' contato(s)'); }); $("a[href=#manual_invite]").click(function(e){ SomeApp.utils.stopPropagation(e); if(!$(this).parents(".tab_title:first").is(".active")) { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } }); if (location.hash == '#manual_invite') { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } //mudando a aba do serviço automaticamente var service_mapping = {0: 'gmail', 1:'yahoo', 2:'live'}; var services_radio_button = ""; for (key in service_mapping) { if ($("#services")[0].places[key].checked) { services_radio_button = service_mapping[key]; } }

$("#service-suffix").html(suffixes[services_radio_button]); $("#services fieldset").attr("class", services_radio_button); $("p#service_instructions").addClass("hidden"); $("#service-select").addClass("hidden"); if(services_radio_button == "yahoo") { $("p#service_instructions").removeClass("hidden"); } else if (services_radio_button == "other") { $("#service-select").removeClass("hidden"); } }}

Page 45: Evento Front End SP - Organizando o Javascript

"invite_friends" : function() { var resizeLoader = function() { $("#loader").css("width", $(".places").width()); $("#loader").css("height", $(".places").height()-18); } resizeLoader(); var resizeTimer; $(window).bind('resize', function() { clearTimeout(resizeTimer); resizeTimer = setTimeout(resizeLoader, 50); }); $("a[href=#automatic_invite]").click(function(e){ SomeApp.utils.stopPropagation(e); if(!$(this).parents(".tab_title:first").is(".active")) { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } }); var suffixes = { "gmail": "@gmail.com", "yahoo": "", "live": "@hotmail.com", "other": "" }; // reset fields (firefox)

$('#service-suffix').html(suffixes['gmail']); $("p#service_instructions").addClass("hidden"); $("#service-select").addClass("hidden"); // add radio button events // when is clicked, should change e-mail suffix and // change fieldset class // shows or hides warning message and dropdown on 'others' service $("#services :radio").click(function() { $("#service-suffix").html(suffixes[this.value]); $("#services fieldset").attr("class", this.value); $("p#service_instructions").addClass("hidden"); $("#service-select").addClass("hidden"); if(this.value == "yahoo") { $("p#service_instructions").removeClass("hidden"); } else if (this.value == "other") { $("#service-select").removeClass("hidden"); } }); // set submit event $("#retrieve-list-button").click(function(){ var user = $('#user').val(); var pass = $('#pass').val(); var service = $('#services :radio:checked').val(); if (!user || !pass) { SomeApp.utils.message("warning", "Você precisa informar seu usuário e senha."); return; } // display logos $('img.service-logo').addClass('hidden'); $('img.' + service).removeClass('hidden'); // build email // gmail, yahoo, hotmail (live), others if (service == "live") { var email = user + suffixes[service]; } else if (service == "yahoo") { if (user.indexOf('@') == -1) { SomeApp.utils.message('warning', 'Você precisa informar um email do Yahoo! valido!'); return; } else { // check if we're handling real Yahoo! emails var regex = /\@((yahoo)|(ymail))\..+/ if (!regex.test(user)) { SomeApp.utils.message('warning', 'Você precisa informar um email do Yahoo! valido!'); return; } else { var email = user; } } } else if (service == "gmail") { var email = user + suffixes[service]; } else { // other services var email = user + suffixes[service]; } $("#loader").removeClass("hidden"); resizeLoader(); $("#loader-message").text("Estamos carregando sua lista de contatos e este processo pode demorar um pouco."); $.ajaxSetup({timeout: 60000}) // syncronize with grabber (time in m$) $.getJSON("/async/contacts", {email: email, password: pass}, function(data){ // any error if (!data) { SomeApp.utils.message('error', 'Não foi possível carregar os contatos. Por favor, tente novamente mais tarde.'); $('#loader').addClass('hidden'); return; } // request returned false if (!data.success) { SomeApp.utils.message('error', data); $('#loader').addClass('hidden'); return; }

// user is not logged if (SomeApp.utils.requireAuth(data)) { $('#loader').addClass('hidden'); return; } // got no contacts, probably user provided invalid credentials if (!data.contacts) { $('#loader').addClass('hidden'); SomeApp.utils.message('warning', data); return; } // got no contacts at all if (data.contacts.length == 0) { $('#loader').addClass('hidden'); SomeApp.utils.message('warning', 'Sua lista não possui nenhum contato.'); return; } $('#loader, #services-block').addClass('hidden'); $('#invite_list').removeClass('hidden'); var contacts = ""; var labels = { 'SomeApp_friend': 'usuário SomeApp já adicionado como amigo', 'SomeApp_user': 'usuário SomeApp', 'none': 'não é usuário SomeApp' } var total_contacts = data.contacts.length; var current_permalink = null; var used_permalinks = {}; for(var i = 0; i < total_contacts; i++) { var contact = data.contacts[i]; var css_status = contact.status; var li_id = ""; var permalink = (contact.permalink == "")? "outros" : contact.permalink;

used_permalinks[permalink] = true; if (contact.status == "none") { css_status = 'new_user'; } if (current_permalink != permalink) { current_permalink = permalink; li_id = 'id="' + permalink + '"'; }; contacts += '<li ' + li_id + ' class="clearfix ' + css_status + ' ' + permalink + '">\ <span class="user_name" title="' + contact.name + '">\ <input type="hidden" name="contacts[' + i + '][name]" value="' + contact.name + '" />\ <input type="hidden" name="contacts[' + i + '][email]" value="' + contact.email + '" />\ <input type="hidden" name="contacts[' + i + '][status]" value="' + contact.status + '" />\ <input type="checkbox" name="selections[]" value="' + i + '" checked="checked" ' + ((css_status == 'SomeApp_friend') || (css_status == 'SomeApp_user' && $('#invite-with-question').val()) ? 'disabled="disabled" style="visibility:hidden" ' : '') + ' />\ <label>' + contact.name + '</label>\ </span>\ <span class="email" title="' + contact.email + '">' + contact.email + '</span>\ <span class="user_type icon_sprite" title="' + labels[contact.status] + '">' + labels[contact.status] + '</span>\ </li>'; }; // disable sidebar links without correspondent items var items = ["outros", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

for (var i = 0; i < items.length; i++) { var item = items[i];

if (!used_permalinks[item]) { var span = '<span>' + $('#found_users_alphabet_list li.' + item + ' a').text() + '</span>'; $('#found_users_alphabet_list li.' + item) .addClass('no-items') .html(span); } }

// inject html $('#contacts-list').html(contacts); // set found contacts total var possible_connections = $('#contacts-list li').not('.SomeApp_friend').length; $('#total-contacts').html(possible_connections); // set boxes event $('#contacts-list :checkbox').not('[disabled]').click(function() { var total_selected = $('#contacts-list :checkbox:checked').not('[disabled]').length; var text = total_selected + ' contato(s)'; $('#total-selected-contacts').html(text); $('#select_SomeApp').removeAttr('checked'); if (total_selected == total_contacts) { $('#select_all').attr('checked', 'checked'); } else { $('#select_all').removeAttr('checked'); }; }); $('#total-selected-contacts').html($('#contacts-list :checkbox:checked').not('[disabled]').length + ' contato(s)'); $('input.send-invitations').click(function(){ $('#loader').removeClass('hidden'); resizeLoader(); $("#loader-message").text("Estamos enviando convites para os amigos selecionados. Por favor, aguarde."); var send_data = $('#contacts-form').formSerialize(); $.post('/users/invite_friends', send_data, function(data){ // try to parse the response as json try { var data = $.parseJSON(data); } catch (e) { var data = false; } // hide loader $('#loader').addClass('hidden'); // couldn't parse response, so probably got an error if (!data) { SomeApp.utils.message('error', 'Não foi possível enviar estes convites. Tente novamente.'); return; } // user is not logged if (SomeApp.utils.requireAuth(data)) { return; } if (data.info.invites) { // hide invite list and display confirmation screen $('#invite_list').addClass('hidden'); $('#invite-confirm').removeClass('hidden');

if (data.info.SomeApp_users_invites > 0) { $("#invitation-status") .append('<li><strong>' + data.info.SomeApp_users_invites + '</strong> pedido(s) de amizade para usuários do SomeApp</li>'); }; if (data.info.non_SomeApp_invites > 0) { $("#invitation-status") .append('<li><strong>' + data.info.non_SomeApp_invites + '</strong> e-mail(s) para amigos fora do SomeApp</li>'); } if ($('#invite-with-question').val()) { var title = (data.info.invites > 1) ? 'Foram enviadas ' + data.info.invites + ' indicações de pergunta.' : 'Foi enviada 1 indicação de pergunta.'; } else { var title = (data.info.invites > 1) ? 'Foram enviados ' + data.info.invites + ' convites.' : 'Foi enviado 1 convite.'; } $('#invitation-title').html(title); } else { SomeApp.utils.message('warning', data.flash_messages.warning); } }); }); }); }); $('#select_all') .attr('checked', 'checked') .click(function(){ if (this.checked) { $('#select_SomeApp').removeAttr('checked'); $('#contacts-list :checkbox').not('[disabled]').attr('checked', 'checked'); } else { $('#contacts-list :checkbox').not('[disabled]').removeAttr('checked'); } $('#total-selected-contacts').html($('#contacts-list :checkbox:checked').not('[disabled]').length + ' contato(s)'); }); $('#select_SomeApp') .removeAttr('checked') .click(function(){ if (this.checked) { $('#select_all').removeAttr('checked'); $('#contacts-list :checkbox').not('[disabled]').removeAttr('checked'); $('#contacts-list li.SomeApp_user :checkbox').attr('checked', 'checked'); } else { $('#contacts-list li.SomeApp_user :checkbox').removeAttr('checked'); } $('#total-selected-contacts').html($('#contacts-list li.SomeApp_user :checkbox:checked').not('[disabled]').length + ' contato(s)'); }); $("a[href=#manual_invite]").click(function(e){ SomeApp.utils.stopPropagation(e); if(!$(this).parents(".tab_title:first").is(".active")) { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } }); if (location.hash == '#manual_invite') { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } //mudando a aba do serviço automaticamente var service_mapping = {0: 'gmail', 1:'yahoo', 2:'live'}; var services_radio_button = ""; for (key in service_mapping) { if ($("#services")[0].places[key].checked) { services_radio_button = service_mapping[key]; } }

$("#service-suffix").html(suffixes[services_radio_button]); $("#services fieldset").attr("class", services_radio_button); $("p#service_instructions").addClass("hidden"); $("#service-select").addClass("hidden"); if(services_radio_button == "yahoo") { $("p#service_instructions").removeClass("hidden"); } else if (services_radio_button == "other") { $("#service-select").removeClass("hidden"); } }}

Page 46: Evento Front End SP - Organizando o Javascript
Page 47: Evento Front End SP - Organizando o Javascript

354 linhasRedimensionamento de janelas, gerenciamento de abas, AJAX, validação, autenticação, criação de lista de contatos no DOM, filtros e, provavelmente, muito mais!

Page 48: Evento Front End SP - Organizando o Javascript

Bad jQuery ou Bad developer?O jQuery é bom porque é simples de usar. Mas ele também é ruim porque é simples de usar.

Page 49: Evento Front End SP - Organizando o Javascript

$("#page").load("/some/file.html");

Page 50: Evento Front End SP - Organizando o Javascript

$("#page").load("/some/file.html");

Seleção do elemento no DOM

Page 51: Evento Front End SP - Organizando o Javascript

$("#page").load("/some/file.html");

Requisição AJAX

Page 52: Evento Front End SP - Organizando o Javascript

$("#page").load("/some/file.html");

Manipulação do DOM

Page 53: Evento Front End SP - Organizando o Javascript

Uma coisa de cada vezO seu código deve fazer uma coisa de cada vez e deve fazê-la bem!

Page 54: Evento Front End SP - Organizando o Javascript

#3 MVC/MV*

Page 55: Evento Front End SP - Organizando o Javascript

O pattern MVC separa as aplicações em três partes conhecidas como Model, Views e Controllers.

Page 56: Evento Front End SP - Organizando o Javascript

ModelGerencia os dados, persistência e

regras de negócio de sua aplicação.

Page 57: Evento Front End SP - Organizando o Javascript

ViewRenderiza os modelos e permite a

interação do usuário com a aplicação.

Page 58: Evento Front End SP - Organizando o Javascript

ControllerFaz a mediação das interações do usuário com as views e modelos.

Page 59: Evento Front End SP - Organizando o Javascript

Existem poucas implementações que seguem o MVC proposto pela Xerox PARC à risca.

Page 60: Evento Front End SP - Organizando o Javascript

A maioria dos frameworks implementa uma variação (ou nem implementam).

Page 61: Evento Front End SP - Organizando o Javascript

MVVM Model View ViewModelModel View PresenterModel View AdapterModel View Variation

MVPMVAMV*

Page 62: Evento Front End SP - Organizando o Javascript

No JavaScript, tivemos uma explosão de frameworks nos últimos 2 anos.

Page 63: Evento Front End SP - Organizando o Javascript

Existem mais de 50 frameworks que querem virar “o queridinho” dos desenvolvedores.

Page 65: Evento Front End SP - Organizando o Javascript

Crie seu próprio frameworkIsso fará com que você entenda o problema a fundo e dará o conhecimento para resolver o problema. Depois jogue tudo fora.

Page 66: Evento Front End SP - Organizando o Javascript

usuário views (UI) controllers

models

Page 67: Evento Front End SP - Organizando o Javascript

#4 DICAS GERAIS

Page 68: Evento Front End SP - Organizando o Javascript

Crie arquivos separadosCrie diversos arquivos, cada um com sua responsabilidade. Você sempre pode concatenar os arquivos com ferramentas como o Grunt.

Page 69: Evento Front End SP - Organizando o Javascript

Documente o seu códigoSempre que possível, documente o seu código. Você não vai lembrar porque fez isso na semana que vem.

Page 70: Evento Front End SP - Organizando o Javascript

Injete os elementos em cada componenteEm vez de assumir que o elemento está sempre na página, injete-o através do construtor. Isso permitirá escrever testes mais desacomplados.

Page 71: Evento Front End SP - Organizando o Javascript

TestesCódigos mais simples e com menos responsabilidades são infinitamente mais simples de testar.

Page 72: Evento Front End SP - Organizando o Javascript

Aprenda JavaScriptVocê só será um desenvolvedor melhor quando realmente souber o JavaScript.

Page 73: Evento Front End SP - Organizando o Javascript

#4 *LIVE CODING*Não importa o quanto digam que fazer live coding sempre dá errado, eu não aprendo!

Page 74: Evento Front End SP - Organizando o Javascript

#5 *OBRIGADO*Aqui é a parte que vocês batem palmas (ou vaiam) e fazem perguntas (ou vão embora).