Tabs How To

Este componente facilita a criação de um sistema de tabs, que pode ser usado de três formas diferentes:

  • Com toda a estrutura e conteúdo em HTML presentes na página, usando o JS apenas para o comportamento, e degradando na falta deste
  • Com o menu em HTML presente na página e conteúdo adicionado dinamicamente por JS (AJAX, callback ou uma simples string de conteúdo.
  • Criar o sistema de tabs programaticamente para posterior adição ao HTML (útil para inserção em componentes JavaScript? mais complexos).

Demo

 http://js.sapo.pt/SAPO/Component/Tabs/sample/



Configuração inicial

Para utilizar este componente é necessário incluir os seguintes ficheiros:

<script type="text/javascript" src="http://js.sapo.pt/SAPO/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Loaded/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Css/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Event/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Element/0.1/"></script
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Utility/Url/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Utility/Dimensions/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Communication/Ajax/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Component/Tabs/0.1/"></script>

Notas importantes

Cada "tab container" tem uma classe sapo-tabs-container e a tab visível tem uma classe sapo-active-container. A definição do css destas classes é injectada automaticamente na página, mas esse css pode ser extendido.

Ao menu de tabs é aplicada uma classe sapo-tabs-nav, e ao item actualmente activo deste menu é aplicada uma classe sapo-active-nav.

Os nomes destas classes são configuráveis através das opções de inicialização, mas nos modos em que é necessário ter HTML presente na página a existência destas classes no código HTML é OBRIGATÓRIA.

Após a listagem dos modos segue-se uma explicação de outros parâmetros possíveis para aplicação de comportamentos às tabs e outras opções.

Apenas o primeiro modo listado é "progressively enhanced", podendo por isso ser usado mesmo que o JavaScript? seja desactivado. Além disso, este primeiro método permite que se usem anchor links para aceder a uma tab, suportando também vários níveis de nested tabs. Exemplo:  http://js.host/SAPO/Component/Tabs/sample/#description2 ou  http://js.host/SAPO/Component/Tabs/sample/#/news/description2 sendo que o segundo tipo de links apenas funcionam correctamente com JavaScript?.



Primeiro modo - Adicionar comportamento a HTML já presente na página

Este modo pressupõe que o utilizador já tem HTML presente na página e pretende adicionar o comportamento de tabs a este HTML. Para tal, é necessário que o HTML respeite a seguinte estrutura, incluindo classes de css:

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="#secondTabName">second tab name</a></li>
    </ul>
    
    <div id="firstTabName" class="sapo-tabs-container">
        first tab content
    </div>

    <div id="secondTabName" class="sapo-tabs-container">
        second tab content
    </div>
</div>

As classes aqui especificadas são obrigatórias para a aplicação do comportamento.

Opcionalmente, e apenas neste primeiro modo pode-se adicionar uma classe sapo-tabs-nojs no container top level do sistema de tabs, para aplicar um estilo específico para quando o JavaScript? é desactivado. Ao instanciar o módulo de tabs, esta classe é automaticamente removida pelo código JavaScript?, se existir.

Apenas falta aplicar o comportamento JavaScript? necessário. Para tal, apenas é necessário o seguinte código, dentro de um evento DOM ready ou DOM loaded:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs("tabSet");
});

Este é o caso mais simples em que se passa como parâmetro apenas a id do div no qual vai ser aplicado o comportamento. Na prática, isto é o mesmo que instanciar o objecto de Tabs com o objecto de opções e passar apenas o parâmetro container:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs({container: "tabSet"});
});

Em que tabSet é a id do container do HTML relativo às tabs.

Nested tabs

Neste primeiro modo, para usar nested tabs, deve-se usar o markup e código JavaScript? seguintes. Atenção que isto apenas é válido para o primeiro modo. Nos outros modos, nested tabs devem ser instanciadas e injectadas separadamente na markup.

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="#secondTabName">second tab name</a></li>
    </ul>
    
    <div id="firstTabName" class="sapo-tabs-container">
        first tab content
    </div>

    <div id="secondTabName" class="sapo-tabs-container">
        second tab content

		<div id="tabSet2">
		    <ul class="sapo-tabs-nav">
		        <li><a href="#firstNestedTabName">first tab name</a></li>
		        <li><a href="#secondNestedTabName">second tab name</a></li>
		    </ul>

		    <div id="firstNestedTabName" class="sapo-tabs-container">
		        first nested tab content
		    </div>

		    <div id="secondNestedTabName" class="sapo-tabs-container">
		        second nested tab content
		    </div>
		</div>
    </div>
</div>

Com a seguinte invocação:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs(
		container: "tabSet",
		nested: {
			"secondTabName": new SAPO.Component.Tabs("tabSet2")
		}
	);
});

Todas as nested tabs devem ser instanciadas no parâmetro "nested", associadas à tab dentro da qual vão existir. Podem existir vários níveis de nested tabs, sempre declaradas da mesma forma.

Links internos

Neste primeiro modo, é possível criar links para aceder a uma dada tab, que possam ser usados em vez do menu de tabs. Para tal, esse link apenas necessita de referenciar a anchor da tab pretendida, e ter a classe sapo-tabs-innerlink. Exemplo:

