thomascube
2011-12-20 bab0433a274f4e22130793b5e77d3767492c4a9f
First steps for Larry's address book

3 files added
8 files modified
578 ■■■■■ changed files
program/steps/addressbook/edit.inc 9 ●●●●● patch | view | raw | blame | history
skins/larry/addressbook.css 182 ●●●●● patch | view | raw | blame | history
skins/larry/images/buttons.png patch | view | raw | blame | history
skins/larry/images/listicons.png patch | view | raw | blame | history
skins/larry/mail.css 22 ●●●● patch | view | raw | blame | history
skins/larry/styles.css 108 ●●●●● patch | view | raw | blame | history
skins/larry/templates/addressbook.html 92 ●●●●● patch | view | raw | blame | history
skins/larry/templates/compose.html 4 ●●●● patch | view | raw | blame | history
skins/larry/templates/contact.html 33 ●●●●● patch | view | raw | blame | history
skins/larry/templates/contactedit.html 52 ●●●●● patch | view | raw | blame | history
skins/larry/ui.js 76 ●●●●● patch | view | raw | blame | history
program/steps/addressbook/edit.inc
@@ -176,9 +176,8 @@
{
  global $OUTPUT;
  // add ID if not given
  if (!$attrib['id'])
    $attrib['id'] = 'rcmUploadbox';
  // set defaults
  $attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes');
  // find max filesize value
  $max_filesize = parse_bytes(ini_get('upload_max_filesize'));
@@ -196,10 +195,10 @@
      $hidden->show() .
      html::div(null, $input->show()) .
      html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) .
      html::div('buttons',
      (get_boolean($attrib['buttons']) ? html::div('buttons',
        $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' .
        $button->show(rcube_label('upload'), array('class' => 'button mainaction', 'onclick' => JS_OBJECT_NAME . ".command('upload-photo', this.form)"))
      )
      ) : '')
    )
  );
skins/larry/addressbook.css
@@ -10,4 +10,184 @@
 * See http://creativecommons.org/licenses/by-sa/3.0/ for details.
 *
 * $Id$
 */
 */
#addressview-left {
    position: absolute;
    top: 0;
    left: 0;
    width: 220px;
    bottom: 0;
}
#addressview-right {
    position: absolute;
    top: 0;
    left: 232px;
    right: 0;
    bottom: 0;
}
#addressbooktoolbar {
    position: absolute;
    top: -6px;
    left: 0;
    right: 0;
    height: 40px;
    white-space: nowrap;
}
#directorylistbox {
    position: absolute;
    top: 42px;
    left: 0;
    width: 100%;
    bottom: 0;
}
#addresslist {
    position: absolute;
    top: 42px;
    left: 0;
    width: 280px;
    bottom: 0;
}
#contacts-box {
    position: absolute;
    top: 42px;
    left: 292px;
    right: 0;
    bottom: 0;
}
#addressview-left #quicksearchbar input {
    width: 156px;
}
#directorylist li a,
#contacts-table .contact td.name {
    background: url(images/listicons.png) -100px 0 no-repeat;
    overflow: hidden;
    padding-left: 36px;
    text-overflow: ellipsis;
}
#directorylist li.addressbook a {
    background-position: 6px -766px;
}
#directorylist li.addressbook.selected a {
    background-position: 6px -791px;
}
#directorylist li.contactgroup a {
    padding-left: 62px;
    background-position: 32px -1555px;
}
#directorylist li.contactgroup.selected a {
    background-position: 32px -1579px;
}
#contacts-table .contact td.name {
    background-position: 6px -1603px;
}
#contacts-table .contact.selected td.name,
#contacts-table .contact.unfocused td.name {
    background-position: 6px -1627px;
    font-weight: bold;
}
#contact-frame {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 28px;
    border: 0;
}
#headerbuttons {
    position: absolute;
    top: 48px;
    right: 10px;
    width: auto;
    z-index: 10;
}
#sourcename {
    color: #999;
    font-size: 10px;
    margin: -5px 0 8px 2px;
}
#contactphoto {
    float: left;
    margin: 0 18px 20px 0;
    width: 112px;
}
#contactpic {
    width: 112px;
    min-height: 112px;
    background: white;
}
#contactpic img {
    width: 112px;
}
#contacthead {
    border: 0;
    margin: 0 20em 1em 0;
    padding: 0;
    line-height: 1.5em;
    font-size: 12px;
}
#contacthead .names span.namefield,
#contacthead .names input {
    font-size: 140%;
    font-weight: bold;
}
#contacthead .displayname span.namefield {
    font-size: 120%;
    font-weight: bold;
}
#contacthead span.nickname:before,
#contacthead span.nickname:after,
#contacthead input.ff_nickname:before,
#contacthead input.ff_nickname:after {
    content: '"';
}
#contacthead input {
    margin-right: 6px;
    margin-bottom: 0.2em;
}
#contacthead .names input,
#contacthead .addnames input {
    width: 180px;
}
#contacthead input.ff_prefix,
#contacthead input.ff_suffix {
    width: 90px;
}
a.deletebutton {
    position: relative;
    left: 5px;
    top: -3px;
    display: inline-block;
    width: 24px;
    height: 18px;
    text-decoration: none;
    text-indent: -1000px;
    background: url(images/buttons.png) -7px -337px no-repeat;
}
skins/larry/images/buttons.png

