#desenvolvimento, #projetos

No Comments – Extensão pro Chrome


Olá pessoas.

Após muito tempo sem posts resolvi escrever sobre uma extensão para o Chrome que fiz recentemente. Não irei me ater aos detalhes de como criar a extensão porque acredito que uma lida na documentação é suficiente para este fim.

Meu objetivo é discorrer sobre a motivação para criá-la e os recursos que utilizei.

Alguns sabem que a Web 2.0  trouxe a possibilidade dos usuários colaborarem com o conteúdo publicado através da inclusão de comentários, avaliações, personalização e compartilhamento. A ideia é linda mas o fato é que na maioria dos sites os comentários não adicionam nenhum valor ao conteúdo.

Hoje em uma lista de comentários é raro não ter pelo menos um comentário escrito com o intuito de ofender alguém. Nos grandes sites de notícias do nosso lindo país é comum ver centenas de comentários que nos fazem desacreditar na humanidade.  Às vezes a gente nem quer ler mas acaba lendo involuntariamente ao navegar pela página. E neste caso eu concordo plenamente com a frase: “A ignorância é um dom”. E não, eu não estou sendo contra a liberdade de expressão, só acho que não sou obrigada a ler esses lixos certas opiniões.

Partindo daí eu procurei por alguma extensão, pro Chrome, que bloqueasse a visualização dos comentários. Encontrei algumas, testei mas não funcionaram exatamente como eu queria e por isso eu resolvi desenvolvê-la :D.

O objetivo da extensão é bem simples: ocultar todos os comentários de todas as páginas assim que a página for carregada. Como um plus eu adicionei a possibilidade de reverter o processo porque apesar de tudo ainda tem alguns casos que queremos ver os comentários, mesmo que seja só para rir ou passar raiva.

Talk is cheap. Show me the code.

Torvalds, Linus

Então vamos ver como essa tal extensão foi feita, né.

Para que o seu código seja visto como uma extensão você precisa adicionar um arquivo chamado manifest.json que conterá as definições das propriedades.

{
  ...

  "background": {
    // Define qual é o JS principal da extensão.
    "scripts": ["background.js"]
  },

  "icons": {
    // Define o ícone exibido na lista de extensões (chrome://extensions).
    "128": "icon128.png";
  },

  "browser_action": {
    // Define o ícone exibido na omnibox.
    "default_icon": "icon.png"
  },

  "content_scripts": [ {
    // Define quais JS serão utilizados pela extensão.
    "js": [ "jquery-2.0.3.min.js", "functions.js" ],
    // Define para quais sites a extensão será carregada.
    "matches": [ "http://*/*", "https://*/*" ],
    // Define para quais sites a extensão NÃO será carregada.
    "exclude_matches": [ "https://*.github.com/*" ]
  }]

  ...
}

Como definimos o arquivo background.js como JS principal, ele será executado assim que a extensão for carregada.

// Adiciona o ouvinte para o clique no ícone da extensão.
chrome.browserAction.onClicked.addListener(function(tab) {
  // Define qual JS será executado quando receber o clique.
  chrome.tabs.executeScript(tab.id, {file: 'onclick_script.js'});
});

O arquivo onclick_script.js contém apenas uma verificação para identificar se os comentários serão exibidos ou ocultados no momento em que receber o clique.

if (show){
  show = false;
  showComments();
} else {
  show = true;
  hideComments();
}

E a ~~mágica~~ toda está acontecendo no arquivo functions.js. Aqui eu utilizei o jQuery para facilitar a vida juntamente com este sagaz código que seleciona os elementos utilizando expressão regular. A intenção era encontrar todos os elementos que tivessem nos atributos id e class o conteúdo coment(ario) ou comment. Por fim eu adicionei também um critério para buscar pelos comentários que utilizam o Disqus.

function showComments() {
  // Percorre os elementos encontrados exibindo-os.
  jQuery.each(elementsToShowById, function() {
    $(this).show();
  });
}

function hideComments() {

  var disqusExpression = '.*disqus_thread.*';
  var commentExpression = '.*[Cc]o(m|mm)ent.*';

  getVisibleElements('id', commentExpression);
  getVisibleElements('class', commentExpression);
  getVisibleElements('id', disqusExpression);

  // Percorre os elementos encontrados ocultando-os.
  jQuery.each(elementsToShowById, function() {
    $(this).hide();
  });
}

