quinta-feira, 23 de outubro de 2014

Fácil e reutilizável galeria de imagens em Jquery

Se você é programador vai achar esse código um tanto quanto é trivial, mas se você for designer, como o cara que me pediu isso, talvez isso seja muito útil pra você.

Direto vemos galerias de imagens e hotsites e afins, e hoje é simplesmente ridículo fazer esse tipo de coisa com flash. Flash aos poucos está sendo banido da Internet. 

HTML5 e um pouco de jQuery é o que você precisa para fazer uma galeria de imagens onde seja possível escolher a imagem com thumbnails, avançar, voltar e ter exibição automática em ciclo. 

Aqui eu corrijo um erro muito comum dessas galerias: se uma nova imagem aparece a cada 5 segundos, e o usuário passou 4 segundos na última imagem, não seria correto trocar a imagem novamente no timeout, um segundo depois. Com a interação do usuário o timer deveria ser resetado. 

Crie uma página HTML com o conteúdo abaixo. Você pode trazer o  jquery de um CDN também.

Repare nos comentários do código. Uso atributos do tipo data-* e algumas funções anônimas.


 
  
  Untitled Document
  


  
  



 

 

  



«     »

Tudo o que você precisa saber sobre CORS

Primeiro de tudo, a documentação: http://www.w3.org/TR/cors/
Segundo, como configurar no IIS 7: http://i-liger.com/article/cross-domain-http-request
Como configurar cors no IIS 6: http://enable-cors.org/server_iis6.html
É importante salientar que essa configuração também é possível via web.config. Como o web.config é hierárquico, hereditário e combinatório, então você pode colocar um web.config adicional pequenininho com cabeçalhos só para permitir CORS nas páginas de um diretório, em vez da aplicação inteira.
Se a configuração não for para a aplicação inteira nem para uma pasta inteira temos que colcoar cabeçalhos http na página. Os cabeçalhos são:
  • Access-Control-Allow-Origin -> indica quais domínios podem fazer um request no seu, colocando * permite todos os domínios.
  • Access-Control-Allow-Methods -> indica quais métodos são permitidos o cliente consultar no seu domínio. Não adianta colocar só post ou get, pois o client pode mandar uma requisição head para saber encoding e contenttype antes, ou uma requisição options, para saber mais configurações (é o browser / javascript que manda esses métodos), portanto, permita GET, POST, PUT, DELETE, HEAD, DEBUG, OPTIONS
  • Access-Control-Allow-Headers -> indica quais headers o client pode solicitar, configurar Content-Type, Accept
  • Access-Control-Max-Age -> indica quantos segundos um request já atendido deveria ser mantido em cache. Muita gente coloca 1728000, mas eu acho isso muito tempo. 72000 (20 horas) é um número muito mais aceitável, considerando que mesmo um conteúdo estático como o de um e-learning pode mudar de um dia para o outro.
Um exemplo de web.config para um único diretório é:

    
        
            
                
                
                
                                                               
            
        
    


Também é possível fazer isso em uma única página, colocando, como primeiro código a ser executado no page_load, o código
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, HEAD, DEBUG, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "72000");
As configurações no IIS valem para todas as páginas, enquanto que as configurações via web.config são para um diretório e o código acima para uma única página. Todos eles representam a mesma configuração.
Mais informações e exemplos: http://encosia.com/using-cors-to-access-asp-net-services-across-domains/

sexta-feira, 17 de outubro de 2014

Domine a herança de construtores

Em hierarquias longas de objetos é importante saber onde colocar o código dos contructors (construtores) pois eles tem uma ordem lógica para executar e, se for um parameterless constructor (construtor sem parâmetros) então todos os parameterless constructors serão executados desde a raiz object.

Um parameterless constructor sempre executa o parameterless constructor da classe base (pai), mas um construtor com parâmetros você deve especificar:


  1. :this([parametros]) para executar um outro constructor na mesma classe e deixar a hierarquia seguir sucessivamente
  2. :base([parametros]) para executar um constructor específico da classe base
  3. NADA para executar o parameterless constructor da base.