skins/larry/images/listicons.png

skins/larry/mail.css
@@ -541,14 +541,16 @@
    background-position: -24px -1036px;
}
#messagelist tr td.flag span.unflagged:hover {
#messagelist tr td.flag span.unflagged:hover,
#messagelist tr td.status span.msgicon:hover {
    background-position: 0 -1056px;
}
#messagelist tr td.subject span.msgicon,
#messagelist tr td.subject span.unreadchildren {
    background-position: 0 -1056px;
    margin: 0 4px 0 0;
    margin: 0 1px 0 0;
    width: 24px;
}
#messagelist tr td.subject span.replied {
@@ -580,8 +582,13 @@
*/
#messagelist tr td.status span.status,
#messagelist tr td.status span.unread,
#messagelist tr td.subject span.unread {
#messagelist tr td.subject span.unread,
#messagelist tr td.status span.unread:hover {
    background-position: 0 -1016px;
}
#messagelist thead tr td.status span.status {
    background-position: -24px -1016px;
}
#messagelist tr td div.collapsed {
@@ -1132,10 +1139,11 @@
#compose-attachments {
    position: absolute;
    right: 0;
    top: 0;
    top: 1px;
    bottom: 0;
    width: 240px;
    background: #f0f0f0;
    border-left: 1px solid #ddd;
    padding: 8px;
    overflow: auto;
}
@@ -1171,3 +1179,9 @@
    border: 0 !important;
}
#composebody_toolbargroup {
    border-bottom: 1px solid #ddd;
}
skins/larry/styles.css
@@ -35,6 +35,7 @@
input[type="text"],
input[type="password"],
textarea {
    margin: 0; /* Safari by default adds a margin */
    padding: 4px;
    border: 1px solid #b2b2b2;
    border-radius: 4px;
@@ -82,6 +83,7 @@
    -webkit-box-shadow: 0 1px 1px 0 #ccc;
    -moz-box-shadow: 0 1px 1px 0 #ccc;
    text-decoration: none;
    outline: none;
}
.formbuttons input.button {
@@ -103,7 +105,8 @@
    -moz-box-shadow: 0 1px 1px 0 #ccc, inset 0 1px 0 0 #888;
}
.formbuttons input.button:hover {
.formbuttons input.button:hover,
.formbuttons input.button:focus {
    color: #f2f2f2;
    border-color: #465864;
    box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #888;
@@ -176,7 +179,8 @@
}
a.button:hover,
input.button:hover {
input.button:hover,
input.button:focus {
    border-color: #4fadd5;
    box-shadow: 0 0 2px 1px rgba(71,135,177, 0.6);
    -moz-box-shadow: 0 0 2px 1px rgba(71,135,177, 0.6);
@@ -342,6 +346,11 @@
a.iconlink.edit {
    background-position: -7px -397px;
}
a.iconlink.delete {
    background-position: -7px -337px;
}
/*** message bar ***/
@@ -698,6 +707,10 @@
    margin-top: 1px;
}
.boxfooter .listbutton.disabled {
    opacity: 0.4;
}
.boxfooter .listbutton .inner {
    display: inline-block;
    width: 48px;
@@ -707,7 +720,11 @@
}
.boxfooter .listbutton.add .inner {
    background-position: 10px -1210px;
    background-position: 10px -1211px;
}
.boxfooter .listbutton.delete .inner {
    background-position: 10px -1252px;
}
.boxfooter .listbutton.groupactions .inner {
@@ -758,6 +775,7 @@
    top: 0;
    left: 0;
    width: 100%;
    z-index: 100;
}
.boxcontent {
@@ -892,11 +910,12 @@
    -o-box-shadow: inset 0 1px 0 0 #fff;
}
#login-form input.button:hover {
    box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #fff;
    -moz-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #fff;
    -webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #fff;
    -o-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #fff;
#login-form input.button:hover,
#login-form input.button:focus {
    box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9), inset 0 1px 0 0 #fff;
    -moz-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9), inset 0 1px 0 0 #fff;
    -webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9), inset 0 1px 0 0 #fff;
    -o-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9), inset 0 1px 0 0 #fff;
}
#login-form input.button:active {
@@ -982,7 +1001,7 @@
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 28px 2px 2px 2px;
    padding: 28px 2px 0 2px;
    text-shadow: 0px 1px 1px #eee;
    box-shadow: none;
    -moz-box-shadow: none;