function getVisibleElements(attribute, expression) {
  // Seleciona os elementos pela expressão regular.
  $(':regex(' + attribute + ', ' + expression + ')').filter(function() {
    // Armazena apenas os elementos que estão visíveis.
    if ($(this).is(':visible')){
      elementsToShowById.push($(this));
    }
  });
}

Claro que esta é somente uma das inúmeras maneiras de fazer isto e que pretendo continuar evoluindo a extensão. De pronto já informo que a primeira melhoria a ser implementada é fazer a extensão ocultar os comentários do Youtube que não utiliza a palavra comments para definir seus elementos relacionados aos comentários.

É isso! Fiquem à vontade para instalar, testar e colaborar com a extensão.

Até breve.

PS.: Como eu disse tem casos que convém ler os comentários por isso mesmo que pareça contraditório eu leio e libero todos os comentários do blog, exceto os de spam ;).

Anúncios
Padrão
#bancoDeDados, #desenvolvimento

Como comparar e converter CHAR para DATE em 4GL?


Olá pessoal.

Este post é bem rapidinho com uma dica extremamente simples para quem precisa converter um valor do tipo char em date. Quem já precisou buscar alguma coisa relacionado a 4GL e Progress sabe o quão difícil é encontrar uma resposta satisfatória. Às vezes nem o Stack Overflow resolve.

Então, vamos ao código.


/* Cria as variáveis para o intervalo de data. */
define variable valor-inicial as char.
define variable valor-final as char.

define variable data-inicial as date format "99/99/9999".
define variable data-final as date format "99/99/9999".

/* Atribui os valores  às variáveis do tipo char. */
assign valor-inicial = "01/01/2013".
assign valor-final = "01/06/2013".

/* Converte os valores do tipo char para date. */
assign data-inicial = date(valor-inicial).
assign data-final = date(valor-final).

/* Compara o intervalo. */
For each sua_tabela
   where data_para_comparar >= data-inicial
     and data_para_comparar <= data-final.

   disp data_para_comparar.

Isso é tudo, espero que seja útil pra alguém.

Até breve 😉

Referência:

How to convert a date integer to a date format

Padrão
#desenvolvimento

Relatórios com Rails e Odf-report


Olá pessoal.

Em um projeto desenvolvido em Ruby on Rails que estou trabalhando preciso implementar a geração de alguns relatórios. Atualmente esses relatórios são feitos através de documentos de texto do tipo Word e isto pesou muito na escolha da utilização da gem Odf-report.

Esta gem tem como objetivo criar um relatório/documento de acordo com um template salvo no formato ODF, cuja extensão é .odt.

A utilização da gem é bem simples, basicamente você precisa adicionar no arquivo os campos que terão o valor alterado via código, e no código definir o valor para cada campo.

Para incluir um campo dentro do template basta definir uma palavra ou expressão e adicioná-la entre colchetes, por exemplo:

[NOME]

[DATA_NASCIMENTO]

Para facilitar o entendimento da utilização eu criei um projeto de exemplo que pode ser visto aqui no meu GitHub. Também disponibilizei um demo no Heroku.

É isso.

Até breve 😉

Padrão
#desenvolvimento

Resolvendo o erro: Error calling method on NPObject


Olá pessoal.

Este é um daqueles post com soluções para os problemas do dia a dia. Recentemente eu precisei resolver o erro Uncaught Error: Error calling method on NPObject ocorrido em um projeto web desenvolvido com ASP.NET MVC3.

O tal erro acontecia ao submeter um determinado formulário. Mas só acontecia se em algum dos campos contivessem um & em seu conteúdo.

Este formulário continha um upload de imagem utilizando o Uploadify. E o erro acontecia no momento de executar a função uploadifyUpload() do plugin. Mais especificamente na linha abaixo:

document.getElementById(jQuery(this).attr('id') + 'Uploader').startFileUpload(ID, checkComplete);

Pesquisando e tentando solucionar este erro nada descritivo, identifiquei que o conteúdo do formulário era serializado antes de ser submetido. E quando isso acontecia o & era convertido para %26.

Então, resolvi substituir o & pelo unicode equivalente. Após serializar o objeto eu troquei o & pelo seu unicode \u0026 antes de chamar a função uploadifyUpload(). E o código ficou assim:

