Tabs with Flapjax

3 views
Skip to first unread message

therac25

unread,
Jul 6, 2009, 7:36:25 AM7/6/09
to Flapjax
Hello Flapjax team and thanks for your work !

I find myself constantly re-implementing tabs widgets at work, so I
made a generic one with jQuery. Then I thought I'd try with Flapjax
(something similar to http://andreaslagerkvist.com/jquery/super-simple-tabs/).

At first I didn't know how to get started, until I realized that the
css classes I was changing through callbacks in my jQuery code, really
are time varying values. I really liked how Flapjax let me express how
each tab state is dependent on the state of the others:

tabSelectedB = mergeE(
tabClickE[i],
notE(mergeE.apply(this, otherTabsClickE))
).startsWith(i == 0 ? true : false);

The logic is explicit: a tab is selected if it's been clicked of if
another has not been clicked
Expressing values dependencies this way is a different way of thinking
about problems, higher level, I find this pretty exciting...

On another note, I think adding such a "Tab" or "Navigation" example
to the the Flapjax website demos would be a good idea. This is the
kind of widget you constantly need to deal with, and potential
adopters might relate to it. Yet it is simple enough to be easily
understood by Flapjax beginners. (The form validation demo is also a
good example of "real-world" widget)

This is my first piece of Flapjax code so it's probably ugly and
suboptimal, thanks in advance for any comments or suggestions.

The code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<title>untitled</title>

<style type="text/css" media="screen">
a.selected { background:red; }
div { display:none; }
div.selected { display:block; }
</style>


<script type="text/javascript" src="../flapjax-2.0.1.min.js"></
script>

<script type="text/javascript">


function loader() {
// each tab and each associated content has a class which is a
behavior value
var tabsContainer = document.getElementById('tabs');
var tabs = tabsContainer.getElementsByTagName('a');
var nbTabs = tabs.length;
var tabClickE = [], otherTabsClickE = []; // tabs click events
var tabSelectedB, tabClassB, contentId, otherTabs; // local loop
vars

for(var i=0; i < nbTabs; i++){
// event for the current tab
tabClickE[i] = extractEventE(tabs[i],'click');
// all other tabs
otherTabs = filter(function(elt){ return elt !== tabs[i] ?
true : false ; }, tabs);
// other tabs click events
otherTabsClickE = map(function(elt) { return extractEventE
(elt,'click'); }, otherTabs);
// a tab is selected, if event is true or other tabs events
are false
// we convert the event into a behavior to specify a starting
state (startsWith): the first tab is selected
tabSelectedB = mergeE(
tabClickE[i],
notE(mergeE.apply(this, otherTabsClickE))
).startsWith(i == 0 ? true : false);
// tabClassB is a behavior equals to "selected" when a tab is
selected
tabClassB = liftB(function(selected){ return selected ?
"selected" : ""; }, tabSelectedB);

// we insert the behavior value as a css classes
insertValueB(tabClassB, tabs[i], 'className');
contentId = tabs[i].href.match(/#(.*)/)[1];
insertValueB(tabClassB, contentId, 'className');
}
}

</script>


</head>

<body onload="loader()">



<ul id="tabs">
<li><a href="#tab-content-1">Content 1</a></li>
<li><a href="#tab-content-2">Content 2</a></li>
<li><a href="#tab-content-3">Content 3</a></li>
</ul>

<div id="tab-content-1"><p>1. Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam </p>
</div>

<div id="tab-content-2"><p>2. Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum. </p>
</div>

<div id="tab-content-3"><p>3. Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum. </p>

</div>

</body>
</html>



T25

Artyom Shalkhakov

unread,
Jul 6, 2009, 11:21:20 PM7/6/09
to fla...@googlegroups.com
Hi,

2009/7/6 therac25 <th3r...@googlemail.com>:


> I find myself constantly re-implementing tabs widgets at work, so I
> made a generic one with jQuery. Then I thought I'd try with Flapjax
> (something similar to http://andreaslagerkvist.com/jquery/super-simple-tabs/).

It was the same thing here too. Constant reimplementation modulo some quirks.

> At first I didn't know how to get started, until I realized that the
> css classes I was changing through callbacks in my jQuery code, really
> are time varying values. I really liked how Flapjax let me express how
> each tab state is dependent on the state of the others:

Insights Flapjax gives. :)

> On another note, I think adding such a "Tab" or "Navigation" example
> to the the Flapjax website demos would be a good idea. This is the
> kind of widget you constantly need to deal with, and potential
> adopters might relate to it. Yet it is simple enough to be easily
> understood by Flapjax beginners. (The form validation demo is also a
> good example of "real-world" widget)

I agree with you.

This code is dealing with something along the lines of the list zipper:

>          for(var i=0; i < nbTabs; i++){
>            // event for the current tab
>            tabClickE[i] = extractEventE(tabs[i],'click');
>            // all other tabs
>            otherTabs = filter(function(elt){ return elt !== tabs[i] ?
> true : false ; }, tabs);

You can simplify this:

>            // other tabs click events
>        otherTabsClickE = map(function(elt) { return extractEventE
> (elt,'click'); }, otherTabs);

into this:

> otherTabsClickE = map(clicksE, otherTabs);

Higher-order functions can do wonders! :)

Other than that, I don't have any objections to your code, it seems
natural to me.

Great work.

Cheers,
Artyom Shalkhakov.

Arjun Guha

unread,
Jul 8, 2009, 6:37:28 AM7/8/09
to fla...@googlegroups.com
Tabs do make a good demo. I'd implemented tabs for an application I
wrote last year, though I went about it differently. I implemented a
button bar (the tabs along the top) and a pane (the content of a tab)
as separate components.

The code is here. The buttonBar function is unnecessarily long
because I support tabs along both the left and right edges:

http://github.com/arjunguha/173tourney/blob/dce044761b008cb685a675a1f35be6aff66fed21/static/web/lib/tourney.js#L84

You can see how buttonBar and panelB are used to create a tab here:

http://github.com/arjunguha/173tourney/blob/dce044761b008cb685a675a1f35be6aff66fed21/static/web/index.html#L841

The newAsgn function returns a reactive DOM element that is the tab
control. However, it does not display it. Therefore, I could
arbitrarily nest tabs within other controls and just display the final
product.

Arjun

therac25

unread,
Jul 8, 2009, 12:33:17 PM7/8/09
to Flapjax
Thanks Arjun, I'll take a look

A nice aspect of what I did is that if Javascript is disabled, all
content is displayed and the tabs still let you jump to their relative
content through the use of anchors.
My employer wants so-called "gracefull degradation"

I am thinking about other widgets that would be good additions to the
Flapjax demos (again these are often needed at work) :

1) a carousel (or slideshow) using an external library for animation
purpose, but using Flapjax for the widget logic
2) an upload progress bar (showing how much data had been uploaded in
"real-time")