@@ -1067,6 +1086,18 @@
.toolbar a.button.spellcheck {
    background-position: center -930px;
}
.toolbar a.button.search {
    background-position: center -970px;
}
.toolbar a.button.import {
    background-position: center -1010px;
}
.toolbar a.button.export {
    background-position: center -1050px;
}
@@ -1228,6 +1259,11 @@
    margin: 20px 0 4px 0;
}
.ui-dialog .prompt input {
    display: block;
    margin: 8px 0;
}
.hint {
    margin: 4px 0;
    color: #999;
@@ -1300,3 +1336,57 @@
    background: url(images/buttons.png) -8px -360px no-repeat;
}
/*** fieldset tabs ***/
.tabsbar {
    margin-bottom: 10px;
    padding-top: 15px;
    height: 27px;
}
.tabsbar .tablink {
    padding: 15px 1px 15px 0;
    background: #f8f8f8;
    background: -moz-linear-gradient(top, #f8f8f8 0%, #d3d3d3 50%, #f8f8f8 100%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(50%,#d3d3d3), color-stop(100%,#f8f8f8));
    background: -webkit-linear-gradient(top, #f8f8f8 0%, #d3d3d3 50%, #f8f8f8 100%);
    background: -o-linear-gradient(top, #f8f8f8 0%, #d3d3d3 50%, #f8f8f8 100%);
    background: -ms-linear-gradient(top, #f8f8f8 0%, #d3d3d3 50%, #f8f8f8 100%);
    background: linear-gradient(top, #f8f8f8 0%, #d3d3d3 50%, #f8f8f8 100%);
}
.tabsbar .tablink:last-child {
    background: none;
}
.tabsbar .tablink:last-child a {
    border-right: 0;
}
.tabsbar .tablink a {
    padding: 15px;
    color: #999;
    font-size: 12px;
    font-weight: bold;
    text-decoration: none;
    background: #fff;
    border-right: 1px solid #fafafa;
}
.tabsbar .tablink.selected a {
    color: #004458;
    background: #fff;
    background: -moz-linear-gradient(top, #fff 40%, #efefef 100%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(40%,#fff), color-stop(100%,#efefef));
    background: -o-linear-gradient(top, #fff 40%, #efefef 100%);
    background: -ms-linear-gradient(top, #fff 40%, #efefef 100%);
    background: linear-gradient(top, #fff 40%, #efefef 100%);
}
fieldset.tab {
    border: 0;
    padding: 0;
}
skins/larry/templates/addressbook.html
New file
@@ -0,0 +1,92 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body>
<roundcube:include file="/includes/header.html" />
<div id="mainscreen">
<div id="addressview-left">
<!-- search box -->
<div id="quicksearchbar">
<roundcube:object name="searchform" id="quicksearchbox" />
<roundcube:button name="searchmenulink" id="searchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('searchmenu');return false" title="searchmod" content=" " />
<roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
</div>
<!-- sources/groups list -->
<div id="directorylistbox" class="uibox listbox">
<h2 class="boxtitle"><roundcube:label name="groups" /></h2>
<div class="scroller withfooter">
    <roundcube:object name="directorylist" id="directorylist" class="listing" />
</div>
<div class="boxfooter">
    <roundcube:button command="group-create" type="link" title="newcontactgroup" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="groupoptions" id="groupoptionslink" type="link" title="moreactions" class="listbutton groupactions" onclick="UI.show_popup('groupoptions');return false" innerClass="inner" content="&#9881;" />
</div>
</div>
</div><!-- end addressview-left -->
<div id="addressview-right">
<!-- toolbar -->
<div id="addressbooktoolbar" class="toolbar">
    <roundcube:button command="advanced-search" type="link" class="button search disabled" classAct="button search" classSel="button search pressed" label="advsearch" />
    <roundcube:button command="compose" type="link" class="button compose disabled" classAct="button compose" classSel="button compose pressed" label="writenewmessage" />
    <roundcube:button command="import" type="link" class="button import disabled" classAct="button import" classSel="button import pressed" label="importcontacts" />
    <roundcube:button command="export" type="link" class="button export disabled" classAct="button export" classSel="button export pressed" label="exportvcards" />
    <roundcube:container name="toolbar" id="addressbooktoolbar" />
</div>
<!-- contacts list -->
<div id="addresslist" class="uibox listbox">
<h2 class="boxtitle"><roundcube:label name="contacts" /></h2>
<div class="scroller withfooter">
<roundcube:object name="addresslist" id="contacts-table" class="listing" noheader="true" />
</div>
<div class="boxfooter">
    <roundcube:button command="add" type="link" title="newcontact" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button command="delete" type="link" title="deletecontact" class="listbutton delete disabled" classAct="listbutton delete" innerClass="inner" content="x" />
</div>
</div>
<div id="contacts-box" class="uibox">
    <roundcube:object name="addressframe" id="contact-frame" style="width:100%; height:96%" src="/watermark.html" />
    <roundcube:object name="message" id="message" class="statusbar" />
</div>
</div><!-- end addressview-right -->
</div><!-- end mainscreen -->
<div id="searchmenu" class="popupmenu">
    <ul class="toolbarmenu">
        <li><label><input type="checkbox" name="s_mods[]" value="name" onclick="UI.set_searchmod(this)" /> <roundcube:label name="name" /></label></li>
        <li><label><input type="checkbox" name="s_mods[]" value="firstname" onclick="UI.set_searchmod(this)" /> <roundcube:label name="firstname" /></label></li>
        <li><label><input type="checkbox" name="s_mods[]" value="surname" onclick="UI.set_searchmod(this)" /> <roundcube:label name="surname" /></label></li>
        <li><label><input type="checkbox" name="s_mods[]" value="email" onclick="UI.set_searchmod(this)" /> <roundcube:label name="email" /></label></li>
        <li><label><input type="checkbox" name="s_mods[]" value="*" onclick="UI.set_searchmod(this)" /> <roundcube:label name="allfields" /></label></li>
    </ul>
</div>
<div id="groupoptions" class="popupmenu">
    <ul id="groupoptionsmenu" class="toolbarmenu">
        <li><roundcube:button command="group-rename" label="grouprename" classAct="active" /></li>
        <li><roundcube:button command="group-delete" label="groupdelete" classAct="active" /></li>
        <li><roundcube:button command="search-create" label="searchsave" classAct="active" /></li>
        <li><roundcube:button command="search-delete" label="searchdelete" classAct="active" /></li>
        <roundcube:container name="groupoptions" id="groupoptionsmenu" />
    </ul>
</div>
<roundcube:include file="/includes/footer.html" />
</body>
</html>
skins/larry/templates/compose.html
@@ -104,8 +104,8 @@
<!-- (collapsable) message options -->
<div id="composeoptionsbox">
    <span class="composeoption">
        <label><roundcube:label name="options" /></label>
        <a href="#options" id="composeoptionstoggle">&nbsp;</a>
        <label><roundcube:label name="options" />
            <a href="#options" id="composeoptionstoggle">&nbsp;</a></label>
    </span>
    
    <div id="composeoptions">
skins/larry/templates/contact.html
New file
@@ -0,0 +1,33 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="iframe">
<h1 class="boxtitle"><roundcube:label name="contactproperties" /></h1>
<div id="contact-details" class="boxcontent">
    <roundcube:if condition="strlen(env:sourcename)" />
        <div id="sourcename"><roundcube:label name="addressbook" />: <roundcube:var name="env:sourcename" /></div>
    <roundcube:endif />
    <div id="contactphoto"><roundcube:object name="contactphoto" id="contactpic" placeholder="/images/contactpic.png" /></div>
    <roundcube:object name="contacthead" id="contacthead" />
    <br style="clear:both" />
    <div id="contacttabs" class="tabbed">
        <roundcube:object name="contactdetails" />
    </div>
</div>
<div id="headerbuttons" class="formbuttons">
    <roundcube:button command="edit" type="input" class="button mainaction" label="editcontact" condition="!ENV:readonly" />
</div>
<roundcube:include file="/includes/footer.html" />
</body>
</html>
skins/larry/templates/contactedit.html
New file
@@ -0,0 +1,52 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="iframe">
<h1 class="boxtitle">
    <roundcube:if condition="env:action=='add'" /><roundcube:label name="addcontact" />
    <roundcube:else /><roundcube:label name="editcontact" />
<roundcube:endif /></h1>
<form name="editform" method="post" action="./" id="contact-details" class="boxcontent">
    <roundcube:if condition="strlen(env:sourcename)" />
        <div id="sourcename"><roundcube:label name="addressbook" />: <roundcube:var name="env:sourcename" condition="env:action!='add'" /><roundcube:object name="sourceselector" id="sourceselect" condition="env:action=='add'" /></div>
    <roundcube:endif />
    <div id="contactphoto">
        <roundcube:object name="contactphoto" id="contactpic" placeholder="/images/contactpic.png" />
        <div class="formlinks">
            <roundcube:button command="upload-photo" id="uploadformlink" type="link" label="replacephoto" class="iconlink upload disabled" classAct="iconlink upload active" onclick="UI.show_uploadform();return false" condition="env:photocol" /><br/>
            <roundcube:button command="delete-photo" type="link" label="delete" class="iconlink delete disabled" classAct="iconlink delete active" condition="env:photocol" />
        </div>
    </div>
    <roundcube:object name="contactedithead" id="contacthead" size="16" form="editform" />
    <br style="clear:both" />
    <div id="contacttabs" class="tabbed">
        <roundcube:object name="contacteditform" size="40" textareacols="60" form="editform" />
    </div>
</form>
<div id="headerbuttons" class="formbuttons">
    <roundcube:button command="save" type="input" class="button mainaction" label="save" />
    <roundcube:button command="show" type="input" class="button" label="cancel" condition="env:action=='edit'" />
    <roundcube:button name="cancel" type="input" class="button" label="cancel" onclick="history.back()" condition="env:action=='add'" />
</div>
<div id="upload-dialog" class="propform popupdialog">
    <roundcube:object name="photoUploadForm" id="upload-form" size="30" buttons="no" />
    <div class="formbuttons">
        <roundcube:button command="upload-photo" type="input" class="button mainaction" label="upload" />
        <roundcube:button name="close" type="input" class="button" label="cancel" onclick="UI.show_uploadform()" />
    </div>
</div>
<roundcube:include file="/includes/footer.html" />
</body>
</html>
skins/larry/ui.js
@@ -34,6 +34,7 @@
  // export public methods
  this.init = init;
  this.init_tabs = init_tabs;
  this.show_popup = show_popup;
  this.set_searchmod = set_searchmod;
  this.show_uploadform = show_uploadform;
@@ -68,12 +69,12 @@
      else if (rcmail.env.action == 'compose') {
        layout_composeview();
        $('#composeoptionstoggle').click(function(){
          $(this).toggleClass('enabled');
        $('#composeoptionstoggle').parent().click(function(){
          $('#composeoptionstoggle').toggleClass('enabled');
          $('#composeoptions').toggle();
          layout_composeview();
          return false;
        });
        }).css('cursor', 'pointer');
        new rcube_splitter({ id:'composesplitterv', p1:'#composeview-left', p2:'#composeview-right',
          orientation:'v', relative:true, start:248, min:150, size:12 }).init();
@@ -107,6 +108,12 @@
          orientation:'v', relative:true, start:305, min:150, size:12 }).init();
      }
    }
    else if (rcmail.env.task == 'addressbook') {
    }
    // turn a group of fieldsets into tabs
    $('.tabbed').each(function(idx, elem){ init_tabs(elem); })
    $(document.body).bind('mouseup', function(e){
      var config, obj, target = e.target;
@@ -189,8 +196,8 @@
    body.width(w).height(h);
    if (window.tinyMCE && tinyMCE.get('composebody')) {
      $('#composebody_tbl').width((w+11)+'px').height('').css('margin-top', '1px');
      $('#composebody_ifr').width((w+11)+'px').height((h-24)+'px');
      $('#composebody_tbl').width((w+12)+'px').height('').css('margin-top', '1px');
      $('#composebody_ifr').width((w+12)+'px').height((h-22)+'px');
    }
    else {
      $('#googie_edit_layer').height(h+'px');
@@ -540,6 +547,65 @@
    $('#' + which + '-link').show();
    this.resize_compose_body();
  }
  /**
   * Fieldsets-to-tabs converter
   */
  function init_tabs(elem, current)
  {
    var id = elem.id,
      content = $(elem),
      fs = content.children('fieldset');
    if (!fs.length)
      return;
    if (!id) {
      id = 'rcmtabcontainer';
      elem.attr('id', id);
    }
    // first hide not selected tabs
    current = current || 0;
    fs.each(function(idx) { if (idx != current) $(this).hide(); });
    // create tabs container
    var tabs = $('<div>').addClass('tabsbar').prependTo(content);
    // convert fildsets into tabs
    fs.each(function(idx) {
      var tab, a, elm = $(this), legend = elm.children('legend');
      // create a tab
      a   = $('<a>').text(legend.text()).attr('href', '#');
      tab = $('<span>').attr({'id': 'tab'+idx, 'class': 'tablink'})
        .click(function() { show_tab(id, idx); return false })
      // remove legend
      legend.remove();
      // style fieldset
      elm.addClass('tab');
      // style selected tab
      if (idx == current)
        tab.addClass('selected');
      // add the tab to container
      tab.append(a).appendTo(tabs);
    });
  }
  function show_tab(id, index)
  {
    var fs = $('#'+id).children('fieldset');
    fs.each(function(idx) {
      // Show/hide fieldset (tab content)
      $(this)[index==idx ? 'show' : 'hide']();
      // Select/unselect tab
      $('#tab'+idx).toggleClass('selected', idx==index);
    });
  }
}