O programa abaixo ilustra isso.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HerancaConstrutor
{

    class ClasseBase
    {
        public ClasseBase()
        {
            Console.WriteLine("parameterless constructor da classe ClasseBase");
        }
    }

    class DerivadaSemConstructor : ClasseBase
    {
        
    }


    class DerivadaComConstructor : ClasseBase
    {
        public DerivadaComConstructor()
        {
            Console.WriteLine("parameterless constructor da classe DerivadaComConstructor");
        }

        public DerivadaComConstructor(string argumento)
        {
            Console.WriteLine("constructor com argumentos da classe DerivadaComConstructor. Argumento: " + argumento);
        }
    }


    class DerivadaDaDerivadaSemConstructor : DerivadaSemConstructor
    {
        
    }

    class DerivadaDaDerivadaComConstructor : DerivadaComConstructor
    {
        public DerivadaDaDerivadaComConstructor()
            : base("")
        {
            Console.WriteLine("parameterless constructor da classe DerivadaDaDerivadaComConstructor");
        }

        public DerivadaDaDerivadaComConstructor(string argumento) : base(argumento)
        {
            Console.WriteLine("constructor com argumentos da classe DerivadaDaDerivadaComConstructor. Argumento: " + argumento);
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            var v1 = new ClasseBase();

            var v2 = new DerivadaSemConstructor();
            var v3 = new DerivadaComConstructor();
            var v3b = new DerivadaComConstructor("b");

            var v4 = new DerivadaDaDerivadaSemConstructor();
            var v5 = new DerivadaDaDerivadaComConstructor();
            var v5b = new DerivadaDaDerivadaComConstructor("b");
        }
    }
}



Toda classe sem parameterless constructor padrão possui um parameterless constructor implícito herdado de object.
Toda classe com um parameterless constructor implicitamente executa o parameterless constructor da classe base, estando ele sendo chamado com :base() explicitamente ou não.

Se um constructor não é criado eecuta o parameterless constructor da classe base
se um constructor é criado mas não é definido um constructor base é executado o parameterless constructor da base.
se um construtor é criado e é especificado um outro construtor da classe base com argumentos para ser executado, é executado o constructor escolhido e o constructor da classe ancestral da base é executado.
Se um constructor chama outros constructors, com ou sem parâmetros, na classe atual ou na classe base, não importa, uma hora um constructor parameterless implícito ou explícito será executado.

As vezes eu esqueço por que programo




Mas o 9gag me faz o favor de me lembrar.


quinta-feira, 16 de outubro de 2014

Duas funções úteis para manipulação de datas

De tempos em tempos precisamos fazer aquele processamento que só pode ser feito em dias úteis. Seja a data de pagamento de um boleto, o agendamento de uma entrevista e assim por diante.

O desafio disso está no fato de que temos feriados nacionais com dia fixo, feriados com dia variável porém computável (através de algoritmos) e feriados municipais.

Os municipais não tem outra forma de atender senão consultando uma tabela do banco de dados pelo código do município, mas os feriados nacionais fixos nós podemos dar uma bom começo.

Segue abaixo a função fn_dia_util que retorna 1 se o dia for útil e 0 se for sábado, domingo ou feriado (usando a função weekday para isso) e a função fn_proximo_dia_util, que verifica se o próximo dia é util e se não for vai acrescentando um em loop. Mesmo se o feriado cair numa sexta-feira ela retornará o próximo dia útil.


-- ############################################################################################################################################
-- # NOME   : fn_dia_util
-- # PRODUTO  : blog.vitorrubio.com.br
-- # DEVELOPER  : Vitor Luiz Rubio
-- # COPYRIGHT  : 
-- # OBJETIVO  : Dada uma data, diz se é dia útil (1) ou não (0)
-- # VERSAO   : 1.0
-- # DT. CRIACAO : 2014-10-16
-- # DT. ALTERACAO : 
-- #
-- # DEPENDENCIAS :
-- # 
-- # DEPENDENTES :
-- #
-- # HISTÓRICO
-- # 2014-10-16 : Criação
-- #  
-- ############################################################################################################################################ 

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION dbo.fn_dia_util
(
 @data datetime
)
RETURNS integer
AS
BEGIN

  declare @result integer
  
  if (
    --VERIFICA SE É SÁBADO OU DOMINGO
    (datepart(weekday, @data) IN (1,7)) or 
    --VERIFICA SE É ALGUM FERIADO NACIONAL DE DIA FIXO
    (convert(Varchar, day(@data))+'/'+convert(Varchar, month(@data)) in (
     '1/1',
     '21/4',
     '1/5',
     '7/9',
     '12/10',
     '2/11',
     '15/11',
     '25/12' 
    ))
    
    --TODO: COLOCAR AQUI OS OUTROS FERIADOS NACIONAIS DE DIA "COMPUTÁVEL" E FAZER UMA CONSULTA A OUTRA TABELA PARA VER OS FERIADOS MUNICIPAIS
   )
  begin
   set @result =  0
  end;
  else
  begin
   set @result = 1
  end;


  RETURN @result