...
if ($('.uploadifyQueueItem').length > 0) {
   var conteudoForm= $("#id_form").serializeObject();
   var campo = conteudoForm['id_campo'];
   conteudoForm['id_campo'] = campo.replace('&', '\\u0026');
   $('.upload').uploadifySettings('scriptData', conteudoForm);
   $('.upload').uploadifyUpload();
}

Erro resolvido e formulário submetido normalmente. Tudo lindo, ou melhor, quase. O valor do campo está chegando com o unicode e precisamos voltar para o &.

No meu caso utilizando o ASP.NET MVC 3 recebo o conteúdo do formulário no método Create e faço a conversão lá mesmo:

[HttpPost]
public ActionResult Create(ModelQualquer modelQualquer, HttpPostedFileBase Filedata) {

   modelQualquer.Atributo = modelQualquer.Atributo.Replace("\\u0026", "&");
   ...
}

Agora sim, ta certo.

A solução foi bem idiota boba e deve ter umas 1000, ou mais, maneiras melhores de se resolver. O mais chatinho foi encontrar onde realmente estava o problema, já que o erro não diz nada muita coisa.

É isso, galera. Espero que possa ser útil e fiquem a vontade para postar outras soluções nos comentários.

Até breve 😉

Padrão
#desenvolvimento

ActiveAdmin – Customização do menu


Olá pessoal.

Após um longo hiato sem posts resolvi escrever sobre como fazer um menu customizado utilizando ActiveAdmin.

Pra quem não conhece o ActiveAdmin é um framework que pode ser utilizado para administração de projetos feitos com Ruby on Rails, facilitando ainda mais o desenvolvimento.

Mas como nada é perfeito, o ActiveAdmin tem uma limitação de apenas dois níveis no menu superior. Só que eu precisava de um menu com três níveis.

Eu abri uma questão no StackOverflow mas até o momento sem nenhuma resposta que torne essa customização mais fácil. Eu pesquisei um bocado e fui juntando um pouco de tudo pra poder fazer o que precisava.

Entretanto deixo os comentários abertos caso alguém tenha encontrado uma forma mais simples e mais bonita 😉

Então vamos ao código!!!

A primeira coisa que precisamos fazer é informar ao ActiveAdmin que iremos utilizar um cabeçalho próprio. Para isto acrescente as linhas abaixo no arquivo config/initializers/active_admin.rb:

ActiveAdmin.setup do |config|
  ...
  # Define a classe que irá construir o menu.
  config.view_factory.header = CustomAdminHeader

  # Define o arquivo de CSS que será utilizado no menu.
  config.register_stylesheet 'novo_menu.css'
  ...
end

Agora precisamos criar nossa classe CustomAdminHeader que conterá o código que irá sobrescrever a construção do menu. Você pode criar esta classe dentro da pasta app/admin e nomear o arquivo como custom_admin_header.rb. No arquivo criado, adicione o código abaixo:

# encoding: UTF-8

class CustomAdminHeader < ActiveAdmin::Views::Header
  include Rails.application.routes.url_helpers

  def build(namespace, menu)
    div :id => 'tabs' do
      # Adiciona um item de menu sem filhos.
      ul do
        # Substitua rota_destino_path para a rota que deseja seguir quando o item receber o clique.
        li { link_to 'Item sem filhos', rota_destino_path }
      end

      # Adiciona um item de menu com 1 filho.
      ul do
        li do
          text_node link_to("Pai com 1 filho", "#")
          ul do
            li { link_to 'Filho sem filhos', rota_destino_path }
            # Caso queira adicionar mais filhos, inclua mais LIs aqui.
          end
        end
      end

      # Adiciona um item de menu com 1 filho e 1 neto.
      ul do
        li do
          text_node link_to("Avó com 1 filho", "#")
          ul do
            li do
              text_node link_to("Pai com 1 filho", rota_destino_path)
              ul do
                li { link_to 'Neto sem filhos', rota_destino_path }
                # Caso queira adicionar mais netos, inclua mais LIs aqui.
              end
            end
          end
        end
      end

    # Chama o método construtor da classe pai para colocá-lo todos juntos.
    super(namespace, menu)
  end
end

