Clique aqui para ler todos os artigos desta edição
Crie seu Weblog com ASP.NET, JavaScript e OleDB (Parte II)
por Marco Bellinaso
Esta é a segunda parte do artigo sobre Weblog, onde você verá como selecionar o blog em um período de datas, trabalhar com janelas de calendário pop-up, inserir comentários e administrar o blog.
Selecionando um Intervalo e Carregando o Blog
Na primeira parte foi abordada a definição de conteúdo de página no arquivo ASPX, mas não foi analisado nenhum código que realmente carregue o conteúdo do blog. Para permitir que o usuário selecionasse um intervalo de um único dia, de uma semana ou de todo o mês, foi utilizado o controle Calendar com a propriedade SelectionMode definida como DayWeekMonth. É boa idéia fornecer caixas de texto para as datas de início e fim desejadas pelo usuário, caso ele queira selecionar as últimas duas semanas ou os últimos 45 dias, por exemplo. A Figura 1 mostra os novos controles adicionados à página com a semana toda selecionada no Calendar.
Figura 1 Intervalos
Se, devido a um postback, a página não for carregada, você deve selecionar um intervalo padrão, por exemplo, a última semana. No entanto, no caso de blogs atualizados com muita freqüência, poderá ser mais apropriado carregar os dados para menos dias e, no caso de blogs raramente atualizados, para todo o mês. Assim como no recurso de notificação de comentários, a melhor opção é deixar a escolha para o administrador do blog, usando uma chave personalizada no arquivo web.config que permita especificar o número de dias para o intervalo padrão. O código a seguir mostra como a chave personalizada é lida a partir do arquivo, feito o Parse para Integer e usada para calcular um intervalo para os últimos n dias, bem como a maneira como o intervalo é destacado no calendário:
Private Sub Page_Load(...) Handles MyBase.Load
If Not IsPostBack Then
Dim defPeriod As Integer = Integer.Parse( _
ConfigurationSettings.AppSettings("Blog_DefaultPeriod"))
Dim fromDate = Date.Today.Subtract(New TimeSpan(defPeriod -_
1,0,0,0))
BlogCalendar.SelectedDates.SelectRange(fromDate, Date.Today)
BindData()
End If
End Sub
A data de início é calculada subtraindo-se n-1 dias da data de hoje. A chamada para BindData carrega os dados para o intervalo selecionado e os vincula ao Repeater e a seus controles internos. Esse método chama o método GetData da classe de negócio do Blog desenvolvido anteriormente (parte I) e passa as datas de início e fim da data selecionada no calendário, que são lidas a partir da coleção SelectedDates:
Private Sub BindData()
Dim ds As DataSet = m_BlogManager.GetData( _
BlogCalendar.SelectedDates(0), _
BlogCalendar.SelectedDates(_
BlogCalendar.SelectedDates.Count - 1))
Blog.DataSource = ds.Tables("Messages").DefaultView
Blog.DataBind()
End Sub
Caso tenha sido selecionado um dia, a coleção SelectedDates terá apenas um item e as datas de início e fim serão iguais. Quando o usuário clica no calendário, a página é enviada novamente (é feito o postback), o novo intervalo é automaticamente selecionado e você manipula o evento SelectionChanged do calendário para que ele chame outra vez o BindData para o novo intervalo. Por fim, você deve manipular o evento Click do botão Load para selecionar o intervalo personalizado especificado no calendário e carregar os dados do blog. No procedimento deste evento, é feito o parse no conteúdo dos dois controles de entrada e são obtidas duas datas. Embora seja possível adicionar validadores no final do procedimento para assegurar que o formato de data esteja correto antes de enviar o formulário, a análise poderia gerar uma exceção se o formato de data não fosse válido. Nesse caso, foi utilizada a data atual (veja a Listagem 1).
Listagem 1 Carregando as datas
Private Sub LoadBlog_Click(...) Handles LoadBlog.Click
Dim fromDate, toDate As Date
Try
fromDate = Date.Parse(IntervalFrom.Text)
Catch
fromDate = Date.Today
End Try
' Faça o mesmo para o toDate...
' Se toDate for anterior a fromDate, defina toDate = fromDate
If toDate < fromDate Then toDate = fromDate
BlogCalendar.SelectedDates.SelectRange(fromDate, toDate)
BlogCalendar.VisibleDate = toDate
BindData()
End Sub
Observe o uso do VisibleDate do calendário (para assegurar que a data final esteja visível no calendário). Isso é necessário porque, se o usuário selecionasse um período de dois meses anteriores, a seleção não estaria visível no calendário. Em vez disso, o calendário mostraria o mês atual, o que não seria muito claro.
Calendário Pop-up
Na configuração atual, se o usuário quiser selecionar um intervalo diferente de um único dia, semana ou mês, ele precisará digitar manualmente a data de início e de fim nas duas caixas de texto e fazer referência a um calendário externo. Além disso, ele poderá digitar a data em um formato inválido. Por esses motivos, é boa prática oferecer um calendário pop-up. Quando o usuário clicar em uma data, o calendário será fechado e a data aparecerá no controle textbox da janela principal. Esse recurso pode ser facilmente reproduzido em ASP.NET por meio do controle Calendar e de um pouco de JavaScript no lado cliente.
Primeiro, vamos cuidar do código ASPX da janela-pai. Adicione um link em uma imagem que abre a janela pop-up por meio de uma chamada à seguinte função JavaScript:
O procedimento JavaScript espera receber o nome do controle textbox que será preenchido com a data selecionada, juntamente com a largura e a altura da janela do calendário pop-up que será aberta. Veja aqui o código JavaScript que deverá entrar na seção já definida no canto superior da página:
function PopupPicker(ctl,w,h)
{
var PopupWindow=null;
settings='width='+ w + ',height='+ h;
PopupWindow=window.open('DatePicker.aspx?Ctl=' +
ctl,'DatePicker',settings);
PopupWindow.focus();
}
Esse código usa window.open para abrir a janela pop-up com uma dimensão especificada, não-ajustável, sem nenhuma barra de rolagem, menu, barra de ferramentas ou barra de status. O primeiro parâmetro é a URL da página a ser carregada na nova janela; no código mostrado, ele carrega uma página DatePicker.aspx com um parâmetro ctl, cujo valor é passado como uma entrada para o código PopupPicker.
Agora que terminamos a página principal, é hora de escrever a página DatePicker.aspx que processa o calendário. Essa página possui um controle Calendar cujas propriedades Width e Height estão definidas como 100%, a fim de que cubra a página inteira. Outro item importante a ser observado no arquivo ASPX é o código JavaScript no lado cliente, que pega uma seqüência de caracteres como entrada e a utiliza como valor para o controle de entrada do formulário-pai e cujo nome é passado na seqüência de caracteres de consulta (query string). Por fim, ele fecha o formulário pop-up propriamente dito. O código JavaScript pode ser visto na Listagem 2.
Listagem 2 Definindo a data
function SetDate(dateValue)
{
// pega na querystring o valor do parâmetro ctl,
// ou seja, o nome do controle de entrada do formulário-pai
// que o usuário deseja definir com a data selecionada
ctl = window.location.search.substr(5);
// define o valor do controle com a data fornecida
thisForm =
window.opener.document.forms[0].elements[ctl].value = dateValue;
// fecha esta pop-up
self.close();
}
Quando o usuário clicar em um link no controle Calendar, em vez do processamento normal que submete o formulário e seleciona o dia clicado, faremos com que seja invocado o procedimento JavaScript personalizado. Por padrão, todos os links processados pelo controle Calendar geram um postback para o servidor. Em vez disso, vamos fazer com que eles apontem para o código SetDate personalizado. Graças ao evento DayRender do Calendar (acionado a cada vez que um dia é processado e o qual fornece uma referência para a célula da tabela que está sendo criada), alterar a saída padrão das células de tabela que contêm os links para o dia é muito fácil. O fragmento de código a seguir substitui o conteúdo da célula padrão por meu próprio controle de hyperlink, que possui o mesmo texto mas aponta para o código JavaScript:
Private Sub DatePicker_DayRender(...) Handles DatePicker.DayRender
Dim hl As New HyperLink()
hl.Text = CType(e.Cell.Controls(0), LiteralControl).Text
hl.NavigateUrl = "javascript:SetDate('" & _
e.Day.Date.ToShortDateString() & "');"
e.Cell.Controls.Clear()
e.Cell.Controls.Add(hl)
End Sub
O valor passado para o código JavaScript é a data do dia selecionado, em formato abreviado (geralmente mm/dd/aa). Esse valor será usado para o controle de entrada no formulário-pai. A Figura 2 mostra a janela pop-up resultante.
Figura 2 Calendário Pop-up
Como você pode ver, os controles do servidor (Server Controls) ASP.NET podem ser altamente personalizados. Outra situação em que você poderá usar o evento DayRender dessa maneira consiste no redirecionamento para outra página, com a data incluída na seqüência de caracteres de consulta (query string) - em vez de redirecionar para a segunda página no servidor após um postback com a data. Para fazer isso, simplesmente substitua a linha na qual você define a propriedade NavigateUrl do hyperlink para algo semelhante ao seguinte:
hl.NavigateUrl = "SecondPage.aspx?Date=" & e.Day.Date.ToShortDateString()
Postando Comentários
Na Figura 2 da parte I do artigo (edição número 3 - janeiro/2004), você viu que, abaixo de cada mensagem, existe um link "Post your own comment" (Publique seu próprio comentário). Quando o usuário clica nesse link, é exibida uma caixa com controles de entrada que permite a inclusão de comentários. Você pode adivinhar como ela funciona porque usamos a mesma técnica para criar a lista de comentários. A caixa Comments com seus controles de entrada é declarada dentro de uma DIV cujo estilo de exibição é inicialmente definido como "none", para que ela não esteja visível. Quando se clica nesse link, o estilo é alterado e a página é rolada até o canto inferior até que se torne visível. Para evitar o envio de códigos HTML desnecessários, que tornariam a página mais lenta, é definida uma única caixa de comentários no canto inferior da página (em vez de uma caixa para cada mensagem). A Figura 3 mostra a caixa de comentários e os controles de entrada necessários.
Figura 3 Postando um Comentário
Como você especifica a mensagem para a qual o comentário é postado? Uma boa solução é armazenar a ID da mensagem-pai em um textbox hidden ASP.NET para quando o usuário clicar no link "Post your own comment". Quando o botão Post (Enviar) for pressionado, esse valor poderá ser recuperado do codebehind. Observe que você não pode usar a propriedade Visible para ocultar o controle, porque quando Visible estiver definido como False o controle será oculto e o código HTML não será enviado para o cliente. Você precisa usar o mesmo estilo de exibição utilizado para a DIV. A DIV e o controle textbox são declarados desta forma:
Post your own comment A rotina ShowCommentBox JavaScript recebe a ID da mensagem a ser comentada e a utiliza como o valor do controle textbox oculto recém-declarado: function ShowCommentBox(msgID) { document.forms[0].ParentMessageID.value = msgID; ShowCommentBox2(); } O código que realmente torna a caixa de comentários visível e rola a página para baixo está localizado em uma rotina separada (o código ShowCommentBox2). Chamaremos esse código novamente quando quisermos mostrar a caixa de comentários sem configurar o atributo de valor do controle textbox oculto: function ShowCommentBox2() { CommentBox.style.display = ""; window.location.href = '#CommentBoxAnchor'; } Agora, só nos resta criar o clique no botão Post (Enviar) para chamar o InsertComment da instância Business.Blog e vincular novamente os dados atualizados ao Repeater: Private Sub PostComment_Click(...) Handles PostComment.Click m_BlogManager.InsertComment(Integer.Parse(ParentMessageID.Text), _ Author.Text, Email.Text, Comment.Text) BindData() ' redefina o valor dos controles de entrada ParentMessageID.Text = "" ' redefina as outras textbox visíveis... End Sub Administrando o Blog O código para as tarefas do usuário está quase completo. Os usuários podem ler as mensagens relacionadas ao intervalo selecionado e postar comentários. O proprietário do blog, por outro lado, precisa adicionar, inserir e excluir as mensagens e comentários diretamente no banco de dados. Para permitir esse acesso, a próxima etapa será desenvolver uma página de login e modificar a página principal do blog de modo que, quando o administrador estiver conectado, a página mostre os controles adicionais que permitem executar operações administrativas. A página de login é composta de caixas de texto para o nome e a senha do usuário, uma caixa de seleção para a opção "persistent login" (login persistente) e um botão de envio. Como você terá apenas um administrador e não precisará de segurança por função, armazenar as credenciais no arquivo web.config será suficiente. A Listagem 3 mostra a classe codebehind. Se as credenciais especificadas forem válidas, ele autenticará o usuário e o redirecionará para a página Default.aspx. Listagem 3 Classe Codebehind da Página de Login Imports System.Web.Security Public Class Login Inherits System.Web.UI.Page ' Web Form Designer Generated Code here... Protected UserName As System.Web.UI.WebControls.TextBox Protected Password As System.Web.UI.WebControls.TextBox Protected Persistent As System.Web.UI.WebControls.CheckBox Protected WithEvents LoginUser As System.Web.UI.WebControls.Button Protected InvalidLogin As System.Web.UI.WebControls.Label Private Sub Page_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load If Not Page.IsPostBack Then ' se a querystring contiver um parâmetro "Action=logout", faça logout ' e exclua o cookie If Request.Params("Action") = "logout" Then FormsAuthentication.SignOut() End If End If End Sub Protected Sub LoginUser_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles LoginUser.Click ' verifique o nome de usuário e senha If FormsAuthentication.Authenticate(UserName.Text, Password.Text) Then ' se ok, salve o cookie FormsAuthentication.SetAuthCookie(UserName.Text, _ Persistent.Checked) ' redirecione para Default.aspx Response.Redirect("Default.aspx", True) Else ' se as credenciais estiverem erradas, mostre a mensagem de erro InvalidLogin.Visible = True End If End Sub End Class Na página Default.aspx, adicionamos os controles de edição, que só estarão visíveis se o usuário for autenticado. Na parte superior da página, declare um painel (panel) com um link "logout" que aponte para Login.aspx com o parâmetro "action=logout" na seqüência de caracteres de consulta (query string), e uma tabela com as caixas de texto para especificar o título e o conteúdo da mensagem. Esse painel poderá ser exibido ou oculto no Page_Load, da seguinte forma: MessageBox.Visible = User.Identity.IsAuthenticated Quando o administrador preenche as caixas de texto e clica no botão Post (Enviar), é acionado o evento Click no lado servidor. Utilizamos a função InsertMessage para adicionar a nova mensagem ao banco de dados e chamar o BindData para carregá-la no Repeater. Agora, é hora de adicionarmos a funcionalidade de edição. Para fazer isso, adicione um controle LinkButton ao ItemTemplate do Repeater:
Eu sabia pouquíssimas coisas de programação antes de começar a estudar com
vocês, fui me especializando em várias áreas e ferramentas que tinham na plataforma, e com essa
bagagem consegui um estágio logo no início do meu primeiro
período na faculdade. Estudo aqui na Dev desde o meio do ano passado!
Nesse período a Dev me ajudou a crescer muito aqui no trampo. Economizei 3 meses para assinar a plataforma e sendo sincero valeu muito a
pena, pois a plataforma é bem intuitiva e muuuuito
didática a metodologia de ensino. Sinto que estou EVOLUINDO a cada dia. Muito
obrigado! Nossa! Plataforma maravilhosa. To amando o curso de desenvolvimento
front-end, tinha coisas que eu ainda não tinha visto. A
didática é do jeito que qualquer pessoa consegue aprender. Sério, to apaixonado,
adorando demais. Adquiri o curso de vocês e logo percebi que são os melhores do Brasil. É
um passo a passo incrível. Só não aprende quem não quer.
Foi o melhor investimento da minha vida! Foi um dos melhores investimentos que já fiz na vida e tenho aprendido
bastante com a plataforma. Vocês estão fazendo parte da minha jornada nesse mundo da
programação, irei assinar meu contrato como programador
graças a plataforma.
Wanderson Oliveira
Comprei a assinatura tem uma semana,
aprendi mais do que 4 meses estudando outros cursos. Exercícios práticos que não tem
como não aprender, estão de parabéns! Obrigado DevMedia, nunca presenciei uma plataforma de ensino tão presente na vida acadêmica de
seus alunos, parabéns!
Eduardo Dorneles
Aprendi React na plataforma da DevMedia há cerca de 1 ano e meio... Hoje estou há 1 ano empregado trabalhando 100% com
React!
Adauto Junior
Já fiz alguns cursos na área e nenhum é tão bom quanto o de vocês. Estou aprendendo
muito, muito obrigado por existirem. Estão de parabéns... Espero um dia conseguir um emprego na
área.Confira outros conteúdos:
Perguntas frequentes
Nossos casos de sucesso
Fui o primeiro desenvolvedor contratado pela minha
empresa. Hoje eu lidero um time de desenvolvimento!
Minha meta é continuar estudando e praticando para ser um
Full-Stack Dev!