END
GO


/*
TESTE:

 SELECT dbo.fn_dia_util('2015-1-1') -- 0 
 SELECT dbo.fn_dia_util(GETDATE()) -- 1 SE HOJE NÃO FOR FERIADO :)
 --drop function fn_dia_util
*/


-- ############################################################################################################################################
-- # NOME   : fn_next_dia_util
-- # PRODUTO  : blog.vitorrubio.com.br
-- # DEVELOPER  : Vitor Luiz Rubio
-- # COPYRIGHT  : 
-- # OBJETIVO  : retorna o próximo dia útil a partir de uma data
-- # VERSAO   : 1.0
-- # DT. CRIACAO : 2014-10-16
-- # DT. ALTERACAO : 
-- #
-- # DEPENDENCIAS :
-- # 
-- # DEPENDENTES :
-- #
-- # HISTÓRICO
-- # 2014-10-16 : Criação
-- #  
-- ############################################################################################################################################ 

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION dbo.fn_next_dia_util
(
 @data datetime
)
RETURNS datetime
AS
BEGIN

  declare @result datetime
  
  set @result = dateadd(day, 1, @data)
  
  while (dbo.fn_dia_util(@result) = 0)
  begin
   set @result = dateadd(day, 1, @result)
  end 


  RETURN @result

END
GO


/*
TESTE:

 SELECT dbo.fn_next_dia_util('2014-12-31') -- 2015-1-2 
 SELECT dbo.fn_next_dia_util('2014-04-18') -- 2014-4-22 porque segunda-feira é feriado
 SELECT dbo.fn_next_dia_util(GETDATE()) -- amanhã SE NÃO FOR FERIADO :)
 --drop function fn_dia_util
*/


Duas maneiras de se fazer split no Delphi XE2 parecido com a função split do C#


Para se fazer uma função split no Delphi basta usar array dinâmico ou list de string.
O exemplo abaixo mostra como.


function split(original: string; separador: string) : TStringArray;
var idx: integer;
tmp, item: string;
resultado: TStringArray;
begin

  idx:=0;
  SetLength(resultado, idx);
  tmp := original;

  while Pos(separador, tmp) > 0 do
  begin

    SetLength(resultado, length(resultado)+1);
    item := Copy(tmp, 1, Pos(separador, tmp)-1);
    tmp := Copy(tmp, Pos(separador, tmp) + length(separador), length(tmp) +  Pos(separador, tmp) - length(separador));
    resultado[idx] := item;
    inc(idx);

  end;
  SetLength(resultado, length(resultado)+1);
  resultado[idx] := tmp;
  Result := resultado;

end;




function split2(original: string; separador: string) : TList < string >;
var
  tmp, item: string;
begin
  result := TList< string >.Create;
  tmp := original;

  while Pos(separador, tmp) > 0 do
  begin
    Result.Add( Copy(tmp, 1, Pos(separador, tmp)-1));
    tmp := Copy(tmp, Pos(separador, tmp) + length(separador), length(tmp) +  Pos(separador, tmp) - length(separador));
  end;

  Result.Add(tmp);

end;

É isso aí, isso é usado em alguns outros posts desse blog.

quarta-feira, 15 de outubro de 2014

Reflexão no Javascript

Dado um objeto javascript, é possível varrer seus métodos e propriedades e até mesmo serializá-lo.
Para isso devemos fazer uma conversão forçada do objeto para um vetor, e varre-lo. Cada item desse vetor pode ser um método ou uma propriedade.
O que vai dizer se ele é um método ou uma propriedade é que seu tipo, dado pela função typeof():
  • quando, como string, for igual a "function" significa que ele é um método ou função.
  • caso contrário é uma propriedade.