Cheers

T25

On Jul 8, 11:37 am, Arjun Guha <ar...@cs.brown.edu> wrote:
> Tabs do make a good demo.  I'd implemented tabs for an application I  
> wrote last year, though I went about it differently.  I implemented a  
> button bar (the tabs along the top) and a pane (the content of a tab)  
> as separate components.
>
> The code is here.  The buttonBar function is unnecessarily long  
> because I support tabs along both the left and right edges:
>
> http://github.com/arjunguha/173tourney/blob/dce044761b008cb685a675a1f...
>
> You can see how buttonBar and panelB are used to create a tab here:
>
> http://github.com/arjunguha/173tourney/blob/dce044761b008cb685a675a1f...
>
> The newAsgn function returns a reactive DOM element that is the tab  
> control.  However, it does not display it.  Therefore, I could  
> arbitrarily nest tabs within other controls and just display the final  
> product.
>



> Arjun
>
> On Jul 6, 2009, at 23:21 , Artyom Shalkhakov wrote:
>
>
>
> > Hi,
>
> > 2009/7/6 therac25 <th3ra...@googlemail.com>:
> >> I find myself constantly re-implementing tabs widgets at work, so I
> >> made a generic one with jQuery. Then I thought I'd try with Flapjax
> >> (something similar tohttp://andreaslagerkvist.com/jquery/super-simple-tabs/)

Arjun Guha

unread,
Jul 9, 2009, 4:05:16 AM7/9/09
to fla...@googlegroups.com
That is a nice feature. Unfortunately, what may be good functional-
reactive style may not degrade gracefully.

Arjun
Reply all
Reply to author
Forward
0 new messages