FELIX-1171 Refactor display of configuration status using tabbed
view. This includes the tabworld JQuery plugin with a preliminary
(yet completely open) license (still have to confirm whether this
can be licensed under a better known license such as BSD or MIT).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@815280 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/LICENSE.tabworld b/webconsole/LICENSE.tabworld
new file mode 100644
index 0000000..214b980
--- /dev/null
+++ b/webconsole/LICENSE.tabworld
@@ -0,0 +1,9 @@
+Tanner Hildebrand's License
+
+TabWorld by Tanner Hildebrand is free to use for any purpose, commercial or
+otherwise. The user of the script may modify, distribute, sell, use, or
+publish this script at their discretion. The uses are unrestricted and may
+only be restricted if the user is found to be guilty (by a U.S. court only)
+of a criminal act that involves this script.
+
+Please enjoy and use this script as you wish to its fullest potential.
\ No newline at end of file
diff --git a/webconsole/NOTICE b/webconsole/NOTICE
index 7e3807b..0df574c 100644
--- a/webconsole/NOTICE
+++ b/webconsole/NOTICE
@@ -38,6 +38,10 @@
Copyright (c) 2006 Mark James
Licensed under the Creative Commons Attribution 2.5 License
+This product includes software from http://benchsketch.com/bquery/index.html
+Copyright (c) 2009 Tanner Hildebrand
+Licensed under Tanner Hildebrand's License
+
II. Used Software
@@ -53,3 +57,4 @@
- JSON License
- MIT License
- Creative Commons Attribution 2.5 License
+- Tanner Hildebrand's License
\ No newline at end of file
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
index f51ed44..92a4b38 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
@@ -19,18 +19,45 @@
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.*;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.bundlerepository.*;
+import org.apache.felix.bundlerepository.R4Attribute;
+import org.apache.felix.bundlerepository.R4Export;
+import org.apache.felix.bundlerepository.R4Import;
+import org.apache.felix.bundlerepository.R4Package;
+import org.apache.felix.webconsole.ConfigurationPrinter;
import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
import org.apache.felix.webconsole.internal.Util;
-import org.json.*;
-import org.osgi.framework.*;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.log.LogService;
@@ -42,7 +69,7 @@
/**
* The <code>BundlesServlet</code> TODO
*/
-public class BundlesServlet extends BaseWebConsolePlugin
+public class BundlesServlet extends BaseWebConsolePlugin implements ConfigurationPrinter
{
public static final String NAME = "bundles";
@@ -62,6 +89,7 @@
// see #activate and #isBootDelegated
private boolean[] bootPkgWildcards;
+ private ServiceRegistration configurationPrinter;
public void activate( BundleContext bundleContext )
{
@@ -83,6 +111,20 @@
}
bootPkgs[i] = bootDelegation;
}
+
+ configurationPrinter = bundleContext.registerService( ConfigurationPrinter.SERVICE, this, null );
+ }
+
+
+ public void deactivate()
+ {
+ if ( configurationPrinter != null )
+ {
+ configurationPrinter.unregister();
+ configurationPrinter = null;
+ }
+
+ super.deactivate();
}
@@ -98,6 +140,72 @@
}
+ //---------- ConfigurationPrinter
+
+ public void printConfiguration( PrintWriter pw )
+ {
+ try
+ {
+ StringWriter w = new StringWriter();
+ writeJSON( w, null, null, true );
+ String jsonString = w.toString();
+ JSONObject json = new JSONObject( jsonString );
+
+ pw.println( "Status: " + json.get( "status" ) );
+ pw.println();
+
+ JSONArray data = json.getJSONArray( "data" );
+ for ( int i = 0; i < data.length(); i++ )
+ {
+ if ( !data.isNull( i ) )
+ {
+ JSONObject bundle = data.getJSONObject( i );
+
+ pw.println( MessageFormat.format( "Bundle {0} - {1} {2} (state: {3})", new Object[]
+ { bundle.get( "id" ), bundle.get( "name" ), bundle.get( "version" ), bundle.get( "state" ) } ) );
+
+ JSONArray props = bundle.getJSONArray( "props" );
+ for ( int pi = 0; pi < props.length(); pi++ )
+ {
+ if ( !props.isNull( pi ) )
+ {
+ JSONObject entry = props.getJSONObject( pi );
+
+ pw.print( " " + entry.get( "key" ) + ": " );
+
+ Object entryValue = entry.get( "value" );
+ if ( entryValue instanceof JSONArray )
+ {
+ pw.println();
+ JSONArray entryArray = ( JSONArray ) entryValue;
+ for ( int ei = 0; ei < entryArray.length(); ei++ )
+ {
+ if ( !entryArray.isNull( ei ) )
+ {
+ pw.println( " " + entryArray.get( ei ) );
+ }
+ }
+ }
+ else
+ {
+ pw.println( entryValue );
+ }
+ }
+ }
+
+ pw.println();
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ getLog().log( LogService.LOG_ERROR, "Problem rendering Bundle details for configuration status", e );
+ }
+ }
+
+
+ //---------- BaseWebConsolePlugin
+
protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
IOException
{
@@ -331,7 +439,15 @@
writeJSON(pw, bundle, pluginRoot);
}
- private void writeJSON( final PrintWriter pw, final Bundle bundle, final String pluginRoot) throws IOException
+
+ private void writeJSON( final PrintWriter pw, final Bundle bundle, final String pluginRoot ) throws IOException
+ {
+ writeJSON( pw, bundle, pluginRoot, false );
+ }
+
+
+ private void writeJSON( final Writer pw, final Bundle bundle, final String pluginRoot,
+ final boolean fullDetails ) throws IOException
{
final Bundle[] allBundles = this.getBundles();
final String statusLine = this.getStatusLine(allBundles);
@@ -354,7 +470,7 @@
for ( int i = 0; i < bundles.length; i++ )
{
- bundleInfo( jw, bundles[i], bundle != null, pluginRoot );
+ bundleInfo( jw, bundles[i], fullDetails || bundle != null, pluginRoot );
}
jw.endArray();
@@ -1023,7 +1139,12 @@
private String getBundleDescriptor( Bundle bundle, final String pluginRoot )
{
StringBuffer val = new StringBuffer();
- val.append("<a href='").append(pluginRoot).append('/').append(bundle.getBundleId()).append("'>");
+
+ if ( pluginRoot != null )
+ {
+ val.append( "<a href='" ).append( pluginRoot ).append( '/' ).append( bundle.getBundleId() ).append( "'>" );
+ }
+
if ( bundle.getSymbolicName() != null )
{
// list the bundle name if not null
@@ -1044,7 +1165,10 @@
// only append the bundle
val.append( bundle.getBundleId() );
}
- val.append("</a>");
+ if ( pluginRoot != null )
+ {
+ val.append( "</a>" );
+ }
return val.toString();
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
index 55a38f6..505d0c0 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
@@ -18,27 +18,33 @@
import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.text.MessageFormat;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Iterator;
-import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
@@ -59,6 +65,20 @@
public static final String TITLE = "Configuration Status";
+ /**
+ * Formatter pattern to generate a relative path for the generation
+ * of the plain text or zip file representation of the status. The file
+ * name consists of a base name and the current time of status generation.
+ */
+ private static final SimpleDateFormat FILE_NAME_FORMAT = new SimpleDateFormat( "'" + LABEL
+ + "/configuration-status-'yyyyMMdd'-'HHmmZ" );
+
+ /**
+ * Formatter pattern to render the current time of status generation.
+ */
+ private static final DateFormat DISPLAY_DATE_FORMAT = SimpleDateFormat.getDateTimeInstance( SimpleDateFormat.LONG,
+ SimpleDateFormat.LONG, Locale.US );
+
private ServiceTracker cfgPrinterTracker;
private int cfgPrinterTrackerCount;
@@ -78,28 +98,82 @@
}
+ protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ if ( request.getPathInfo().endsWith( ".txt" ) )
+ {
+ response.setContentType( "text/plain; charset=utf-8" );
+ ConfigurationWriter pw = new PlainTextConfigurationWriter( response.getWriter() );
+ printConfigurationStatus( pw );
+ pw.flush();
+ }
+ else if ( request.getPathInfo().endsWith( ".zip" ) )
+ {
+ String type = getServletContext().getMimeType( request.getPathInfo() );
+ if ( type == null )
+ {
+ type = "application/x-zip";
+ }
+ response.setContentType( type );
+
+ ZipOutputStream zip = new ZipOutputStream( response.getOutputStream() );
+ zip.setLevel( 9 );
+ zip.setMethod( ZipOutputStream.DEFLATED );
+
+ ConfigurationWriter pw = new ZipConfigurationWriter( zip );
+ printConfigurationStatus( pw );
+ pw.flush();
+
+ zip.finish();
+ }
+ else
+ {
+ super.doGet( request, response );
+ }
+ }
+
+
protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
- PrintWriter pw = response.getWriter();
+ ConfigurationWriter pw = new HtmlConfigurationWriter( response.getWriter() );
- pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+ String appRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_APP_ROOT );
+ pw.println( "<link href='" + appRoot + "/res/ui/configurationrender.css' rel='stylesheet' type='text/css'>" );
+ pw.println( "<script src='" + appRoot + "/res/ui/tw-1.1.js' language='JavaScript'></script>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<th class='content container'>Configuration Details</th>" );
- pw.println( "</tr>" );
+ pw.println( "<script>$(document).ready(function(){ $('#cfgprttabs').tabworld() });</script>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content'>" );
- pw.println( "<pre>" );
+ final Date currentTime = new Date();
+ synchronized ( DISPLAY_DATE_FORMAT )
+ {
+ pw.println( "<p>Date: " + DISPLAY_DATE_FORMAT.format( currentTime ) + "</p>" );
+ }
- pw.println( "*** Date: "
- + SimpleDateFormat.getDateTimeInstance( SimpleDateFormat.LONG, SimpleDateFormat.LONG, Locale.US ).format(
- new Date() ) );
- pw.println();
+ synchronized ( FILE_NAME_FORMAT )
+ {
+ String fileName = FILE_NAME_FORMAT.format( currentTime );
+ pw.println( "<p>Download as <a href='" + fileName + ".txt'>[Single File]</a> or as <a href='" + fileName
+ + ".zip'>[ZIP]</a></p>" );
+ }
+ pw.println( "<div id='divcfgprttabs'>" );
+
+ pw.println( "<ul id='cfgprttabs'>" );
+
+ printConfigurationStatus( pw );
+
+ pw.println( "</ul>" );
+ pw.println( "</div>" );
+
+ pw.flush();
+ }
+
+
+ private void printConfigurationStatus( ConfigurationWriter pw )
+ {
this.printSystemProperties( pw );
- this.printBundles( pw );
this.printServices( pw );
this.printPreferences( pw );
this.printConfigurations( pw );
@@ -109,11 +183,6 @@
{
printConfigurationPrinter( pw, ( ConfigurationPrinter ) cpi.next() );
}
-
- pw.println( "</pre>" );
- pw.println( "</td>" );
- pw.println( "</tr>" );
- pw.println( "</table>" );
}
@@ -147,9 +216,9 @@
}
- private void printSystemProperties( PrintWriter pw )
+ private void printSystemProperties( ConfigurationWriter pw )
{
- pw.println( "*** System properties:" );
+ pw.title( "System properties" );
Properties props = System.getProperties();
SortedSet keys = new TreeSet( props.keySet() );
@@ -159,7 +228,7 @@
this.infoLine( pw, null, ( String ) key, props.get( key ) );
}
- pw.println();
+ pw.end();
}
@@ -194,31 +263,10 @@
// pw.println();
// }
- private void printBundles( PrintWriter pw )
+
+ private void printServices( ConfigurationWriter pw )
{
- pw.println( "*** Bundles:" );
- // biz.junginger.freemem.FreeMem (1.3.0) "FreeMem Eclipse Memory
- // Monitor" [Resolved]
-
- Bundle[] bundles = getBundleContext().getBundles();
- SortedSet keys = new TreeSet();
- for ( int i = 0; i < bundles.length; i++ )
- {
- keys.add( this.getBundleString( bundles[i], true ) );
- }
-
- for ( Iterator ki = keys.iterator(); ki.hasNext(); )
- {
- this.infoLine( pw, null, null, ki.next() );
- }
-
- pw.println();
- }
-
-
- private void printServices( PrintWriter pw )
- {
- pw.println( "*** Services:" );
+ pw.title( "Services" );
// get the list of services sorted by service ID (ascending)
SortedMap srMap = new TreeMap();
@@ -242,17 +290,15 @@
this.infoLine( pw, null, String.valueOf( sr.getProperty( Constants.SERVICE_ID ) ), sr
.getProperty( Constants.OBJECTCLASS ) );
- this.infoLine( pw, " ", "Bundle", this.getBundleString( sr.getBundle(), false ) );
+ this.infoLine( pw, " ", "Bundle", this.getBundleString( sr.getBundle() ) );
Bundle[] users = sr.getUsingBundles();
if ( users != null && users.length > 0 )
{
- List userString = new ArrayList();
for ( int i = 0; i < users.length; i++ )
{
- userString.add( this.getBundleString( users[i], false ) );
+ this.infoLine( pw, " ", "Using Bundle", this.getBundleString( users[i] ) );
}
- this.infoLine( pw, " ", "Using Bundles", userString );
}
String[] keys = sr.getPropertyKeys();
@@ -267,21 +313,22 @@
pw.println();
}
+
+ pw.end();
}
- private void printPreferences( PrintWriter pw )
+ private void printPreferences( ConfigurationWriter pw )
{
- pw.println( "*** System Preferences:" );
+ pw.title( "Preferences" );
ServiceReference sr = getBundleContext().getServiceReference( PreferencesService.class.getName() );
if ( sr == null )
{
pw.println( " Preferences Service not registered" );
- pw.println();
- return;
}
-
+ else
+ {
PreferencesService ps = ( PreferencesService ) getBundleContext().getService( sr );
try
{
@@ -304,6 +351,9 @@
}
}
+ pw.end();
+ }
+
private void printPreferences( PrintWriter pw, Preferences prefs ) throws BackingStoreException
{
@@ -324,9 +374,9 @@
}
- private void printConfigurations( PrintWriter pw )
+ private void printConfigurations( ConfigurationWriter pw )
{
- pw.println( "*** Configurations:" );
+ pw.title( "Configurations" );
ServiceReference sr = getBundleContext().getServiceReference( ConfigurationAdmin.class.getName() );
if ( sr == null )
@@ -368,15 +418,15 @@
}
}
- pw.println();
+ pw.end();
}
- private void printConfigurationPrinter( PrintWriter pw, ConfigurationPrinter cp )
+ private void printConfigurationPrinter( ConfigurationWriter pw, ConfigurationPrinter cp )
{
- pw.println( "*** " + cp.getTitle() + ":" );
+ pw.title( cp.getTitle() );
cp.printConfiguration( pw );
- pw.println();
+ pw.end();
}
@@ -466,7 +516,7 @@
}
- private String getBundleString( Bundle bundle, boolean withState )
+ private String getBundleString( Bundle bundle )
{
StringBuffer buf = new StringBuffer();
@@ -494,38 +544,11 @@
buf.append( " \"" ).append( headers.get( Constants.BUNDLE_NAME ) ).append( '"' );
}
- if ( withState )
- {
- buf.append( " [" );
- switch ( bundle.getState() )
- {
- case Bundle.INSTALLED:
- buf.append( "Installed" );
- break;
- case Bundle.RESOLVED:
- buf.append( "Resolved" );
- break;
- case Bundle.STARTING:
- buf.append( "Starting" );
- break;
- case Bundle.ACTIVE:
- buf.append( "Active" );
- break;
- case Bundle.STOPPING:
- buf.append( "Stopping" );
- break;
- case Bundle.UNINSTALLED:
- buf.append( "Uninstalled" );
- break;
- }
- buf.append( ']' );
- }
-
return buf.toString();
}
- private void printThreads( PrintWriter pw )
+ private void printThreads( ConfigurationWriter pw )
{
// first get the root thread group
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
@@ -534,7 +557,7 @@
rootGroup = rootGroup.getParent();
}
- pw.println( "*** Threads:" );
+ pw.title( "Threads" );
printThreadGroup( pw, rootGroup );
@@ -546,7 +569,7 @@
printThreadGroup( pw, groups[i] );
}
- pw.println();
+ pw.end();
}
@@ -605,4 +628,116 @@
infoLine( pw, " ", null, info.toString() );
}
}
+
+ private abstract static class ConfigurationWriter extends PrintWriter
+ {
+
+ ConfigurationWriter( Writer delegatee )
+ {
+ super( delegatee );
+ }
+
+
+ abstract void title( String title );
+
+
+ abstract void end();
+
+ }
+
+ private static class HtmlConfigurationWriter extends ConfigurationWriter
+ {
+
+ HtmlConfigurationWriter( Writer delegatee )
+ {
+ super( delegatee );
+ }
+
+
+ public void title( String title )
+ {
+ println( "<li>" );
+ println( title );
+ println( "<q><pre>" );
+ }
+
+
+ public void end()
+ {
+ println( "</pre>" );
+ println( "</q>" );
+ println( "</li>" );
+ }
+ }
+
+ private static class PlainTextConfigurationWriter extends ConfigurationWriter
+ {
+
+ PlainTextConfigurationWriter( Writer delegatee )
+ {
+ super( delegatee );
+ }
+
+
+ public void title( String title )
+ {
+ print( "*** " );
+ print( title );
+ println( ":" );
+ }
+
+
+ public void end()
+ {
+ println();
+ }
+ }
+
+ private static class ZipConfigurationWriter extends ConfigurationWriter
+ {
+ private final ZipOutputStream zip;
+
+ private int counter;
+
+
+ ZipConfigurationWriter( ZipOutputStream zip )
+ {
+ super( new OutputStreamWriter( zip ) );
+ this.zip = zip;
+ }
+
+
+ public void title( String title )
+ {
+ String name = MessageFormat.format( "{0,number,000}-{1}.txt", new Object[]
+ { new Integer( counter ), title } );
+
+ counter++;
+
+ ZipEntry entry = new ZipEntry( name );
+ try
+ {
+ zip.putNextEntry( entry );
+ }
+ catch ( IOException ioe )
+ {
+ // should handle
+ }
+ }
+
+
+ public void end()
+ {
+ flush();
+
+ try
+ {
+ zip.closeEntry();
+ }
+ catch ( IOException ioe )
+ {
+ // should handle
+ }
+ }
+ }
}
diff --git a/webconsole/src/main/resources/res/ui/configurationrender.css b/webconsole/src/main/resources/res/ui/configurationrender.css
new file mode 100644
index 0000000..9bcba5a
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/configurationrender.css
@@ -0,0 +1,70 @@
+/* tabbed view */
+
+#divcfgprttabs {
+}
+
+#divcfgprttabs ul {
+ list-style: none;
+}
+
+#divcfgprttabs ul li {
+ display: inline;
+ background: #fff;
+ height: 21px;
+ margin: 0 2px 0 0 ;
+ border: 1px solid #999;
+ float: left;
+ padding: 1px 1px 0 1px
+}
+
+#divcfgprttabs ul li.tabactive {
+ border-bottom-color: white;
+}
+
+#divcfgprttabs ul li a {
+ color: #6181A9;
+ background-color: white;
+ display: block;
+ float: left;
+ height: 100%;
+ line-height: 2;
+ padding: 0 10px 0 10px;
+ cursor: pointer;
+}
+
+#divcfgprttabs ul li a.tabactive {
+}
+
+#divcfgprttabs ul li a:hover {
+ color: white;
+ background-color: #6181A9;
+}
+
+.menu {
+ background: none;
+ height: 23px;
+ margin-bottom: 0;
+ padding-left: 0;
+}
+.area {
+ background: #fff;
+ border: 1px solid #999;
+ padding: 1px;
+}
+
+/* Contents container of the tabs */
+.tabcont {
+ background: #fff;
+ border: 1px solid #999;
+ border-right: none;
+ padding: 1px;
+}
+
+/* The actual content of the tabs */
+.space {
+ padding: 10px;
+
+ /* don't let this area make the display wider */
+ width: 100px;
+ overflow: visible;
+}
diff --git a/webconsole/src/main/resources/res/ui/tw-1.1.js b/webconsole/src/main/resources/res/ui/tw-1.1.js
new file mode 100644
index 0000000..7a313ab
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/tw-1.1.js
@@ -0,0 +1,130 @@
+// JavaScript Document
+// Tab World From BenchSketch.com
+// Benchsketch.com/bquery/tab.html for documentation
+// You can use it FREE!!! Yay.
+// Let me know how it works, or send suggestions, comments, requests to benchsketch@gmail.com
+// Thanks
+
+(function($){
+ $.fn.extend({
+
+ // tabworld function
+ tabworld: function(options){
+
+ // Get the user extensions and defaults
+ var opts = $.extend({}, $.fn.tabworld.defaults, options);
+
+ // Content location
+ if(opts.contloc=="none"){
+ contloc=$(this).parent();
+ }else{
+ contloc=opts.contloc;
+ }
+ // Content location
+ if(opts.tabloc=="none"){
+ tabloc=$(this).parent();
+ }else{
+ tabloc=opts.tabloc;
+ }
+
+ // better define some stuff for safety
+ var newli="",newdiv="";
+
+ // Start Building Tabs
+ return this.each(function(i){
+
+
+ //start developing basis
+ now=$(this);
+ nowid=now.attr("id");
+ now.addClass(opts.color);
+
+ // tab maker function
+ // $("#"+nowid+" li").each(function(i){ // lets hide that for now
+ $("#"+nowid+" > li").each(function(i){
+
+ tabli = $(this);
+ // taba = $('#'+nowid+" > li q");
+ taba = tabli.children("q");
+ $(this).addClass("removeme");
+ tabcont = taba.html();
+ $(".removeme q").remove();
+ licont = tabli.html();
+ $(this).remove();
+
+ newli += "<li rel='"+nowid+"-"+i+"'><a>"+licont+"</a></li>";
+ newdiv += "<div id='"+nowid+"-"+i+"'>"+tabcont+"</div>";
+
+ });
+
+ // Something weird to gain the location
+ now.remove();
+ $(tabloc).append("<ul id='"+nowid+"-tabworld' class='"+opts.color+"'>"+newli+"</ul>");
+ // Fix the ul
+ // $("#"+nowid).append(newli);
+ // Find the Parent then append the divs
+ // var parent = $("#"+nowid).parent();
+ newdiv = "<div id='"+nowid+"content' class='tabcont'><div class='"+opts.area+"'>"+newdiv+"</div></div>";
+ newdiv = newdiv.replace(/\/>/,">");
+ $(contloc).append(newdiv);
+
+
+ // Find the default
+ ndef = nowid+"-"+opts.dopen;
+ ncon = nowid+"content ."+opts.area+" > div";
+ $('#'+ncon).hide();
+ $('#'+ndef).show();
+ //$('#'+ndef+" > div").show();
+
+ deftab = $('li[rel='+ndef+"]");
+ deftab.addClass(opts.tabactive);
+ deftab.children("a").addClass(opts.tabactive);
+ // Seperate function to start the tabbing
+ $("#"+nowid+"-tabworld >li").click(function(){
+ here=$(this);
+ nbound=here.attr("rel");
+
+ // Make the active class / remove it from others
+ $("#"+nowid+"-tabworld > li").removeClass(opts.tabactive);
+ $("#"+nowid+"-tabworld > li a").removeClass(opts.tabactive);
+ here.addClass(opts.tabactive);
+ $("."+opts.tabactive+">a").addClass(opts.tabactive);
+
+ // The real action! Also detirmine transition
+ if(opts.transition=="slide"){
+ $('#'+ncon+':visible').slideUp(opts.speed, function(){
+ $('#'+nbound).find("div").show();
+ $('#'+nbound).slideDown(opts.speed);
+ });
+ }else if (opts.transition=="fade"){
+ $('#'+ncon+':visible').fadeOut(opts.speed, function(){
+ $('#'+nbound).find("div").show();
+ $('#'+nbound).fadeIn(opts.speed);
+ });
+ }else{
+ $('#'+ncon+':visible').hide(opts.speed, function(){
+ $('#'+nbound).find("div").show();
+ $('#'+nbound).show(opts.speed);
+ });
+ }
+
+ });
+
+ });// end return each (i)
+ }// end tabworld
+ })// end $.fn.extend
+
+// Defaults
+$.fn.tabworld.defaults = {
+ mislpace:'none',
+ speed:'fast',
+ color:'menu',
+ area:'space',
+ tabloc:'none',
+ contloc:'none',
+ dopen:0,
+ transition:'fade',
+ tabactive:'tabactive'
+}; // end defaults
+
+})(jQuery);// end function($)
\ No newline at end of file