├── 01-blocos-basicos ├── 01.js ├── 02.js ├── 03.js └── 04.js ├── 02-dom ├── .gitignore ├── index.html ├── main.js └── main.scss ├── 03-promises ├── .gitignore ├── get_data.js ├── index.html ├── main.js └── main.scss ├── 04-apis ├── .gitignore ├── README.md ├── credentials.sample.js ├── get_data.js ├── index.html ├── loading.gif ├── main.js └── main.scss ├── 05-classes ├── index.html ├── main.css └── main.js ├── 06-npm ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── index.js │ └── main.scss └── webpack.config.js └── 07-exercicio ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── src ├── js │ ├── .DS_Store │ ├── index.js │ └── resources │ │ ├── google.js │ │ └── musicbrainz.js └── styles │ └── main.scss └── webpack.config.js /01-blocos-basicos/01.js: -------------------------------------------------------------------------------- 1 | // Escreva uma função que recebe 2 | // um número e retorna `true` se ele 3 | // é um numero de cartao de credito 4 | // valido ou `false` se não. 5 | // 6 | // Dica: Algoritmo de Luhn. 7 | 8 | // 1. limpar o input, deixando so os digitos 9 | // 2. loopar a sequencia de digitos de tras pra frente 10 | // 1. pegar um digito sim e um nao e multiplicar por dois 11 | // 2. se for o produto for maior que nove, soma os algarismos 12 | // 3. depois disso ai em cima, somar todos 13 | // 3. pegar soma total, e verificar se modulo 10 e zero 14 | 15 | function isValidCreditCard(card) { 16 | let clean_card = card.replace(/\D/g, "").split("") 17 | // let clean_card = "" 18 | // for (const char of card) { 19 | // if (!isNaN(char * 1)) { 20 | // clean_card += char 21 | // // ou... 22 | // // clean_card = clean_card + char 23 | // } 24 | // // ou... 25 | // if (!isNaN(Number(char))) { 26 | // } 27 | // ou... 28 | // if ("0123456789".indexOf(char) !== -1) { 29 | // } 30 | // } 31 | // ou ... 32 | // for (let i = 0; i < card.length; i++) { 33 | // const char = card.charAt(i) 34 | // } 35 | for (let i = clean_card.length - 2; i >= 0; i -= 2) { 36 | let result = (clean_card[i] * 2).toString() 37 | if (result.length === 2) { 38 | result = parseInt(result[0]) + parseInt(result[1]) 39 | } 40 | clean_card[i] = result 41 | } 42 | let sum = 0 43 | for (const element of clean_card) { 44 | sum += parseInt(element) 45 | } 46 | return sum > 0 && sum % 10 === 0 47 | } 48 | 49 | // ou... 50 | // function isValidCreditCard(card) { 51 | // let clean_card = card.replace(/\D/g, "").split("") 52 | // let aux = false 53 | // let sum = 0 54 | // for (let i = clean_card.length - 1; i >= 0; i--) { 55 | // let result = clean_card[i] 56 | // if (aux) { 57 | // result = (clean_card[i] * 2).toString() 58 | // if (result.length === 2) { 59 | // result = parseInt(result[0]) + parseInt(result[1]) 60 | // } 61 | // } 62 | // sum += parseInt(result) 63 | // aux = !aux 64 | // } 65 | // return sum > 0 && sum % 10 === 0 66 | // } 67 | 68 | const valid_credit_cards = [ 69 | "799 273 987 13", 70 | "378734493671000", 71 | "3714-4963-5398-431", 72 | "5610XXX..5910--810!18250", 73 | "30569309025904", 74 | "385 2000 0023 237", 75 | "6011111111111117", 76 | "6011000990139424", 77 | "353 0111 3333 00000", 78 | "356600 woop woop 2020360505", 79 | "5555555555554444", 80 | "5105105105105100" 81 | ] 82 | 83 | for (const valid of valid_credit_cards) { 84 | console.log(isValidCreditCard(valid)) 85 | } 86 | 87 | const invalid_credit_cards = [ 88 | "799 223 987 13", 89 | "3787786493671000", 90 | "3724-4963-5398-431", 91 | "5610XX3..5910--810!18250", 92 | "0305699025904", 93 | "385 2000 0011123 237", 94 | "6011111111117", 95 | "60190139424", 96 | "353 0111 3333 00100", 97 | "3566043 woop woop 2020360505", 98 | "55553555555554444", 99 | "5105205105105100" 100 | ] 101 | 102 | for (const invalid of invalid_credit_cards) { 103 | console.log(isValidCreditCard(invalid)) 104 | } -------------------------------------------------------------------------------- /01-blocos-basicos/02.js: -------------------------------------------------------------------------------- 1 | // Escreva uma função que recebe 2 | // um RG não formatado e retorna ele 3 | // formatado. Exemplo: "5 5555553" -> "5.555.555-3" 4 | 5 | function formatRG(unformatted) { 6 | let result = unformatted.replace(/\D/g,""); 7 | result.split(""); 8 | if (result.length === 9){ 9 | return result[0] + result[1] + "." + result[2] + result[3] + result[4] + "." + result[5] + result[6] + result[7] + "-" + result[8]; 10 | } else { 11 | return result[0] + result[1] + "." + result[2] + result[3] + result[4] + "." + result[5] + result[6] + result[7] + "-" + "x"; 12 | } 13 | } 14 | 15 | function formatRG(unformatted) { 16 | const clearRg = unformatted.replace(/\D/g,""); 17 | return `${clearRg.substr(0, 2)}.${clearRg.substr(2, 3)}.${clearRg.substr(5, 3)}-${clearRg.substr(8, 1)}`; 18 | } 19 | 20 | function formatRG(unformatted) { 21 | const clearRg = unformatted.replace(/\D/g,""); 22 | return clearRg.replace(/(\d{1})(\d{3})(\d{3})(\d{1})/, "$1.$2.$3-$4") 23 | } 24 | 25 | function cpfValido(cpf) { 26 | return cpf.match(/(\d{3})\.(\d{3})\.(\d{3})\-(\d{2})/) 27 | } 28 | 29 | 30 | https://regexr.com/ -------------------------------------------------------------------------------- /01-blocos-basicos/03.js: -------------------------------------------------------------------------------- 1 | // Escreva uma função que 2 | // recebe dois arrays de objetos 3 | // e retorna um terceiro array 4 | // com todos os objetos que aparecem 5 | // no segundo mas não no primeiro. 6 | 7 | function difference(arr1, arr2) { 8 | 9 | } 10 | 11 | -------------------------------------------------------------------------------- /01-blocos-basicos/04.js: -------------------------------------------------------------------------------- 1 | // Escreva uma função que recebe um 2 | // array de números e strings e retorna 3 | // um objeto com o seguinte formato: 4 | // { elemento: repetições } 5 | // ordenado de forma decrescente pelo 6 | // número de repetições. 7 | 8 | function repetitions(arr) { 9 | 10 | } -------------------------------------------------------------------------------- /02-dom/.gitignore: -------------------------------------------------------------------------------- 1 | *.css.map 2 | *.css 3 | /.sass-cache -------------------------------------------------------------------------------- /02-dom/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | CPF 10 | 11 | 12 |
13 |
14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /02-dom/main.js: -------------------------------------------------------------------------------- 1 | const input_cpf = document.getElementById("cpf") 2 | 3 | input_cpf.addEventListener("focus" , function(event) { 4 | input_cpf.value = "___.___.___-__" 5 | setTimeout(function() { 6 | input_cpf.setSelectionRange(0, 0) 7 | }, 1) 8 | // ou... 9 | // event.target.value = "___.___.___-__" 10 | // setTimeout(function() { 11 | // event.target.setSelectionRange(0, 0) 12 | // }, 1) 13 | // ou... 14 | // this.value = "___.___.___-__" 15 | // const that = this 16 | // setTimeout(function() { 17 | // that.setSelectionRange(0, 0) 18 | // }, 1) 19 | // ou... 20 | // this.value = "___.___.___-__" 21 | // let set_cursor_position = function () { 22 | // this.setSelectionRange(0, 0) 23 | // } 24 | // set_cursor_position = set_cursor_position.bind(this) 25 | // setTimeout(set_cursor_position, 1) 26 | }) 27 | 28 | input_cpf.addEventListener("blur" , function() { 29 | this.value = "" 30 | }) 31 | 32 | input_cpf.addEventListener("keydown", function(event) { 33 | event.preventDefault() 34 | if("0123456789".indexOf(event.key) !== -1 35 | && this.value.indexOf("_") !== -1) { 36 | this.value = this.value.replace(/_/, event.key) 37 | const next_index = this.value.indexOf("_") 38 | this.setSelectionRange(next_index, next_index) 39 | } else if (event.key === "Backspace") { 40 | this.value = this.value.replace(/(\d$)|(\d(?=\D+$))/, "_") 41 | const next_index = this.value.indexOf("_") 42 | this.setSelectionRange(next_index, next_index) 43 | } 44 | }) 45 | -------------------------------------------------------------------------------- /02-dom/main.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | font-size: 16px; 6 | font-family: 'Montserrat', sans-serif; 7 | } 8 | 9 | body { 10 | background-color: #e8f7e2; 11 | display: flex; 12 | align-items: center; 13 | height: 100vh; 14 | } 15 | 16 | form { 17 | width: 400px; 18 | margin: 0 auto; 19 | padding: 80px 40px; 20 | background-color: white; 21 | box-shadow: 0px 0px 90px 0px rgba(14, 87, 0, 0.151); 22 | border-radius: 3px; 23 | 24 | label { 25 | width: 100%; 26 | margin-bottom: 15px; 27 | display: block; 28 | } 29 | 30 | input { 31 | border-radius: 7px; 32 | width: 100%; 33 | 34 | &[type="submit"] { 35 | text-align: center; 36 | text-transform: uppercase; 37 | font-weight: 800; 38 | background-color: #54c259; 39 | padding: 15px 30px; 40 | margin: 30px 0 0; 41 | display: block; 42 | color: white; 43 | border: none; 44 | cursor: pointer; 45 | 46 | &:active { 47 | box-shadow: 3px 3px 10px 0px rgba(0,0,0,0.1); 48 | } 49 | } 50 | 51 | &[type="text"] { 52 | padding: 20px 15px; 53 | border: 1px solid #ccc; 54 | 55 | &:focus { 56 | box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.2); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /03-promises/.gitignore: -------------------------------------------------------------------------------- 1 | *.css.map 2 | *.css 3 | /.sass-cache -------------------------------------------------------------------------------- /03-promises/get_data.js: -------------------------------------------------------------------------------- 1 | // Cria uma função que retorna uma Promise. 2 | // Essa função recebe como argumento uma URL e faz uma request HTTP 3 | // para essa URL. A Promise resolve se a request tiver sido bem sucedida 4 | // e retorna os dados da resposta da request. Se a request nao for bem 5 | // sucedida a Promise sera rejeitada. 6 | function get_data(url) { 7 | return new Promise(function (resolve, reject) { 8 | // Cria uma nova request 9 | const req = new XMLHttpRequest() 10 | 11 | // Cria a request 12 | req.open('GET', url) 13 | 14 | // Captura o evento de 'onload', que é quando a 15 | // request terminou de ser executada. 16 | req.onload = function () { 17 | // Checa se o status da request é 200, 18 | // o que quer dizer que a request foi bem sucedida. 19 | if (req.status === 200) { 20 | // Resolve a Promise retornando a resposta da nossa request 21 | resolve(req.response) 22 | } else { 23 | // Rejeita a Promise retornando os status e texto da request 24 | reject(req.status + ' ' + req.statusText) 25 | } 26 | } 27 | 28 | // Captura o evento de 'onerror' caso o não tenha conseguido 29 | // fazer a request. Geralmente por não estar conectado a internet. 30 | req.onerror = function () { 31 | // Rejeita a Promise retornando a string 'Erro de conexão' 32 | reject('Erro de conexão') 33 | } 34 | 35 | // Envia a request. 36 | req.send() 37 | }) 38 | } -------------------------------------------------------------------------------- /03-promises/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CEP 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 |

Este CEP é inválido.

17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /03-promises/main.js: -------------------------------------------------------------------------------- 1 | const cep_input = document.getElementById("cep") 2 | const logradouro_input = document.getElementById("logradouro") 3 | const complemento_input = document.getElementById("complemento") 4 | const bairro_input = document.getElementById("bairro") 5 | const localidade_input = document.getElementById("localidade") 6 | const uf_input = document.getElementById("uf") 7 | const cep_error = document.getElementById("cep-error") 8 | 9 | cep_input.addEventListener("focus", function () { 10 | cep_input.classList.remove("error") 11 | cep_error.style.display = "none" 12 | this.value = "" 13 | }) 14 | 15 | cep_input.addEventListener("blur", function () { 16 | const cep = this.value.replace(/\D/g, "") 17 | 18 | logradouro_input.value = "..." 19 | complemento_input.value = "..." 20 | bairro_input.value = "..." 21 | localidade_input.value = "..." 22 | uf_input.value = "..." 23 | 24 | get_data(`https://viacep.com.br/ws/${cep}/json/`) 25 | .then(function(data) { 26 | data = JSON.parse(data) 27 | if (data.erro) { 28 | cep_input.classList.add("error") 29 | cep_error.style.display = "block" 30 | 31 | logradouro_input.value = "" 32 | complemento_input.value = "" 33 | bairro_input.value = "" 34 | localidade_input.value = "" 35 | uf_input.value = "" 36 | } else { 37 | logradouro_input.value = data.logradouro 38 | complemento_input.value = data.complemento 39 | bairro_input.value = data.bairro 40 | localidade_input.value = data.localidade 41 | uf_input.value = data.uf 42 | } 43 | }) 44 | .catch(function(error) { 45 | cep_input.classList.add("error") 46 | cep_error.style.display = "block" 47 | 48 | logradouro_input.value = "" 49 | complemento_input.value = "" 50 | bairro_input.value = "" 51 | localidade_input.value = "" 52 | uf_input.value = "" 53 | }) 54 | }) -------------------------------------------------------------------------------- /03-promises/main.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 16px; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | body { 10 | display: flex; 11 | align-items: center; 12 | min-height: 100vh; 13 | } 14 | 15 | form { 16 | width: 100%; 17 | max-width: 400px; 18 | margin: 0 auto; 19 | padding: 50px 30px; 20 | 21 | label { 22 | color: #888; 23 | margin-top: 30px; 24 | display: block; 25 | } 26 | 27 | #cep-error { 28 | margin-top: 5px; 29 | font-size: 12px; 30 | color: red; 31 | display: none; 32 | } 33 | 34 | input { 35 | display: block; 36 | width: 100%; 37 | padding: 15px; 38 | border: none; 39 | margin: 7px 0 0; 40 | background-color: #f5f5f5; 41 | border-radius: 5px; 42 | color: green; 43 | 44 | &.error { 45 | border: 1px solid red; 46 | } 47 | 48 | &:focus { 49 | border: 1px solid #d5d5d5; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /04-apis/.gitignore: -------------------------------------------------------------------------------- 1 | *.css.map 2 | *.css 3 | /.sass-cache 4 | credentials.js -------------------------------------------------------------------------------- /04-apis/README.md: -------------------------------------------------------------------------------- 1 | ### Youtube 2 | 3 | Para esse projeto funcionar corretamente, 4 | voce deve duplicar o arquivo `credentials.sample.js`, 5 | mudar o nome dele para `credentials.js` e colocar 6 | a sua chave de API ([veja aqui como criar](https://developers.google.com/youtube/v3/docs/)) 7 | para o Youtube API v3. -------------------------------------------------------------------------------- /04-apis/credentials.sample.js: -------------------------------------------------------------------------------- 1 | const gkey = "" -------------------------------------------------------------------------------- /04-apis/get_data.js: -------------------------------------------------------------------------------- 1 | // Cria uma função que retorna uma Promise. 2 | // Essa função recebe como argumento uma URL e faz uma request HTTP 3 | // para essa URL. A Promise resolve se a request tiver sido bem sucedida 4 | // e retorna os dados da resposta da request. Se a request nao for bem 5 | // sucedida a Promise sera rejeitada. 6 | function get_data(url) { 7 | return new Promise(function (resolve, reject) { 8 | // Cria uma nova request 9 | const req = new XMLHttpRequest() 10 | 11 | // Inicia a request 12 | req.open('GET', url) 13 | 14 | // Envia a request. 15 | req.send() 16 | 17 | // Captura o evento de 'onload', que é quando a 18 | // request terminou de ser executada. 19 | req.onload = function () { 20 | // Checa se o status da request é 200, 21 | // o que quer dizer que a request foi bem sucedida. 22 | if (req.status === 200) { 23 | // Resolve a Promise retornando a resposta da nossa request 24 | resolve(req.response) 25 | } else { 26 | // Rejeita a Promise retornando os status e texto da request 27 | reject(req.status + ' ' + req.statusText) 28 | } 29 | } 30 | 31 | // Captura o evento de 'onerror' caso o não tenha conseguido 32 | // fazer a request. Geralmente por não estar conectado a internet. 33 | req.onerror = function () { 34 | // Rejeita a Promise retornando a string 'Erro de conexão' 35 | reject('Erro de conexão') 36 | } 37 | }) 38 | } -------------------------------------------------------------------------------- /04-apis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | YouTube 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 |

Faça sua busca...

18 |
19 |
20 | 21 | 22 | 23 | 24 | https://developers.google.com/youtube/v3/ -------------------------------------------------------------------------------- /04-apis/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reprograma/t6-javascript-iii/48d2162eb4e6d5013f94e48bd660724d19f4aece/04-apis/loading.gif -------------------------------------------------------------------------------- /04-apis/main.js: -------------------------------------------------------------------------------- 1 | const input_search = document.querySelector("input") 2 | const results_container = document.getElementById("results") 3 | 4 | input_search.addEventListener("blur", function () { 5 | results_container.innerHTML = "" 6 | get_data(`https://www.googleapis.com/youtube/v3/search?part=snippet&q=${this.value}&type=video&key=${gkey}`) 7 | .then(function(data) { 8 | data = JSON.parse(data) 9 | results_container.innerHTML = "" 10 | // ou... 11 | // while (results_container.firstChild) { 12 | // results_container.removeChild(results_container.firstChild) 13 | // } 14 | if (data.items.length > 0) { 15 | for (const video of data.items) { 16 | results_container.innerHTML += ` 17 | 18 |

${video.snippet.title}

19 |

${video.snippet.description}

20 |
21 | ` 22 | } 23 | } else { 24 | results_container.innerHTML = "

Nenhum resultado encontrado

" 25 | } 26 | }) 27 | .catch(function(error) { 28 | results_container.innerHTML = `

${error}

` 29 | }) 30 | }) -------------------------------------------------------------------------------- /04-apis/main.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | font-family: 'Roboto', sans-serif; 4 | } 5 | 6 | #container { 7 | width: 500px; 8 | padding: 30px; 9 | margin: 80px auto; 10 | min-height: 80vh; 11 | box-shadow: 0px 0px 48px 0px rgba(0,0,0,0.31); 12 | } 13 | 14 | #loading { 15 | display: block; 16 | margin: 0 auto; 17 | } 18 | 19 | form { 20 | input { 21 | width: 100%; 22 | padding: 10px 15px; 23 | border: 1px solid #e0e0e0; 24 | } 25 | } 26 | 27 | #results { 28 | margin-top: 30px; 29 | 30 | & > p { 31 | text-align: center; 32 | color: grey; 33 | } 34 | 35 | a { 36 | color:black; 37 | text-decoration: none; 38 | display: block; 39 | padding: 20px; 40 | margin-bottom: 20px; 41 | border: 1px solid #e0e0e0; 42 | transition: box-shadow 200ms ease-in; 43 | 44 | &:hover { 45 | box-shadow: 0px 0px 7px 0px rgba(0,0,0,0.3); 46 | } 47 | 48 | h1 { 49 | margin-bottom: 15px; 50 | font-size: 16px; 51 | margin: 0; 52 | } 53 | 54 | p { 55 | margin-bottom: 0; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /05-classes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /05-classes/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | overflow: hidden; 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | height: 100vh; 13 | } 14 | 15 | main { 16 | width: 500px; 17 | height: 500px; 18 | border: 1px solid black; 19 | position: relative; 20 | } 21 | 22 | div { 23 | border-radius: 100%; 24 | position: absolute; 25 | } -------------------------------------------------------------------------------- /05-classes/main.js: -------------------------------------------------------------------------------- 1 | class Ponto { 2 | constructor(nome, posX, posY) { 3 | this.nome = nome 4 | this.x = posX 5 | this.y = posY 6 | } 7 | 8 | mover_horizontalmente(distancia) { 9 | this.x += distancia 10 | return this.x 11 | } 12 | 13 | mover_verticalmente(distancia) { 14 | this.y += distancia 15 | return this.y 16 | } 17 | 18 | mover(distanciaX, distanciaY) { 19 | this.x += distanciaX 20 | this.y += distanciaY 21 | return [ this.x, this.y ] 22 | } 23 | 24 | distancia_entre_dois_pontos(outro_ponto) { 25 | const x1 = this.x 26 | const y1 = this.y 27 | const x2 = outro_ponto.x 28 | const y2 = outro_ponto.y 29 | return Math.sqrt( ( Math.abs( x1 - x2 ) ) ** 2 + ( Math.abs( y1 - y2 ) ) ** 2 ) 30 | } 31 | } 32 | 33 | class Div extends Ponto { 34 | constructor(nome, cor, posX, posY, altura, largura) { 35 | super(nome, posX, posY) 36 | 37 | this.cor = cor 38 | this.altura = altura 39 | this.largura = largura 40 | } 41 | 42 | desenhar(container) { 43 | this.node = document.createElement("div") 44 | this.node.style.width = this.largura + "px" 45 | this.node.style.height = this.altura + "px" 46 | this.node.style.backgroundColor = this.cor 47 | this.node.style.left = this.x + "px" 48 | this.node.style.top = this.y + "px" 49 | container.appendChild(this.node) 50 | } 51 | 52 | // direcao: up, down, left, right 53 | mover_na_tela(direcao, incremento) { 54 | if (direcao === "up") { 55 | this.mover_verticalmente(-incremento) 56 | this.node.style.top = this.y + "px" 57 | } else if (direcao === "down") { 58 | this.mover_verticalmente(incremento) 59 | this.node.style.top = this.y + "px" 60 | } else if (direcao === "left") { 61 | this.mover_horizontalmente(-incremento) 62 | this.node.style.left = this.x + "px" 63 | } else if (direcao === "right") { 64 | this.mover_horizontalmente(incremento) 65 | this.node.style.left = this.x + "px" 66 | } 67 | } 68 | } 69 | 70 | const container = document.querySelector("main") 71 | const div0 = new Div("beatriz", "lime", 10, 10, 20, 20) 72 | div0.desenhar(container) 73 | const div1 = new Div("wanessa", "red", 40, 40, 20, 20) 74 | div1.desenhar(container) 75 | const divs = [div0, div1] 76 | 77 | let active 78 | for (const div of divs) { 79 | div.node.addEventListener("click", function (event) { 80 | active = div 81 | }) 82 | } 83 | 84 | document.addEventListener("keydown", function(event) { 85 | if (event.key === "ArrowUp") { 86 | if (active.y > 0) { 87 | active.mover_na_tela("up", 10) 88 | } 89 | } else if (event.key === "ArrowDown") { 90 | if (active.y < (container.offsetHeight - active.altura)) { 91 | active.mover_na_tela("down", 10) 92 | } 93 | } else if (event.key === "ArrowLeft") { 94 | if (active.x > 0) { 95 | active.mover_na_tela("left", 10) 96 | } 97 | } else if (event.key === "ArrowRight") { 98 | if (active.x < (container.offsetWidth - active.largura)) { 99 | active.mover_na_tela("right", 10) 100 | } 101 | } 102 | }) -------------------------------------------------------------------------------- /06-npm/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # parcel-bundler cache (https://parceljs.org/) 61 | .cache 62 | 63 | # next.js build output 64 | .next 65 | 66 | # nuxt.js build output 67 | .nuxt 68 | 69 | # vuepress build output 70 | .vuepress/dist 71 | 72 | # Serverless directories 73 | .serverless 74 | 75 | # FuseBox cache 76 | .fusebox/ 77 | 78 | # SCSS 79 | .sass-cache/ 80 | *.css.map 81 | *.sass.map 82 | *.scss.map 83 | 84 | # JS 85 | dist/ -------------------------------------------------------------------------------- /06-npm/README.md: -------------------------------------------------------------------------------- 1 | # Boilerplate NPM 2 | 3 | Boilerplate simples para projetos com JS e SCSS. 4 | 5 | ### Pré-requisitos do projeto 6 | 7 | - npm (^6.4.1) 8 | 9 | #### Como montar o projeto 10 | 11 | ```bash 12 | npm install && npm run build 13 | ``` 14 | 15 | #### Como assistir os arquivos JS e CSS 16 | 17 | ```bash 18 | npm run watch 19 | ``` 20 | -------------------------------------------------------------------------------- /06-npm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /06-npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "06-npm", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack", 9 | "watch": "webpack --watch" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "css-loader": "^1.0.1", 15 | "node-sass": "^4.10.0", 16 | "path": "^0.12.7", 17 | "sass-loader": "^7.1.0", 18 | "style-loader": "^0.23.1", 19 | "webpack": "^4.25.1", 20 | "webpack-cli": "^3.1.2" 21 | }, 22 | "dependencies": { 23 | "jquery": "^3.3.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /06-npm/src/index.js: -------------------------------------------------------------------------------- 1 | import './main.scss' 2 | 3 | import $ from 'jquery' 4 | 5 | console.log($) 6 | -------------------------------------------------------------------------------- /06-npm/src/main.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: cyan; 3 | } -------------------------------------------------------------------------------- /06-npm/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'development', 5 | entry: './src/index.js', 6 | output: { 7 | path: path.resolve(__dirname, 'dist'), // ./dist 8 | filename: 'bundle.js' 9 | }, 10 | module: { 11 | rules: [{ 12 | test: /\.scss$/, 13 | use: [{ 14 | loader: "style-loader" 15 | }, { 16 | loader: "css-loader" 17 | }, { 18 | loader: "sass-loader" 19 | }] 20 | }] 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /07-exercicio/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # parcel-bundler cache (https://parceljs.org/) 61 | .cache 62 | 63 | # next.js build output 64 | .next 65 | 66 | # nuxt.js build output 67 | .nuxt 68 | 69 | # vuepress build output 70 | .vuepress/dist 71 | 72 | # Serverless directories 73 | .serverless 74 | 75 | # FuseBox cache 76 | .fusebox/ 77 | 78 | # SCSS 79 | .sass-cache/ 80 | *.css.map 81 | *.sass.map 82 | *.scss.map 83 | 84 | # JS 85 | dist/ 86 | 87 | # Credentials 88 | credentials.js -------------------------------------------------------------------------------- /07-exercicio/README.md: -------------------------------------------------------------------------------- 1 | # Exercicio API busca artistas 2 | 3 | 1. escutar pelo evento de submissao do input 4 | 1. pegar o valor dentro do input 5 | 2. usar o valor pra fazer a busca 6 | 1. musicbrainz api - https://wiki.musicbrainz.org/Development/JSON_Web_Service 7 | exemplo: http://musicbrainz.org/ws/2/artist/?query=nirvana&fmt=json 8 | 2. google imagens api 9 | 1. api key - https://developers.google.com/custom-search/v1/introduction#identify_your_application_to_google_with_api_key 10 | 2. cx - https://cse.google.com/all 11 | exemplo: https://www.googleapis.com/customsearch/v1?key=&cx=&q=nirvana&searchType=image&imgSize=huge 12 | 3. verifica se retornou algo ou nao 13 | - se retornou... tranforma em um objeto e usa os dados pra criar o html 14 | - se nao retornou... mlstra mensagem avisando que nao teve resultados encontrados 15 | - se deu erro... avisa o usuario que deu erro 16 | 17 | -------------------------------------------------------------------------------- /07-exercicio/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Music Brainz 9 | 10 | 11 | 12 |
13 |
14 |
15 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /07-exercicio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "06-npm", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack", 9 | "watch": "webpack --watch" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "css-loader": "^1.0.1", 15 | "node-sass": "^4.10.0", 16 | "path": "^0.12.7", 17 | "sass-loader": "^7.1.0", 18 | "style-loader": "^0.23.1", 19 | "webpack": "^4.25.1", 20 | "webpack-cli": "^3.1.2" 21 | }, 22 | "dependencies": { 23 | "axios": "^0.18.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /07-exercicio/src/js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reprograma/t6-javascript-iii/48d2162eb4e6d5013f94e48bd660724d19f4aece/07-exercicio/src/js/.DS_Store -------------------------------------------------------------------------------- /07-exercicio/src/js/index.js: -------------------------------------------------------------------------------- 1 | import "../styles/main.scss" 2 | 3 | import google_image_search from "./resources/google" 4 | import musicbrainz_search from "./resources/musicbrainz" 5 | 6 | const bg = document.getElementById("bg") 7 | const form = document.querySelector("form") 8 | const input = form.querySelector("input") 9 | const main = document.querySelector("main") 10 | const content = document.getElementById("content") 11 | 12 | for (const event of ["focus", "click", "keypress"]) { 13 | input.addEventListener(event, function () { 14 | main.style.width = "60vw" 15 | }) 16 | } 17 | 18 | input.addEventListener("blur", function () { 19 | if (content.innerHTML !== "" && 20 | content.innerHTML !== "Carregando..." && 21 | content.innerHTML !== "

Erro de conexão.

" && 22 | content.innerHTML !== "

Nenhum resultado encontrado.

" && 23 | main.style.width === "60vw") { 24 | main.style.width = input.offsetWidth + main.style.padding * 2 + "px" 25 | } 26 | }) 27 | 28 | form.addEventListener("submit", function(event) { 29 | event.preventDefault() 30 | 31 | const query = input.value 32 | content.innerHTML = "Carregando..." 33 | content.style.height = "auto" 34 | bg.style.opacity = 0 35 | musicbrainz_search(query) 36 | .then(function(mb_data) { 37 | let image_index = 0; 38 | (function loadImage (index) { 39 | google_image_search(`${mb_data.name}`, index) 40 | .then(function (g_data) { 41 | bg.src = g_data 42 | bg.onload = function() { 43 | bg.style.opacity = 1 44 | main.style.width = input.offsetWidth + main.style.padding * 2 + "px" 45 | 46 | content.innerHTML = "" 47 | content.style.height = 0 48 | const h1 = document.createElement("h1") 49 | const h3 = document.createElement("h3") 50 | const p = document.createElement("p") 51 | h1.textContent = mb_data.name 52 | h3.textContent = mb_data.life_span 53 | p.textContent = mb_data.area 54 | content.appendChild(h1) 55 | content.appendChild(h3) 56 | content.appendChild(p) 57 | content.style.height = h1.clientHeight + h3.clientHeight + p.clientHeight + 80 + "px" 58 | } 59 | bg.onerror = function (error) { 60 | console.log("load image error", error) 61 | image_index++ 62 | loadImage(image_index) 63 | } 64 | }) 65 | .catch(function (error) { 66 | console.log("google", error) 67 | error = error !== "Nenhum resultado encontrado." 68 | ? "Erro de conexão." : error 69 | content.innerHTML = `

${error}

` 70 | }) 71 | })(image_index) 72 | }) 73 | .catch(function (error) { 74 | console.log("mb", error) 75 | error = error !== "Nenhum resultado encontrado." 76 | ? "Erro de conexão." : error 77 | content.innerHTML = `

${error}

` 78 | }) 79 | }) -------------------------------------------------------------------------------- /07-exercicio/src/js/resources/google.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import credentials from '../credentials' 3 | 4 | function google_image_search(search, index) { 5 | return new Promise(function (resolve, reject) { 6 | axios.get(`https://www.googleapis.com/customsearch/v1?key=${credentials.google.key}&cx=${credentials.google.cx}&q=${search}&searchType=image&imgSize=huge`) 7 | .then(function (response) { 8 | const image_index = index ? index : 0 9 | if (response.data.items[index]) { 10 | resolve(response.data.items[image_index].link) 11 | } else { 12 | reject("Nenhum resultado encontrado.") 13 | } 14 | }) 15 | .catch(function (error) { 16 | reject(error) 17 | }); 18 | }) 19 | } 20 | 21 | export default google_image_search -------------------------------------------------------------------------------- /07-exercicio/src/js/resources/musicbrainz.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | function musicbrainz_artist_search(search) { 4 | return new Promise(function (resolve, reject) { 5 | axios.get(`http://musicbrainz.org/ws/2/artist/?query=${search}&fmt=json`) 6 | .then(function (response) { 7 | const search_result = response.data.artists[0] 8 | if (search_result) { 9 | resolve({ 10 | name: search_result.name, 11 | life_span: `${search_result["life-span"].begin} - ${search_result["life-span"].ended ? search_result["life-span"].end : "present"}`, 12 | area: search_result.area ? search_result.area.name : "" 13 | }) 14 | } else { 15 | reject("Nenhum resultado encontrado.") 16 | } 17 | }) 18 | .catch(function (error) { 19 | reject(error) 20 | }); 21 | }) 22 | } 23 | 24 | export default musicbrainz_artist_search -------------------------------------------------------------------------------- /07-exercicio/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | font-family: "Open Sans", sans-serif; 6 | } 7 | 8 | h1, 9 | h2, 10 | h3, 11 | h4, 12 | h5, 13 | h6 { 14 | font-family: "Montserrat", sans-serif; 15 | } 16 | 17 | body { 18 | background-size: cover; 19 | background-color: #f0f0f0; 20 | overflow: hidden; 21 | 22 | #bg { 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | width: 100vw; 27 | z-index: -1; 28 | opacity: 0; 29 | transition: opacity 1s ease-in-out; 30 | } 31 | } 32 | 33 | main { 34 | width: 60vw; 35 | max-width: 60vw; 36 | padding: 70px; 37 | background-color: rgba(255, 255, 255, 0.9); 38 | min-height: 100vh; 39 | display: flex; 40 | flex-direction: column; 41 | justify-content: center; 42 | align-items: flex-end; 43 | transition-delay: 1s; 44 | transition: width 1s ease-in-out; 45 | 46 | .group { 47 | width: 100%; 48 | max-width: 500px; 49 | } 50 | 51 | #content { 52 | margin-bottom: 80px; 53 | width: 100%; 54 | height: 0; 55 | transition: height 1s ease-in-out; 56 | overflow: hidden; 57 | 58 | h1 { 59 | font-size: 3rem; 60 | margin-bottom: 15px; 61 | } 62 | 63 | h3 { 64 | font-size: 2rem; 65 | margin-bottom: 20px; 66 | } 67 | 68 | p { 69 | font-size: 1.2rem; 70 | } 71 | } 72 | 73 | #search { 74 | width: 100%; 75 | 76 | input { 77 | padding: 15px 20px; 78 | font-size: 16px; 79 | color: #999; 80 | border-radius: 5px; 81 | border: 1px solid #e0e0e0; 82 | width: 100%; 83 | 84 | &:focus { 85 | box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.2); 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /07-exercicio/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'development', 5 | entry: './src/js/index.js', 6 | output: { 7 | path: path.resolve(__dirname, 'dist'), // ./dist 8 | filename: 'bundle.js' 9 | }, 10 | module: { 11 | rules: [{ 12 | test: /\.scss$/, 13 | use: [{ 14 | loader: "style-loader" 15 | }, { 16 | loader: "css-loader" 17 | }, { 18 | loader: "sass-loader" 19 | }] 20 | }] 21 | } 22 | }; 23 | --------------------------------------------------------------------------------