<a href="#stuff" class="sapo-tabs-innerlink">internal link</a>



Segundo modo - Adicionar comportamento a um menu HTML sem conteúdo presente na página

Este modo pressupõe apenas a existência de um menu em HTML já presente na página, sendo todo o conteúdo das tabs gerado através de código JavaScript?. O HTML necessário é o seguinte:

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="#secondTabName">second tab name</a></li>
    </ul>
</div>

As classes aqui especificadas são obrigatórias para a aplicação do comportamento.

Para aplicar o comportamento JavaScript? é necessário o seguinte código, dentro de um evento DOM ready ou DOM loaded:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs({
        container: "tabSet",
        tabs: [
            { content: "this is the first tab" },
            { content: "this is the second tab" }
        ]
    });
});

O parâmetro content deve ser uma string com código HTML ou uma função que retorne código HTML (ver mais sobre isto).

Se o utilizador pretender carregar conteúdo HTML através de um pedido GET XMLHttpRequest pode especificar o url do pedido no parâmetro href do link e especificar o parâmetro remote a true. Para necessidades mais específicas deve ser desenvolvido o comportamento necessário dentro de uma callback passada ao parâmetro content. Exemplo de como carregar conteúdo por AJAX:

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="request.html">second tab name</a></li>
    </ul>
</div>


SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs({
        container: "tabSet",
        tabs: [
            { content: "this is the first tab" },
            { remote: true }
        ]
    });
});



Terceiro modo - Criar tabs programaticamente

Este modo permite que as tabs sejam criadas através de JavaScript? e posteriormente injectadas no DOM. Para tal, é necessário o seguinte código:

var tabs = new SAPO.Component.Tabs({
    tabs: [
        { title: "first tab title", content: "this is the first tab" },
        { title: "second tab title", content: "this is the second tab" }
    ]
});
s$("tabSet").appendChild(tabs.getTabs());

Neste modo, instancia-se um objecto do tipo Tabs, que possui um método getTabs que irá retornar os objectos do DOM gerados de acordo com as opções especificadas. Estes objectos podem então ser injectados no DOM. Neste modo é necessário especificar um parâmetro title para cada tab, que irá ser o título desta tab no menu.

O parâmetro content deve ser uma string com código HTML ou uma função que retorne código HTML. Se o utilizador pretender carregar conteúdo HTML através de XMLHttpRequest pode usar o parâmetro remote em vez do parâmetro content para especificar um url que retorne HTML através de um pedido GET. Para necessidades mais específicas deve ser desenvolvido o comportamento necessário dentro de uma callback passada ao parâmetro content. Exemplo de como carregar conteúdo por AJAX:

var tabs = new SAPO.Component.Tabs({
    tabs: [
        { title: "first tab title", content: "this is the first tab" },
        { title: "second tab title", remote: "remote.html" }
    ]
});

Após inicializar a instância, o método getTabs retorna os objectos criados para o conjunto de tabs definidas na inicialização, que devem então ser injectadas no DOM:

var tabSet = document.createElement("DIV");

tabSet.appendChild(tabs.getTabs());

document.body.appendChild(tabSet);



Callback no parâmetro content

O parâmetro content pode aceitar uma callback em vez de uma string. Esta callback deve retornar HTML que será injectado na tab, ou, caso isto não seja possível devido a chamadas assíncronas (AJAX), a callback recebe um objecto container com um método loadContent através do qual é possível carregar o conteúdo para a tab. Exemplo:

var tabs = new SAPO.Component.Tabs({
    tabs: [
        {
            title: "first tab title",
            content: function(container){
                container.loadContent("<p>some html</p>");
            }
        }
    ]
});



Outras opções

O objecto passado ao constructor SAPO.Component.Tabs pode conter algumas opções adicionais:

  • cache: true|false - esta opção apenas é aplicável ao segundo e terceiro modo de funcionamento. Ao activar esta opção, as tabs apenas são criadas no DOM uma vez, e os pedidos Ajax apenas serão feitos uma vez. Se o conteúdo pode mudar de cada vez que a tab é activada, esta opção não deve ser usada.
  • tabNavClass - nome da classe aplicada ao menu de tabs
  • activeNavClass - nome da classe aplicada ao item activo do menu de tabs
  • tabContainerClass - nome da classe aplicada ao container ou containers de tabs
  • activeContainerClass - nome da classe aplicada ao container actualmente activo
  • nojsContainerClass - nome da classe aplicada a ser removida do top level container, para quando JS está desactivado (apenas para primeiro modo)
  • innerLinkClass - nome da classe usada para links internos
  • nested - objecto que contém as nested tabs no primeiro nível abaixo deste sistema de tabs (apenas para primeiro modo)
  • loadCallback - callback executada após o carregamento de qualquer tab. Recebe como parâmetros o DOM object do container da tab e o objecto passado no array tabs correspondente a esta tab.
  • Cada objecto do array tabs permite especificar também uma opção de nome events que é uma callback aplicada à tab em questão. É semelhante ao loadCallback mas aplicado a uma tab específica. Recebe como parâmetro o DOM object do container da tab.