Quase lá. A estrutura do seu menu será criada por esta classe por isso as definições de menu utilizadas nas classes contidas na pasta app/admin não devem ser exibidas. Para isto você precisa adicionar o código a seguir em todas as classes:

ActiveAdmin.register SuaClasse do
  menu false
end

Por fim deixo o código CSS que utilizei para customizar o menu de forma que mantivesse o layout do menu parecido com o menu original. Você pode chamar o arquivo CSS de novo_menu.css (conforme adicionamos nas configurações do ActiveAdmin) e salvá-lo na pasta app/assets/stylesheets.

.site_title {
  position: absolute;
  left: 20px;
  top: 10px;
  font-size: 1.5em !important;
  font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
}

#tabs {
  font-size: 1.0em;
  font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
  padding-left: 80px;
  background: #6a7176;
  background: -webkit-gradient(linear, left top, left bottom, from(#6a7176), to(#4d5256));
  background: -moz-linear-gradient(-90deg, #6a7176, #4d5256);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#6a7176', endColorstr='#4d5256');
  -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#6a7176', endColorstr='#4d5256');
}

#tabs ul {
  margin:0;
  padding:0;
  list-style:none;
}

#tabs ul li {
  float:left;
}

#tabs ul li a {
  float: left;
  padding-left: 20px;
  padding-right: 20px;
  padding-top: 3px;
  padding-bottom: 3px;
  text-decoration:none;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}

#tabs li ul {
  background: #7b8389;
  border-top-right-radius: 5px;
  -moz-border-radius-topright: 5px;
  -webkit-border-top-right-radius: 5px;
  border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  -webkit-border-top-left-radius: 5px;
  border-bottom-right-radius: 5px;
  -moz-border-radius-bottomright: 5px;
  -webkit-border-bottom-right-radius: 5px;
  border-bottom-left-radius: 5px;
  -moz-border-radius-bottomleft: 5px;
  -webkit-border-bottom-left-radius: 5px;
  box-shadow: 0 1px 3px #444444;
  -moz-box-shadow: 0 1px 3px #444444;
  -webkit-box-shadow: 0 1px 3px #444444;
  left: -999em;
  margin: 25px 0 0;
  position: absolute;
  width: 200px;
  z-index: 1010;
}

#tabs li ul a {
  background: none;
  border: 0 none;
  margin-right: 0;
  width: 160px;
  padding-top: 3px;
  padding-bottom: 3px;
}

#tabs ul li a:hover,
#tabs ul li:hover > a {
  color: #fff;
  background: #7b8389;;
}

#tabs li ul a:hover,
#tabs ul li li:hover > a  {
  color: #fff;
  background: #7b8389;;
}

#tabs li:hover ul {
  left: auto;
}

#tabs li li ul {
  margin: 0px 0 0 200px;
  visibility:hidden;
}

#tabs li li:hover ul {
  visibility:visible;
}

Bom, é isso! Espero que possa ser útil.

Até breve 😉

Padrão
#desenvolvimento

Criando um site com Locomotive CMS


Olá pessoal.

Neste mês tive a oportunidade de conhecer e trabalhar um pouco com o LocomotiveCMS. Fiquei bastante interessada em saber mais sobre como ele funciona. Então resolvi seguir o Getting started disponibilizado pelo pessoal do Locomotive. Mas, para variar, a instalação não ocorreu exatamente como o descrito e foram necessárias algumas configurações adicionais.

Recomendo que tentem primeiro seguir o que está proposto no Getting started e caso não consigam tentem os passos a seguir.

Observação: Os passos foram feitos no Mac OS X Lion 10.7.5.

Vamos lá 😉

Crie uma aplicação Rails:

rails new nome_aplicacao --skip-active-record --skip-test-unit --skip-javascript --skip-bundle

Acesse a pasta criada com a sua aplicação:

cd nome_aplicacao

Edite o arquivo Gemfile deixando apenas o código abaixo:

source 'https://rubygems.org'
gem 'rails', '3.2.11'
gem 'locomotive_cms', '~> 2.0.0.rc11', :require => 'locomotive/engine'
gem 'unicorn', :group => 'development'
gem 'compass-rails', '~> 1.0.2', :group => 'assets'
gem 'sass-rails', '~> 3.2.4', :group => 'assets'
gem 'coffee-rails', '~>; 3.2.2', :group => 'assets'
gem 'uglifier', '~> 1.2.4', :group => 'assets'
gem 'devise'