Código da função de serialização
   ///Transforma um objeto em string considerandp se é null ou undefined
   function ObjToString(obj)
   {
    if(obj === null)
    {
     return "null";
    }
    
    if(typeof obj === "undefined")
    {     
     return "undefined";
    }
     
    return obj.toString();
   }
  
   ///escreve as propriedades do objeto na página
   function serialize(obj)
   {
    //coleção de métodos
    var metodos = [];
    //coleção de propriedades
    var propriedades = [];
    
    //varre as propriedades
    for (i in obj) 
    {
     //verifica se não é a própria função
     if (i != "serialize")
     {
      if (typeof(obj[i]) == "function") 
      {
       //se for método adiciona em uma coleção
       metodos.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
      }
      else
      {
       //senão adiciona na outra
       propriedades.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
      }
     }
    }
    
    //varre as coleções escrevendo na página
    document.write("metodos
");
    for (m in metodos) 
    {
     document.write(metodos[m]+"
");
    }    
    document.write("

propriedades
");
    for (p in propriedades) 
    {
     document.write(propriedades[p]+"
");
    }    
   } 
No caso dessa função, ela simplesmente lista as propriedades e métodos e os concatena a seus devidos valores, pulando linha. Isso poderia ser feito de outra forma, por exemplo, a função de serialização poderia gerar um JSON e usá-lo em uma requisição ajax, ou interpretá-lo com eval() e gerar um clone do objeto em questão (apenas as propriedades, um DTO), ou ainda serializá-lo em XML. Por enquanto vamos listar os métodos e propriedades na página mesmo. Depois tentamos gravar em uma string ou objeto json.
Note o uso do comando for ... in. for (i in obj)
Ele equivale ao foreach do c# e de outras linguagens. Ele varre todos os elementos de um array atribuindo a I o elemento do array de indice x quando for um array, ou a propriedade quando for um ojeto (como se fosse um hashtable/dictionay). Usando esse comando, para uma varredura geral sem armazenar ou utilizar o índice, você pode fazer uma varredura geral em um array sem se preocupar com os limites inferior e superior.
A função ObjToString apenas verifica se o objeto é nulo ou undefined antes de chamar .toString() nele.
Abaixo um exemplo de serialização do objeto window:
 serialize(window);
Com a saída:
 metodos
 function: postMessage: function () { [native code] }
 function: close: function () { [native code] }
 function: blur: function () { [native code] }
 function: focus: function () { [native code] }
 function: getSelection: function getSelection() { [native code] }
 function: print: function print() { [native code] }
 function: stop: function stop() { [native code] }
 function: open: function open() { [native code] }
 function: alert: function alert() { [native code] }
 function: confirm: function confirm() { [native code] }
 function: prompt: function prompt() { [native code] }
 function: find: function find() { [native code] }
 function: scrollBy: function scrollBy() { [native code] }
 function: scrollTo: function scrollTo() { [native code] }
 function: scroll: function scroll() { [native code] }
 function: moveBy: function moveBy() { [native code] }
 function: moveTo: function moveTo() { [native code] }
 function: resizeBy: function resizeBy() { [native code] }
 function: resizeTo: function resizeTo() { [native code] }
 function: matchMedia: function matchMedia() { [native code] }
 function: getComputedStyle: function getComputedStyle() { [native code] }
 function: getMatchedCSSRules: function getMatchedCSSRules() { [native code] }
 function: webkitConvertPointFromPageToNode: function webkitConvertPointFromPageToNode() { [native code] }
 function: webkitConvertPointFromNodeToPage: function webkitConvertPointFromNodeToPage() { [native code] }
 function: requestAnimationFrame: function requestAnimationFrame() { [native code] }
 function: cancelAnimationFrame: function cancelAnimationFrame() { [native code] }
 function: webkitRequestAnimationFrame: function webkitRequestAnimationFrame() { [native code] }
 function: webkitCancelAnimationFrame: function webkitCancelAnimationFrame() { [native code] }
 function: webkitCancelRequestAnimationFrame: function webkitCancelRequestAnimationFrame() { [native code] }
 function: captureEvents: function captureEvents() { [native code] }
 function: releaseEvents: function releaseEvents() { [native code] }
 function: btoa: function btoa() { [native code] }
 function: atob: function atob() { [native code] }
 function: setTimeout: function setTimeout() { [native code] }
 function: clearTimeout: function clearTimeout() { [native code] }
 function: setInterval: function setInterval() { [native code] }
 function: clearInterval: function clearInterval() { [native code] }
 function: webkitRequestFileSystem: function webkitRequestFileSystem() { [native code] }
 function: webkitResolveLocalFileSystemURL: function webkitResolveLocalFileSystemURL() { [native code] }
 function: openDatabase: function openDatabase() { [native code] }
 function: addEventListener: function addEventListener() { [native code] }
 function: removeEventListener: function removeEventListener() { [native code] }
 function: dispatchEvent: function dispatchEvent() { [native code] }


 propriedades
 object: top
 object: window
 object: location
 object: external
 object: chrome
 object: document
 object: speechSynthesis
 object: localStorage
 object: sessionStorage
 object: applicationCache
 object: webkitStorageInfo
 object: indexedDB
 object: webkitIndexedDB
 object: crypto
 object: CSS
 object: performance
 object: console
 number: devicePixelRatio
 object: styleMedia
 object: parent
 object: opener
 object: frames
 object: self
 string: defaultstatus
 string: defaultStatus
 string: status
 string: name
 number: length
 boolean: closed
 number: pageYOffset
 number: pageXOffset
 number: scrollY
 number: scrollX
 number: screenTop
 number: screenLeft
 number: screenY
 number: screenX
 number: innerWidth
 number: innerHeight
 number: outerWidth
 number: outerHeight
 boolean: offscreenBuffering
 object: frameElement
 object: clientInformation
 object: navigator
 object: toolbar
 object: statusbar
 object: scrollbars
 object: personalbar
 object: menubar
 object: locationbar
 object: history
 object: screen
 object: onautocompleteerror
 object: onautocomplete
 object: ondeviceorientation
 object: ondevicemotion
 object: onunload
 object: onstorage
 object: onpopstate
 object: onpageshow
 object: onpagehide
 object: ononline
 object: onoffline
 object: onmessage
 object: onlanguagechange
 object: onhashchange
 object: onbeforeunload
 object: onwaiting
 object: onvolumechange
 object: ontoggle
 object: ontimeupdate
 object: onsuspend
 object: onsubmit
 object: onstalled
 object: onshow
 object: onselect
 object: onseeking
 object: onseeked
 object: onscroll
 object: onresize
 object: onreset
 object: onratechange
 object: onprogress
 object: onplaying
 object: onplay
 object: onpause
 object: onmousewheel
 object: onmouseup
 object: onmouseover
 object: onmouseout
 object: onmousemove
 object: onmouseleave
 object: onmouseenter
 object: onmousedown
 object: onloadstart
 object: onloadedmetadata
 object: onloadeddata
 object: onload
 object: onkeyup
 object: onkeypress
 object: onkeydown
 object: oninvalid
 object: oninput
 object: onfocus
 object: onerror
 object: onended
 object: onemptied
 object: ondurationchange
 object: ondrop
 object: ondragstart
 object: ondragover
 object: ondragleave
 object: ondragenter
 object: ondragend
 object: ondrag
 object: ondblclick
 object: oncuechange
 object: oncontextmenu
 object: onclose
 object: onclick
 object: onchange
 object: oncanplaythrough
 object: oncanplay
 object: oncancel
 object: onblur
 object: onabort
 object: onwheel
 object: onwebkittransitionend
 object: onwebkitanimationstart
 object: onwebkitanimationiteration
 object: onwebkitanimationend
 object: ontransitionend
 object: onsearch
 number: TEMPORARY
 number: PERSISTENT
Agora imagine um objeto json, por exemplo pessoa:
   var pessoa = {
    nome:"Vitor",
    sobrenome:"Rubio",
    email:"vitorrubio@gmail.com",
    idade:30,
    dataCadastro:"14/10/2014",
    dependente:null,
    hobby:undefined};
Com a saída:
 metodos


 propriedades
 string: nome: Vitor
 string: sobrenome: Rubio
 string: email: vitorrubio@gmail.com
 number: idade: 30
 string: dataCadastro: 14/10/2014
 object: dependente: null
 undefined: hobby: undefined
Repare também que foi necessário colocar uma excessão quanto ao método "serialize" para ele não serializar a si mesmo. Se um método for nativo do browser ele é serializado como [native code], mas se for um método seu então todo o source do método é serializado. Veja o poder disso: nas linguagens compiladas como C ou Delphi, ou nas linguagens com compilação Just In Time como C# e Java, os objetos podem ter suas propriedades e valores varridos, serializando-os para xml, json e outros formatos. Mas apenas seus campos e propriedades. NUNCA SEUS MÉTODOS. Então nas aplicações, não importa se você usa um banco de dados relacional ou orientado a objeto, você nunca poderia armazenar o código executável (métodos) no banco de dados. Apenas os dados poderiam ser armazenados. Isso significaria ter que tratar os dados com functions e stored procedures no banco de dados ou reconstituir o objeto e tratar na aplicação. Com javascript é diferente. Você pode salvar o SOURCE de métodos e argumentos em um banco de dados, trazêlos de volta a vida com eval(), JSON.parse ou jQuery.parseJSON e executar as mesmas funções que eles já possuiam. Não é possível fazer isso com JSON.parse(), apenas com eval, pois entende-se que o JSON é apenas para transferência de DADOS. Mesmo assim você pode embutir o eval como mostrado nesse link
O método abaixo faz o mesmo que o serialize, mas joga o resultado em uma string.
   ///o mesmo que serialize só que retornando uma string
   function SerializeObjToString(obj)
   {
    var metodos = [];
    var propriedades = [];
    var resultado = "";
    
    for (i in obj) 
    {
     //tirada a restrição do "serialize". Deixa trazer tudo. 
      if (typeof(obj[i]) == "function") 
      {
       metodos.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
      }
      else
      {
       propriedades.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
      }
    }
    
    //a string já é formatada
    resultado+="metodos
";
    for (m in metodos) 
    {
     resultado+=metodos[m]+"
";
    }    
    resultado+="

propriedades
";
    for (p in propriedades) 
    {
     resultado+=propriedades[p]+"
";
    } 

    return resultado;
   }
   
O método abaixo transforma o objeto javascript em uma string JSON.
   ///gera uma string json para ser interpretada com eval ou json.parse
   ///não é segura quanto à recursividade, referência cíclica
   function SerializeObjToJSON(obj)
   {
    var metodos = [];
    var propriedades = [];
    var resultado = "";
    
    for (i in obj) 
    {
     //tirada a restrição do "serialize". Deixa trazer tudo. 
      
      //verifica primeiro se o objeto é undefined, para retornar undefined 
      if(typeof (obj[i]) === "undefined")
      {       
       metodos.push("\""+i+"\"" + ":" + "\"undefined\"" );
      }
      //se for uma function retorna o corpo da mesma com ObjToString sem aspas
      else if (typeof(obj[i]) == "function") 
      {
       metodos.push("\""+i+"\""  + ":"  + ObjToString(obj[i]) );
      }
      //se for um número usa ObjToString para retornar sem aspas
      else if (typeof(obj[i]) == "number") 
      {
       metodos.push("\""+i+"\""  + ":" + ObjToString(obj[i]) );
      }
      //se for objeto verifica se é nulo ou não
      else if (typeof(obj[i]) == "object") 
      {
       //se for nulo simplesmente concatena null
       if(obj[i] === null)
       {
        metodos.push("\""+i+"\""  + ":" + "\"null\"" );
       }
       //senão chama a propria função e serializa recursivamente
       else
       {
        metodos.push("\""+i+"\""  + ":" + SerializeObjToJSON(obj[i]) );
       }
      }
      else
      {
       //senão assume que é string e poe entre aspas. Se tiver errado é fácil alterar. 
       propriedades.push("\""+i+"\""  + ":\"" + ObjToString(obj[i])+"\"" );
      }
    }
    
    //começa e termina entre chaves
    resultado+="{";
    for (var m = 0; m 0)
      {
       resultado+=",";
      }
     }
     else
     {
      resultado+=",";
     }
     resultado+="\r\n";
    }    
    
    for (var p = 0; p < propriedades.length; p++) 
    {
     resultado+=propriedades[p];
     
     if(p < propriedades.length-1)
     {
      resultado+=",";
     }
     
     resultado+="\r\n";
     
    }
    resultado+="}";  

    return resultado;
   }
Que pode ser transformada de volta em objeto da seguinte maneira.
    function evalJson()
    { try
     {
      //poe a string entre parenteses antes do eval      
      var txt = SerializeObjToJSON(pessoa);
      alert(txt);
      //var obj = eval("(" + txt + ")"); //para usar eval
      var obj = JSON.parse(txt); //para usar JSON.parse nativo
      //var obj = JSON && JSON.parse(txt) || $.parseJSON(txt); //para decidir de acordo com o browser se vai usar JSON nativo ou a versão do jQuery
      alert(obj.email);
     }
     catch(e)
     {
      alert(e.message);
     }
    }
Bom, por enquanto é isso. Acredito que esse é o meu maior post sobre javascript. Pretendo postar amanhã uma galeria com jQuery e dar uma organizada nesse blog.
Baixar o Exemplo
Have fun :)

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)