Instale as dependências:

bundle install

Instale o LocomotiveCMS na sua aplicação:

bundle exec rails g locomotive:install

Atualize seu Brew:

brew update

Instale o MongoDB, caso não tenha:

brew install mongodb

Coloque o MongoDB pra iniciar no boot do sistema operacional:

ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents

Inicie o MongoDB:

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist

Crie o arquivo de configuração do MongoDB:

rails g mongoid:config

Caso receba o erro:
conflict config/mongoid.yml
Overwrite /Users/monteirobrena/Dropbox/repositorio/brains4it/sites/schedule_class/config/mongoid.yml? (enter “h” for help) [Ynaqdh]

Pressione Y para forçar a sobrescrita do arquivo.

Inicie o servidor Unicorn:

bundle exec unicorn_rails

Feito isto basta acessar o endereço http://localhost:8080 para configurar o seu site 😉

Agora, crie a conta de administrador do site, informando o nome da conta, o e-mail e a senha.

Criar conta de administrador

Criar conta de administrador

Crie o site informando o nome do site e escolhendo o idioma da área administrativa.

Criar site

Criar site

Logue na aplicação com os dados informados no cadastro da conta.

Logar na aplicação

Logar na aplicação

E só! O Locomotive CMS está pronto para ser explorado.

Tela inicial

Tela inicial

Isso é tudo pessoal, espero que seja útil para quem quer conhecer e testar o Locomotive.

Até breve 😉

Padrão
#desenvolvimento

Primeiro contato com Node.js


Olá pessoal.

Neste post vamos ver um pouquinho sobre como o Node.js funciona e como utilizá-lo no Windows. Para quem nunca ouviu falar sobre Node.js, ou quem ainda não sabe ao certo para que ele serve, recomendo a leitura deste post para que fique claro o que é o Node.js realmente é.

Node.js

Node.js

A utilização no Windows é feita de forma bem simples, sendo necessário instalar somente o Node.js que pode ser baixado aqui. Após baixar prossiga a instalação normalmente clicando em Next, Next e Finish 😉

Pronto o Node.js está instalado! Uma entrada de menu para Node.js será criado no menu Iniciar do Windows, porém não é através deste prompt que os códigos serão executados. Os comandos para executar os arquivos .js serão feitos no cmd do Windows.

Então, para fazer o famoso Hello World é preciso criar um arquivo, como por exemplo, teste.js e acrescentar a linha de código abaixo:

console.log('Hello World');

Salve seu arquivo na Área de trabalho, abra o cmd do Windows e acesse a pasta onde o arquivo foi salvo. E execute o comando:

node teste.js

Com isso deverá aparecer “Hello World” no seu cmd. Até aqui nada de muito novo, certo?!

Na página principal do Node.js existem dois trechos de códigos para os primeiros testes. Aqui iremos analisar o primeiro trecho responsável por criar um servidor web que fica esperando o recebimento das requisições HTTP. Vejamos o código:

 var http = require('http');

/*
 * O método createServer() cria e retorna uma nova instância de um webserver baseado no protocolo HTTP.
 * Este método recebe como parâmetro os objetos request e response.
 */
 http.createServer(function (req, res) {

   // Acresenta ao cabeçalho do response o content-type do retorno que será enviado para o browser.
   res.writeHead(200, {'Content-Type': 'text/plain'});

   // Acrescenta ao response o texto que será exibido no browser.
   res.end('Hello World\n');

   // Após a criação do web server é definido a porta e o IP que o server escutará.
 }).listen(1337, '127.0.0.1');

console.log('Server running at http://127.0.0.1:1337/');
 

Substitua o código do arquivo teste.js pelo código acima e execute-o no cmd:

node teste.js

No cmd deverá exibir a mensagem Server running at http://127.0.0.1:1337/, se exibir abra o seu navegador e acesse o endereço http://127.0.0.1:1337/. Então será exibida a mensagem Hello World na página. Isto significa que o web server criado está ativo e escutando as requisições HTTP.

Por enquanto é isso. Espero que possa ser esclarecedor para quem, assim como eu, tem interesse em conhecer o Node.js. Também pretendo postar, em breve, mais conteúdos sobre Node.js.

Até breve 😉

Padrão