Joeytje50 has submitted this change and it was merged.

Change subject: Version 1.1: Add Android Browser support
......................................................................


Version 1.1: Add Android Browser support

Now includes a togglebox fallback for Android Browser (and Dolphin Browser
for Android). This fallback uses the details and summary tags.
Also includes some modifications to the other files, such as readdition of
the qqq i18n file.

Change-Id: I713bef02f2955e3cc16918e2b1fcd447d5293ebc
---
M README.md
M Tabs.body.php
D Tabs.examples.txt
A Tabs.i18n.magic.php
M Tabs.php
M ext.tabs.css
M ext.tabs.js
M i18n/en.json
M i18n/nl.json
A i18n/qqq.json
10 files changed, 879 insertions(+), 290 deletions(-)

Approvals:
  Joeytje50: Verified; Looks good to me, approved
  Siebrand: Looks good to me, but someone else must approve



diff --git a/README.md b/README.md
index e979000..e445bc6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,368 @@
-#Tabs
+This page contains documentation and demos for the tabs extension.
+Paste this text on a wiki article with the tabs extension installed
+to view these demos.
 
-The Tabs extension creates an easy way to add interactive tabs layout to your 
wiki. It is designed to make things as easy as possible. There are currently 
two features in this extension: The "togglebox" and the "tabbox". See the 
Tabs.examples.txt file for examples you can use to test this extension with.
+-----
+
+{{TOC|limit=4}}
+
+== Installation ==
+{{ExtensionInstall|Tabs}}
+
+== Configuration ==
+
+This extension has no configuration options in <code>LocalSettings.php</code>, 
but it does have the ''MediaWiki:tabs-dropdown-bgcolor'' message associated 
with it, which is not meant to be translated. This message contains the default 
value for the <code>background-color</code> style for dropdown menus. This 
needs to be a [https://developer.mozilla.org/en-US/docs/Web/CSS/color_value 
valid <code>background-color</code> value].
+
+It also has the following internationalisation messages associated with it:
+
+*''MediaWiki:tabs-tab-label'' - The default label for a tab. The 
<code>$1</code> stands for the index of the tab.
+*''MediaWiki:tabs-toggle-open'' - The default opening label for toggle boxes.
+*''MediaWiki:tabs-toggle-close'' - The default closing label for toggle boxes.
+*''MediaWiki:tabs-dropdown-label'' - The default label for a dropdown menu.
+
+== Usage ==
+
+=== General usage information ===
+
+'''Note:''' - This extension uses the <code>bgcolor</code> attribute for 
dropdown menus. This is in no way meant as encouragement for the use of this 
deprecated attribute anywhere other than this tag.
+
+For both the <code>&lt;tab&gt;</code> and <code>&lt;tab&gt;</code> tags, 
parser functions ''can'' be used within the content of the tag, but ''not'' in 
the attributes. To use parser functions within the attributes, the 
<code>#tag:tabs</code> or <code>#tag:tab</code> parser functions should be 
used. The [[#Parser function|<code>#tab</code> parser function]] will also 
work, but since the only attributes it can define are the <code>index</code> 
and <code>name</code> attributes, these don't allow complete support.
+
+For example, this will not work:
+
+<pre>
+<tabs style="color:{{#if:{{{1|}}}|green|red}}">
+<tab name="{{{1|}}}">Foo</tab>
+<tab name="{{{2|}}}">Bar</tab>
+</tabs>
+</pre>
+But this will work:
+<pre>
+{{#tag:tabs|
+{{#tag:tab|Foo|name={{{1|}}}}}
+{{#tab:{{{2|}}}|Bar}}
+|style=color:{{#if:{{{1|}}}|green|red}} }}
+</pre>
+
+=== Toggle box ===
+
+==== Documentation ====
+You can create a simple collapsible box by enclosing some content between 
<code><nowiki><tab> ... </tab></nowiki></code>. All content within the tags 
will be displayed within the toggle box.
+
+===== Available attributes: =====
+*<code>collapsed</code> - If this attribute is set, the toggle box will appear 
collapsed when the page loads. Otherwise it will be opened.
+*<code>inline</code> - If this attribute is set, the toggle box can be placed 
within text without interrupting the flow of the text.
+*<code>dropdown</code> - See [[#Dropdown menus]].
+*Name attributes:
+**<code>openname</code> - The label for the toggle box that indicates that 
clicking it will close the box. Default value is stored in the 
''MediaWiki:tabs-toggle-open'' page.
+**<code>closename</code> - Same as <code>openname</code>, but for closing the 
toggle box. Default is stored in ''MediaWiki:tabs-toggle-close''.
+**<code>name</code> - If neither the <code>openname</code> and 
<code>closename</code> is defined, this value will be used for both states.
+**If only one of the <code>openname</code> or <code>closename</code> 
attributes is defined, the other will take its value. If neither is defined, 
and the <code>name</code> attribute is also not defined, the default values are 
taken from the respective MediaWiki pages.
+*<code>container</code> - Use this attribute to define any styles for the 
toggle box container. Styles defined here will only affect the content of the 
toggle box, not the label.
+*Default HTML attributes:
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#title 
<code>title</code>] - Determines the tooltip shown when hovering over the box.
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#style 
<code>style</code>] - Use this attribute to define any styles for the box. This 
can also affect the box's label.
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#class 
<code>class</code>] - Adds classes to the box.
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#id 
<code>id</code>] - Adds an id to the box. This id must be unique on the page, 
as with any id.
+
+==== Toggle box demos ====
+
+===== Plain toggle box =====
+<tab>This toggle box has no attributes assigned to it.</tab>
+
+===== Toggle box attributes =====
+<tab collapsed openname="Toggle" style="font-weight:bold;width:500px;" 
container="font-style:italic;" title="Example tooltip">
+This toggle box has the following attributes defined:
+*<code>collapsed</code> - By default, it is closed.
+*<code>openname="Toggle"</code> - The label will show "Toggle" when it can be 
clicked to open the box. Since no <code>closename</code> attribute is defined, 
it defaults to "Toggle" too.
+*<code>style="font-weight:bold;width:500px;"</code> - The whole toggle box 
will be bold, and have a width of 500px.
+*<code>container="font-style:italic;"</code> - Only the contents of the toggle 
box will be italic.
+*<code>title="Example tooltip"</code> - The tooltip that shows when hovering 
over this tab is defined via the <code>title</code> attribute.
+</tab>
+
+===== Inline toggle boxes =====
+Here is an example of an inline toggle box. <tab inline collapsed 
openname="Show" closename="Hide">This togglebox is <code>inline</code> and 
<code>collapsed</code></tab> This toggle box has the attributes 
<code>openname="Show"</code> and <code>closename="Hide"</code> to change the 
default label text.
+
+=== Dropdown menus ===
+==== Documentation ====
+
+Dropdown menus are made by simply defining the <code>dropdown</code> attribute 
on a toggle box. They can be opened by either hovering over the label, or by 
clicking on the label to keep it opened even after moving away the cursor. 
Dropdown menus have an opening delay of 0.2 seconds built in to prevent 
accidental opening when hovering over the label, and to prevent accidental 
closing when accidentally moving the cursor off the dropdown. This delay is 
enough to prevent accidents like those, but is not enough to be bothersome.
+
+Dropdown menus are heavily based on the code for toggle boxes, so will also 
resemble them in many ways. There are a couple of quite distinct differences 
though.
+
+Since dropdown menus use the <code>&lt;menu&gt;</code> tag for their content, 
it is permitted to use <code>&lt;li&gt;</code> tags directly within the 
dropdown menu's contents. Any other content is also allowed.
+
+Dropdown menus will convert all list items and links placed within to 
specially styled list items. The only exception is that links show as they 
normally do when placed within unordered lists 
([http://www.mediawiki.org/wiki/Help:Lists any line starting with 
<code>*</code>]). This is also the only difference between ordered and 
unordered lists.
+
+Any nested lists will be rendered as sub-menus in the dropdown menu. Nested 
lists are created by starting a line with 
[http://www.mediawiki.org/wiki/Help:Lists multiple <code>*</code> or 
<code>#</code> characters]. There is one limitation with this however: 
Individual nested lists can not alternate between ordered and unordered lists. 
Seperate levels can, however. For example, this is not allowed:
+<pre>
+*Menu item 1
+*Menu item 2
+**Sub-menu item 1
+*#Sub-menu item 2
+</pre>
+But this is:
+<pre>
+*Menu item 1
+#Menu item 2
+#*Sub-menu item 1
+#*Sub-menu item 2
+#*#Sub-sub-menu item 1
+</pre>
+
+===== Available attributes: =====
+
+*All attributes that are available for toggle boxes
+*<code>dropdown</code> - Must be defined for the toggle box to become a 
dropdown menu.
+*<code>openname</code> and <code>closename</code> - These attributes are 
identical to the <code>name</code> attribute in dropdown menus. It is not 
possible to let the dropdown switch between 2 values. If the 
<code>openname</code> attribute is set, that value will be used as label, 
otherwise the <code>closename</code> value is used, and if neither of those 
values is set, the <code>name</code> value is used.
+*<code>bgcolor</code> - Because of how the background-color styling for 
dropdown works (background styles are applied to all items within dropdowns, 
otherwise they would become transparent), background colors need to be defined 
seperately. This must be done in the <code>bgcolor</code> attribute. This 
attribute works exactly the same as the <code>background-color</code> style in 
CSS. This defaults to the value defined in ''MediaWiki:tabs-dropdown-bgcolor''.
+
+==== Dropdown demos ====
+
+===== Dropdown without lists =====
+<tab dropdown style="width:300pt" openname="Click/hover to show" 
closename="Showing...">
+This dropdown contains no lists, so it will not have any of the styling 
designed for dropdowns. It does work as it normally would though.
+
+This dropdown also has its <code>style</code> attribute set to 
<code>style="width:300pt"</code>. It also has different <code>openname</code> 
and <code>closename</code> attributes, so it defaults to the 
<code>openname</code> value.
+</tab>
+
+===== Background-color for dropdowns =====
+
+<tab dropdown bgcolor="salmon}body{font-weight:bold;">
+*This tab has a its <code>bgcolor</code> attribute set to 
<code>bgcolor="salmon"</code>. Just defining a <code>background-color</code> 
style would not work. 
+</tab>
+
+===== Lists and links =====
+Here you can see the difference between unordered and ordered lists within 
dropdowns. The appearance of both does not change, but the behaviour of links 
within them does.
+<tab dropdown>
+#The first 2 items use ordered lists, which will show links as list items too.
+#[[#Dropdown demos|Example link]]
+*From here on this dropdown uses ordered lists, so links are shown within text.
+*See this [[#Dropdown demos|example link]].
+*Any links in dropdown menus placed outside lists will also be rendered as 
list items, like the following link:
+[[#Dropdown demos|Example link]]
+</tab>
+
+===== Inline dropdowns =====
+It is also possible to create inline dropdowns: <tab dropdown inline>
+*You can do anything you'd normally do in a dropdown
+*This box will fit in with the text.
+</tab>. This will also not interrupt the flow of the text.
+
+===== Nested lists =====
+
+<tab dropdown>
+*This dropdown menu demonstrates dropdown menus with multiple levels.
+*Hovering over a list item with further lists nested within it will cause the 
next level to show up
+*Hover over this item to see
+**This list now shows up.
+**Nested lists can also contain even more lists
+**See this item for example
+***This is a third level menu
+**This can go on for any amount of levels.
+*Multiple sub-menus are also allowed
+**Such as this one.
+</tab>
+
+===== Alternating ordered and unordered lists =====
+
+<tab dropdown>
+*It is possible to alternate between ordered and unordered lists, but not 
within sub-menus.
+*The first 2 items are unordered list items
+#And this is an ordered list item
+#*This is an unordered list item again
+#*This also ''has'' to be an unordered list item
+#*#This can be an ordered list item again though
+#*#But then this also has to be ordered.
+#*Within an individual sub-menu, it is not possible to change between ordered 
and unordered list items
+</tab>
+
+<tab dropdown>
+*This item is in an unordered list, so it allows [[#Dropdown demos|in-line 
linking]].
+#This item and the next one are in an ordered list, so they turn links into 
list-items
+#[[#Dropdown demos|List-item links]]
+#*...with a sub-menu that uses unordered lists again, so allows [[#Dropdown 
demos|in-line linking]] again.
+#*#And this sub-menu again creates...
+#*#[[#Dropdown demos|...list-item links]]
+</tab>
+
+=== Tab menus ===
+==== Documentation ====
+
+Tab menus can be used to make it possible to switch between different layouts. 
Anything within <code><nowiki><tabs> ... </tabs></nowiki></code> tags is 
rendered as a tab menu. Individual tabs are then defined via a 
<code>&lt;tab&gt;</code> tag.
+
+===== Available attributes =====
+;<code>&lt;tabs&gt;</code>
+*<code>container</code> - Use this attribute to define any styles for the tabs 
container. Styles defined here will only affect the container of the tabs, not 
the labels.
+*<code>plain</code> - If this attribute is set, the tab interface will be a 
much more plain layout, without a border around the container, and with the tab 
labels just being buttons above it, instead of the typical tab layout. This can 
be used to get more freedom in styling the interface.
+;<code>&lt;tab&gt;</code>
+*<code>inline</code> - If this attribute is set, the tab's contents can be 
placed within text without interrupting the flow of the text. The difference 
between this and the default state of <code>display:inline-block</code> is that 
with <code>inline-block</code>, the tab's contents are forced to a new line 
when placed at the end of a new line, when not the whole of the tab's contents 
fit on the same line. <code>inline</code> tabs however will use up any space 
that's left at the end of the line, and fit in with the normal flow of the text 
just like normal text.
+*<code>block</code> - Converts the tab's contents to a block element. This can 
be used to assure the tab's contents will be displayed as a block instead of an 
inline-block, in cases where the tab's contents should not be placed within a 
line of text. When both the <code>block</code> and <code>inline</code> 
attributes are available, the <code>inline</code> attribute will be ignored.
+*Name attributes:
+**<code>index</code> - This will determine the index of the tab. This only 
works if the entered index is already the index of a defined tab. Otherwise, 
this attribute is ignored. If no valid index or matching name attributes are 
defined, the index is automatically set to be the next in the list of tabs.
+**<code>name</code> - This attribute is used to define the text the label 
shows for the tab. If the entered name already exists within the tab, the 
contents of the <code>&lt;tab&gt;</code> tag are automatically assigned to the 
existing tab. This also means no two tabs can have an identical label. This 
attribute will be ignored if the <code>index</code> attribute already refers to 
an existing tab. Whitespace is automatically removed from the start and end of 
this attribute's value.
+;Both
+*Default HTML attributes:
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#title 
<code>title</code>] - Determines the tooltip shown when hovering over the box.
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#style 
<code>style</code>] - Use this attribute to define any styles for the box. This 
can also affect the box's label.
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#class 
<code>class</code>] - Adds classes to the box.
+**[https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#id 
<code>id</code>] - Adds an id to the box. This id must be unique on the page, 
as with any id.
+
+===== Self-closing tabs =====
+
+Self-closing tabs can be used to define a list of tabs at the top of the tab 
menu, for later use via the <code>index</code> attribute. Self-closing tabs 
only have an effect when a name is defined, and no (valid) index is defined. 
The syntax for self-closing tabs is <code>&lt;tab name="name" /&gt;</code>
+
+===== Parser function =====
+
+As an alternative for the tab tag, the <code><nowiki>{{#tab:}}</nowiki></code> 
parser function can also be used to simplify the syntax for tabs. The syntax 
for this parser function allows the following syntaxes:
+
+<pre>
+{{#tab:name/index 1, name/index 2, etc|content 1|content 2|etc}}
+{{#tab:|content 1|content 2|etc}}
+{{#tab:name/index 1, , name/index 3, name/index 4|content 1|content 2| 
|content 4}}
+{{#tab:name 1, name 2, name 3...}}
+{{#tab:name/index 1, etc|content 1|$1}}
+</pre>
+These have the following effects:
+#Each of the defined names will be set as <code>name</code> or 
<code>index</code> attributes, respectively.
+#*All values that are numbers only will be automatically recognised as 
indices. For indices, surrounding whitespace is allowed, but internal 
whitespace or any non-number characters such as decimal points aren't.
+#*If these condtions are not met, the entered value is interpreted as a name.
+#*If the entered value contains only whitespace or is left empty, the index of 
that tab within the parser function is assumed.
+#No indices or names are defined here, so the indices of the tabs within the 
parser functions are automatically assigned as index.
+#The second tab will automatcally get <code>index="1"</code>, and the third 
tab will have no content:
+#*If the third tab has a name defined in the list of names, then a 
[[#Self-closing tabs|self-closing tag.
+#*If the third tab has an index defined, this tab is skipped, and no output is 
generated for this tab.
+#This will define three tabs, "name 1", "name 2" and "name 3" using the 
[[#Self-closing tabs|self-closing syntax]].
+#When the content of a tab is <code>$n</code> (where <code>n</code> is the 
place of the tab in the parser function), the contents of that tab are copied 
over to the tab that has <code>$n</code> in it. This only works if the tab 
contains nothing other than <code>$n</code>, and the parser function's 
<code>n</code>th parameter is defined and not empty.
+
+==== Demos ====
+
+===== Naming and reusing tabs, and default text =====
+
+<tabs>
+<tab name="First" style="border:1px solid black;">This tab has a defined 
<code>name</code>. It also has a <code>style</code> attribute set to 
<code>style="border:1px solid black;"</code>.</tab>
+<tab name="Second" style="background:salmon;">This tab also has a defined 
<code>name</code> attribute, and its <code>style</code> attribute set to 
<code>style="background:salmon;"</code>.</tab>
+<tab>This tab has no attributes defined. Its name is automatically generated 
based on its position.</tab>
+<tab index="1">This is a seperate tab. It has a defined <code>index</code> 
attribute with value "1". This makes it also show when the first tab is 
selected.</tab>
+<tab name="Second">This is a seperate tab. It has a defined <code>name</code> 
attribute, with a value equal to that of the second tab ("Second"). It 
therefore also shows when the second tab is opened.</tab>
+----
+This line of text will show for every tab you view. It is not placed within 
<code>&lt;tab&gt; tags, and can be used as default content for the tab menu.
+</tabs>
+
+===== <code>block</code> and <code>inline</code> tabs =====
+
+<tabs>
+<tab name="Default 1" style="background:lightgreen;">First tab.</tab>
+<tab name="Default 2" style="background:lightgreen;">Second tab.</tab>
+<tab name="Inline" style="background:salmon;">Third tab.</tab>
+<tab name="Block" style="background:royalblue;">Fourth tab.</tab>
+<tab index="1">This is a seperate tab. It demonstrates what happens if a tab 
has no <code>inline</code> or <code>block</code> attributes defined. If the tab 
contains a lot of text, it will automatically be forced to a new line, despite 
extra space being available at the end of the previous line.</tab>
+<tab index="2">This seperate tab isn't forced to a new line, since it's short 
enough.</tab>
+<tab index="3" inline>This is a seperate tab that has an <code>inline</code> 
attribute defined. It will fit in with the text as normal text would, and it 
fills up any space that is left available after the previous line. This makes 
tabs with <code>inline</code> attributes a bit better at fitting in with the 
flow of text.</tab>
+<tab index="4" block>Despite fitting on the previous line, the 
<code>block</code> attribute forces this seperate tab to a new line</tab>
+</tabs>
+
+===== Inline switching parts =====
+
+This tab menu uses the regular syntax using the <code>&lt;tab&gt;</code> tag.
+<tabs>
+This line of text contains <tab name="Exaggerating">over 9000</tab><tab 
name="Truth">a couple of</tab> switching parts. The <tab index="1">biggest by 
far</tab><tab index="2">main</tab> part of this tab's contents is placed 
outside any <tab index="1">awesome</tab> <code>&lt;tab&gt;</code> tags.
+
+The switching <tab index="1">epicness</tab><tab index="2">parts</tab> are made 
by putting <code>&lt;tab&gt;</code> tags within the flow of the text.
+</tabs>
+----
+This tab menu looks exactly the same, but uses the parser function 
<code><nowiki>{{#tab:name1, name2|content1|content2}}</nowiki></code> or 
<code><nowiki>{{#tab:index1, index2|content1|content2}}</nowiki></code>. This 
makes the code a bit shorter.
+
+<tabs>
+This line of text contains {{#tab:Exagerrating,Truth|over 9000|a couple of}} 
switching parts. The {{#tab:|very biggest|main}} part of this tab's contents is 
placed outside any {{#tab:|awesome}} <code>&lt;tab&gt;</code> tags.
+
+The switching {{#tab:|epicness|parts}} are made by putting 
<code>&lt;tab&gt;</code> tags within the flow of the text.
+</tabs>
+
+===== Predefining tabs and reference syntax =====
+
+Tabs can be predefined via either [[#Self-closing tabs|self-closing tabs]] or 
the [[#Parser function|parser function]]. This tab menu's third tab also uses 
the reference syntax for the parser function.
+
+<tabs>
+<tab name="First"/>{{#tab:Second,Third}}
+The {{#tab:|first|second|third}} tab is predefined via ''{{#tab:|a 
self-closing <code>&lt;tab /&gt;</code> tag|the parser-function syntax|$2}}''.
+
+<tab index="3">The italic text in the above line is defined via a 
<code>$2</code> reference. This automatically inserts the contents for the 
second value entered into the third tab too.
+</tab>
+</tabs>
+
+=== Nested combinations ===
+
+In some cases, it is possible to put multiple of these boxes inside each 
other. For this to work however, the <code>#tag:tabs</code>, 
<code>#tag:tab</code> or <code>#tab:</code> parser functions will have to be 
used whenever two of the same tags are used anywhere within each other. This is 
required because otherwise the wikicode parser will recognise the closing tag 
for the nested tag as the closing tag for the outer tag, and skip the rest of 
the content, which could cause problems.
+
+For the <code>#tag:</code> parser function, even boolean attributes (such as 
<code>dropdown</code> or <code>inline</code>) need to have a value defined for 
them, otherwise they are not recognised as attributes. For example, 
<code><nowiki>{{#tag:tab|Dropdown contents|dropdown}}</nowiki></code> will not 
work (it will show a toggle box instead of a dropdown), while 
<code><nowiki>{{#tag:tab|Dropdown contents|dropdown=true}}</nowiki></code> will 
show a dropdown box.
+
+All combinations of nesting multiple tags will work, except for nesting 
''any'' tab menus inside other tab menus.
+
+==== Nested tab menus ====
+
+===== Inside toggle boxes =====
+
+<tab>
+This tab contains a tab menu:
+
+<tabs>
+{{#tab:First, Second|These tabs use the <code>#tab:</code> parser function to 
create the nested tabs.|Placing <code>&lt;tab&gt;</code> tags inside another 
<code>&lt;tab&gt;</code> tag will cause the parser to recognise the inner 
closing tag as the closing tag for the outer tag, which messes it up.}}
+</tabs>
+</tab>
+
+===== Inside dropdowns =====
+
+<tab dropdown>
+And here is another tab menu:
+<tabs>
+{{#tag:tab|These tabs are generated via the <code>#tag:tab</code> parser 
function|name="First"}}
+{{#tag:tab|This is required, for the same reason as explained in the Second 
tab in the toggle box example above.|name="Second"}}
+</tabs>
+</tab>
+
+==== Nested toggle/dropdown boxes ====
+
+===== Toggle boxes in toggle boxes =====
+<tab>
+This toggle box has another toggle box nested inside it.
+
+{{#tag:tab|This tab is generated by the <code>#tag:tab</code> parser 
function.|openname=Show|closename="Hide"}}
+</tab>
+
+===== Toggle boxes in dropdowns =====
+{{#tag:tab|
+It is also possible to use the <code>#tag:tab</code> parser function for the 
outer tab.
+<tab collapsed>
+This inner toggle box is made via the <code>&lt;tag&gt;</code> syntax.
+</tab>
+|dropdown=true}}
+
+===== Toggle boxes and dropdowns in tab boxes =====
+<tabs>
+<tab name="Toggle box">
+This first tab has a toggle box nested inside it
+{{#tab:Toggle|This toggle box is made via the <code>#tab:</code> parser 
function.}}
+</tab>
+<tab name="Dropdown">
+This second tab has a dropdown nested inside it
+{{#tag:tab|This dropdown is created via the <code>#tag:tab</code> parser 
function, since it's not possible to define attributes such as 
<code>dropdown</code> via the <code>#tab:</code> parser 
function.|dropdown=true}}
+</tab>
+</tabs>
+
+===== Toggle boxes in dropdowns =====
+
+<tab dropdown name="nested toggle boxes" style="width:250px">
+This dropdown has a nested toggle box that has <code>inline</code> and 
<code>collapsed</code> attributes filled in: {{#tag:tab|You can do the same 
things with nested boxes as you'd normally do outside other 
tags.|inline=true|collapsed=true}}
+</tab>
+
+===== Dropdowns in dropdowns =====
+
+<tab dropdown name="nested dropdowns">
+*It is even possible to have a dropdown inside a list item in another dropdown 
box
+*{{#tag:tab|This a dropdown inside a list in the outer dropdown 
menu|dropdown=true}}
+*And it is even possible to have a dropdown inside sub-menus in the dropdown...
+**{{#tag:tab|It also works normally in sub-menus|dropdown=true}}
+Or if you want, you can place it outside lists too.
+{{#tag:tab|Here's a dropdown inside a dropdown, but not in any 
list|dropdown=true}}
+</tab>
diff --git a/Tabs.body.php b/Tabs.body.php
index 351f825..eda7acc 100644
--- a/Tabs.body.php
+++ b/Tabs.body.php
@@ -23,56 +23,26 @@
  * @file
  */
 
-/*Possible features to add:
- * Check if nested <tabs>es work perfectly
- * Dropdown menus with :hover and button:focus
- * Possibility of showing <tab> on multiple indexes, for things like <t 
i="1,2">foo <t i="1">bar</t><t i="2">baz</t></t><t i="3">quux</t>
- *             do this by just adding both .tab-content-1 and .tab-content-2 
to the tab
- * Self-closing tab support, for tab defining at the top: <t n="a"/><t n="b"/> 
using $text===null
- * Use of a parser-function alternative for the <tab> tag: {{#tab:a|b|c|d}}, 
would be useful for inline things
- */
-
 class Tabs {
        /**
-        * @var int $tabsCount Counts the index of the <tabs> tag on the page. 
Increments by 1 before parsing the tag.
-        * @var int $tabCount Counts the index of the <tab> tag on the page. 
Increments by 1 before parsing the tag.
-        */
-       public static $tabsCount = 0;
-       public static $tabCount = 0;
-       
-       /*
-        * @var int $toStyle Counts the maximum amount of <tab> tags used 
within a single <tabs> tag
-        * Its value is used to determine the amount of lines to be added to 
the dynamic stylesheet.
-        */
-       var $toStyle = 0;
-       // TODO: create global settings variable for maximum amount of tabs 
allowed
-       
-       /**
-        * @var int $nested Keeps track of whether the <tab> is nested within a 
<tabs> or not. Value is either 0 or 1.
-        * Will reset to 0 either when parsing recursive tags within <tab>, or 
when finished parsing recursive tags within <tabs>.
-        */
-       public static $nested = false;
-       
-       /**
-        * @var array $tabNames Contains a list of the previously used tab 
names in that scope. 
-        * Will be reset before calling Parser->recursiveTagParse, and is 
returned to its previous value afterwards, to create this effect.
-        */
-       public static $tabNames = array();
-       
-       /**
-        * @var array $labels List of labels to make.
-        * @example array(1 => 'Tab 1', 2 => 'defined name');
-        */
-       public static $labels = array();
-       
-       /**
-        * Initiate the tags
+        * Initiate the tags and parser function
         * @param Parser &$parser
         * @return boolean true
         */
        public static function init( &$parser ) {
-               $parser->setHook( 'tab', array( new self(), 'renderTab' ) );
-               $parser->setHook( 'tabs', array( new self(), 'renderTabs' ) );
+               $parser->tabsData = array(
+                       'tabsCount' => 0, // Counts the index of the <tabs> tag 
on the page. Increments by 1 before parsing the tag.
+                       'tabCount' => 0, // Same, but for <tab> instead.
+                       'addedStatics' => false, // checks if static styles 
have been added, so that it isn't done multiple times.
+                       'toStyle' => 0, // Counts the maximum amount of <tab> 
tags used within a single <tabs> tag. Used to determine the amount of lines to 
be added to the dynamic stylesheet.
+                       'nested' => false, // Keeps track of whether the <tab> 
is nested within a <tabs> or not.
+                       'tabNames' => array(), // Contains a list of the 
previously used tab names in that scope. 
+                       'labels' => array(), // Lists the labels that need to 
be made within <tabs>. Example: array(1 => 'Tab 1', 2 => 'some tab label');
+                       //'dropdown' => false, // Used in combination with 
'nested'; keeps track of whether the <tab> is nested inside a dropdown.
+               );
+               $parser->setHook('tab', array(new self(), 'renderTab'));
+               $parser->setHook('tabs', array(new self(), 'renderTabs'));
+               $parser->setFunctionHook('tab', array(new self(), 'renderPf'));
                return true;
        }
        
@@ -85,19 +55,20 @@
         * @return string
         */
        public function renderTab($input, $attr = array(), $parser) {
-               if ($this::$tabCount === 0) $this->insertCSSJS($parser, true); 
// init styles
-               ++$this::$tabCount;
-               $names = &$this::$tabNames;
-               // This next line allows for "tab defining" at the top of the 
<tabs> tag, so they can be referred to via only their index or name.
-               if (preg_match("/^\s*$/", $input)) return ''; // don't add 
another tab content box when <tab> is empty.
-               $nested = $this::$nested;
+               $form = $parser->tabsData['tabCount'] === 0 ? 
$this->insertCSSJS($parser) : ''; // init styles, set the return <form> tag as 
$form.
+               ++$parser->tabsData['tabCount'];
+               $names = &$parser->tabsData['tabNames'];
+               $nested = $parser->tabsData['nested'];
+               if (isset($attr['name'])) $attr['name'] = 
trim(htmlspecialchars($attr['name'])); // making the name attr safe to use
                // Default value for the tab's given index: index attribute's 
value, or else the index of the tab with the same name as name attribute, or 
else the tab index
-               if (isset($attr['index']) && intval($attr['index']) <= 
count($names))
+               if (!$nested) {
+                       $index = 0; // indices do nothing for non-nested tabs, 
so don't even bother doing the computations.
+               } elseif (isset($attr['index']) && intval($attr['index']) <= 
count($names)) {
                        $index = intval($attr['index']); // if the index is 
given, and it isn't greater than the current index + 1.
-               elseif (isset($attr['name']) && array_search($attr['name'], 
$names) !== false)
-                       $index = array_search($attr['name'], $names) ; // if 
index is not defined, but the name is, use the index of the tabname.
+               } elseif (isset($attr['name']) && array_search($attr['name'], 
$names) !== false)
+                       $index = array_search($attr['name'], $names)+1; // if 
index is not defined, but the name is, use the index of the tabname.
                else {
-                       $index = count($names)+1; // index of this tab in this 
scope.
+                       $index = count($names)+1; // index of this tab in this 
scope. Plus one because tabs are 1-based, arrays are 0-based.
                }
                
                $classPrefix = '';
@@ -109,10 +80,10 @@
                else
                        $attr['class'] = trim("$classPrefix 
".htmlspecialchars($attr['class']));
                
-               if (array_key_exists($index-1, $names)) // if array $names 
already has a name defined at position $index, use that
-                       $name = $names[$index-1];
+               if (isset($names[$index-1])) // if array $names already has a 
name defined at position $index, use that.
+                       $name = $names[$index-1]; // minus 1 because tabs are 
1-based, arrays 0-based.
                else // otherwise, use the entered name, or the $index with a 
"Tab " prefix if it is not defined or empty.
-                       $name = trim(isset($attr['name']) && 
trim($attr['name']) ? $attr['name'] : wfMessage('tabs-tab-label-placeholder', 
$index));
+                       $name = trim(isset($attr['name']) && $attr['name'] ? 
$attr['name'] : wfMessage('tabs-tab-label', $index));
 
                if (!$nested) { // This runs when the tab is not nested inside 
a <tabs> tag.
                        $nameAttrs = array(
@@ -120,8 +91,10 @@
                                'openname'=>isset($attr['openname']),
                                'closename'=>isset($attr['closename']),
                        );
-                       $checked = $this->checkAttrIsDefined('collapsed', 
$attr) ? '' : ' checked="checked"';
-                       $id = str_replace(" ", "_", 
wfMessage('tabs-tab-label-placeholder', $this::$tabCount));
+                       $checked = isset($attr['collapsed']) ? '' : ' 
checked="checked"';
+                       $id = 'Tabs_'.$parser->tabsData['tabCount'];
+                       $dropdown = isset($attr['dropdown']);
+                       if ($dropdown) $attr['style'] = 'width:200px;' . 
(isset($attr['style']) ? $attr['style'] : ''); // default width. Will be 
overridden by styles added by the user, if set.
                        
                        /*
                         * If only one of the openname and closename attributes 
is defined, the both will take the defined one's value
@@ -135,41 +108,56 @@
                        elseif ($nameAttrs['closename'] && 
!$nameAttrs['openname']) $openname = $closename = 
htmlspecialchars($attr['closename']);
                        elseif (!$nameAttrs['openname'] && 
!$nameAttrs['closename'] && $nameAttrs['name']) $openname = $closename = 
htmlspecialchars($attr['name']);
                        elseif (!$nameAttrs['openname'] && 
!$nameAttrs['closename']) {
-                               $openname = 
wfMessage('tabs-toggle-open-placeholder');
-                               $closename = 
wfMessage('tabs-toggle-close-placeholder');
+                               $openname = 
wfMessage('tabs-'.($dropdown?'dropdown-label':'toggle-open'));
+                               $closename = 
wfMessage('tabs-'.($dropdown?'dropdown-label':'toggle-close'));
                        }
                        
                        // Check if the togglebox should be displayed inline. 
No need to check for the `block` attribute, since the default is display:block;
-                       $inline = $this->checkAttrIsDefined('inline', $attr) ? 
' tabs-inline' : '';
-                       $label = "<input class=\"tabs-input\" type=\"checkbox\" 
id=\"$id\"$checked/><label class=\"tabs-label\" for=\"$id\"><span 
class=\"tabs-open\">$openname</span><span 
class=\"tabs-close\">$closename</span></label>";
-                       $attr['class'] = "tabs tabs-togglebox$inline 
".$attr['class'];
-                       $attrStr = $this->getSafeAttrs($attr);
+                       $inline = isset($attr['inline']) ? ' tabs-inline' : '';
+                       $label = "<span 
class=\"tabs-open\">$openname</span><span 
class=\"tabs-close\">$closename</span>";
+                       if ($dropdown) {
+                               $label = "<div class=\"tabs-label\" 
tabindex=\"-1\">$openname</div>"; // negative tabindex allows :focus state on 
click, while not allowing the element to be tabbed to.
+                       } else {
+                               $label = "<input class=\"tabs-input\" 
form=\"tabs-inputform\" type=\"checkbox\" id=\"$id\"$checked/><label 
class=\"tabs-label\" for=\"$id\">$label</label>";
+                       }
+                       $attr['class'] = "tabs tabs-togglebox$inline 
".($dropdown?'tabs-dropdown ':'').$attr['class'];
+                       $containAttrStr = $this->getSafeAttrs($attr);
+                       if (isset($attr['bgcolor'])) {
+                               // preg_split filters for ;{} characters and 
CSS comments, to prevent injection of any other styles than just the 
background-color. Only the input before the filtered characters will be 
included.
+                               $bgcolor = preg_split('/[;{}]|\/\*/', 
trim(htmlspecialchars($attr['bgcolor'])))[0];
+                               $background =  "data-bgcolor=\"$bgcolor\"";
+                               $containAttrStr .= " $background";
+                               $css = "<style 
type=\"text/css\">.tabs-dropdown[$background] .tabs-content, 
.tabs-dropdown[$background] .tabs-container, .tabs-dropdown[$background] li, 
.tabs-dropdown[$background] ul, .tabs-dropdown[$background] ol 
{background-color:$bgcolor}</style>";
+                       } else $css = '';
                        $container = array(
-                               "<div$attrStr><div 
class=\"tabs-container\">$label",
-                               '</div></div>'
+                               "<div$containAttrStr>$css<div 
class=\"tabs-container\">$label",
+                               '</div></div>',
+                               $dropdown?'menu':'div'
                        );
                        $containerStyle = '';
                        if (isset($attr['container'])) $containerStyle = 
htmlspecialchars($attr['container']);
-                       $attrStr = " class=\"tabs-content\" 
style=\"$containerStyle\""; //the attrStr is used in the outer div, so only the 
containerStyle should be applied to the content div.
+                       $attrStr = " class=\"tabs-content\" 
style=\"$containerStyle\"";
                } else { // this runs when the tab is nested inside a <tabs> 
tag.
-                       $container = array('', '');
+                       $container = array('', '', 'div');
                        if (array_search($name, $names) === false) // append 
name if it's not already in the list.
                                $names[] = $name;
-                       if ($this->checkAttrIsDefined('inline', $attr))
-                               $ib = 'tabs-inline';
-                       else if ($this->checkAttrIsDefined('block', $attr))
-                               $ib = 'tabs-block';
+                       
+                       if (isset($attr['block']))
+                               $ib = 'tabs-block ';
+                       elseif (isset($attr['inline']))
+                               $ib = 'tabs-inline ';
                        else
                                $ib = '';
-                       $attr['class'] = "$ib ".$attr['class'];
+                       $attr['class'] = $ib.$attr['class'];
                        $attrStr = $this->getSafeAttrs($attr);
-                       $this::$labels[intval($index)] = $name; // Store the 
index and the name so this can be used within the <tabs> hook to create labels
+                       $parser->tabsData['labels'][intval($index)] = $name; // 
Store the index and the name so this can be used within the <tabs> hook to 
create labels
                }
+               if ($input === null) return ''; // return empty string if the 
tag is self-closing. This can be used to pre-define tabs for referring to via 
the index later.
 
-               $this::$nested = false; // temporary
+               $parser->tabsData['nested'] = false; // temporary
                $newstr = $parser->recursiveTagParse($input);
-               $this::$nested = $nested; // revert
-               return $container[0]."<div$attrStr>$newstr</div>".$container[1];
+               $parser->tabsData['nested'] = $nested; // revert
+               return 
$form.$container[0].'<'.$container[2]."$attrStr>$newstr</".$container[2].'>'.$container[1];
        }
        
        /**
@@ -181,66 +169,101 @@
         * @return string
         */
        public function renderTabs($input, $attr = array(), $parser) {
-               if ($this::$tabsCount === 0) $this->insertCSSJS($parser, true); 
// init styles
-               $count = ++$this::$tabsCount;
-               $attr['class'] = isset($attr['class']) ? 'tabs tabs-tabbox 
'.$attr['class'] : 'tabs tabs-tabbox';
+               if (!isset($input)) return ''; // Exit if the tag is 
self-closing. <tabs> is a container element, so should always have something in 
it.
+               $form = $parser->tabsData['tabCount'] === 0 ? 
$this->insertCSSJS($parser) : ''; // init styles, set the return <form> tag as 
$form.
+               if ($parser->tabsData['tabsCount'] === 0) 
$this->insertCSSJS($parser); // init styles
+               $count = ++$parser->tabsData['tabsCount'];
+               $class = 'tabs tabs-tabbox';
+               if (isset($attr['plain'])) $class .= ' tabs-plain';
+               $attr['class'] = isset($attr['class']) ? "$class 
".$attr['class'] : $class;
                $attrStr = $this->getSafeAttrs($attr);
                $containerStyle = '';
                if (isset($attr['container'])) $containerStyle = 
htmlspecialchars($attr['container']);
                
                // CLEARING:
-               $tabnames = $this::$tabNames; // Copy this array's value, to 
reset it to this value after parsing the inner <tab>s.
-               $this::$tabNames = array(); // temporarily clear this array, so 
that only the <tab>s within this <tabs> tag are tracked.
-               $this::$labels = array(); // Reset after previous usage
-               $this::$nested = true;
+               $tabnames = $parser->tabsData['tabNames']; // Copy this array's 
value, to reset it to this value after parsing the inner <tab>s.
+               $parser->tabsData['tabNames'] = array(); // temporarily clear 
this array, so that only the <tab>s within this <tabs> tag are tracked.
+               $parser->tabsData['labels'] = array(); // Reset after previous 
usage
+               $parser->tabsData['nested'] = true;
                // PARSING
                $newstr = $parser->recursiveTagParse($input);
                // AND RESETTING (to their original values):
-               $this::$tabNames = $tabnames; // reset to the value it had 
before parsing the nested <tab>s. All nested <tab>s are "forgotten".
-               $this::$nested = false; // reset
+               $parser->tabsData['tabNames'] = $tabnames; // reset to the 
value it had before parsing the nested <tab>s. All nested <tab>s are 
"forgotten".
+               $parser->tabsData['nested'] = false; // reset
                
                /**
                 * The default value for $labels creates a seperate input for 
the default tab, which has no label attached to it.
                 * This is to allow any scripts to be able to check easily if 
the user has changed the shown tab at all,
                 * by checking if this 0th input is checked.
                 */
-               $labels = "<input type=\"radio\" id=\"tabs-input-$count-0\" 
name=\"$count\" class=\"tabs-input tabs-input-0\" checked>";
+               $labels = "<input type=\"radio\" form=\"tabs-inputform\" 
id=\"tabs-input-$count-0\" name=\"tabs-$count\" class=\"tabs-input 
tabs-input-0\" checked/>";
                $indices = array(); // this is to most accurately count the 
amount of <tab>s in this <tabs> tag.
-               foreach ($this::$labels as $i => $n) {
+               foreach ($parser->tabsData['labels'] as $i => $n) {
                        $indices[] = $i;
-                       $labels .= $this->makeLabel($i, $n);
+                       $labels .= $this->makeLabel($i, $n, $count);
+               }
+               if (!count($indices)) { // If no tabs have been defined, add 
this plain default tab.
+                       $indices[] = 1;
+                       $labels .= $this->makeLabel(1, 'Tab 1', $count);
                }
                
-               $toStyle = &$this->toStyle;
+               $toStyle = &$parser->tabsData['toStyle'];
                if ($toStyle < count($indices)) { // only redefine the styles 
to be added to the head if we actually need to generate extra styles.
                        $toStyle = count($indices);
                        $this->insertCSSJS($parser); // reload dynamic CSS with 
new amount
                }
                
-               return "<div$attrStr>$labels<div class=\"tabs-container\" 
style=\"$containerStyle\">$newstr</div></div>";
+               return "$form<div$attrStr>$labels<div class=\"tabs-container\" 
style=\"$containerStyle\">$newstr</div></div>";
        }
-               
+       
        /**
-        * Check if an attribute is defined, and doesn't have a false value 
("0", "false" or "null")
-        * @param string|int $attr The key to check for
-        * @param array $obj The array of attributes to search through
-        * @return boolean true when the attribute is defined, its boolean 
value is not false, and not "0", "false" or "null"; false otherwise.
+        * Parser function for simpler inline tab syntax
+        * @param Parser $parser
+        * @param string $index A comma-seperated list of tab names or indices. 
Integers will always be interpreted as indices.
+        * @return string A converted list of <tab> tags, further to be 
processed by the parser.
         */
-       public function checkAttrIsDefined($attr, $obj) {
-               return isset($obj[$attr]) && $obj[$attr] && 
array_search(trim($obj[$attr]), array('0', 'false', 'null')) === false;
+       public function renderPf($parser, $index) {
+               $index = explode(',', $index);
+               $args = max(func_num_args(), count($index)+2);
+               $argcount = func_num_args();
+               $output = '';
+               for ($i = 1; $i+1 < $args; $i++) {// start with 1, since 
that'll be the default index="" for the first tab.
+                       $val = $i+1 < $argcount ? func_get_arg($i+1) : ''; // 
arg 0 will be $parser, arg 1 will be the list of names/indices. Start fetching 
arguments with arg 2. Empty string if this argument is not defined.
+                       $index_i = isset($index[$i-1]) ? trim($index[$i-1]) : 
'';
+                       if (preg_match('/^\d+$/',$index_i) && intval($index_i) 
> 0) {//only assign an index if the attribute is just digits
+                               $attr = "index=\"$index_i\"";
+                               $isname = false;
+                       } elseif ($index_i) { // only assign a name if the name 
attribute isn't just whitespace
+                               $attr = "name=\"$index_i\"";
+                               $isname = true;
+                       } else { // Default: fallback to the current index of 
the parameter within this parser function
+                               $attr = "index=\"$i\"";
+                               $isname = false;
+                       }
+                       if (preg_match('/^\$\d+$/', trim($val))) { // Copying 
over the value of other parameters for the syntax $n. May not contain anything 
other than $n in the value.
+                               $ref = intval(substr(trim($val), 1));
+                               if ($ref+1 < $argcount && $ref > 0) $refval = 
func_get_arg($ref+1); // Only do this when the referred-to value exists
+                               if (trim($refval)) $val = $refval; // only if 
the referred-to value is not empty, assign its value to this parameter
+                       }
+                       if (trim($val)) { // if content is defined for this tab
+                               $output .= "<tab $attr>$val</tab>";
+                       } elseif ($isname) { // if no content is defined, but a 
name is defined. Makes it easier to define all tabs at the top.
+                               $output .= "<tab $attr />";
+                       } //otherwise, just don't append anything to the output.
+               }
+               return array( $output, 'noparse' => false );
        }
        
        /**
         * Template for the tab label
         * @param int $tabN The index of the individual tab.
         * @param string $label The label that is going to appear to the user.
+        * @param int $tagN The index of the <tabs> tag on the page.
         * @return string HTML code of the label
         */
-       public function makeLabel($tabN, $label) {
-               $tagN = $this::$tabsCount;
+       public function makeLabel($tabN, $label, $tagN) {
                $label = htmlspecialchars($label);
-               $id = str_replace(" ", "_", $label);// for direct linking to a 
tab
-               return "<input type=\"radio\" id=\"tabs-input-$tagN-$tabN\" 
name=\"$tagN\" class=\"tabs-input tabs-input-$tabN\"><label 
class=\"tabs-label\" for=\"tabs-input-$tagN-$tabN\" id=\"$id\" 
data-tabpos=\"$tabN\">$label</label>";
+               return "<input type=\"radio\" form=\"tabs-inputform\" 
id=\"tabs-input-$tagN-$tabN\" name=\"tabs-$tagN\" class=\"tabs-input 
tabs-input-$tabN\"/><label class=\"tabs-label\" for=\"tabs-input-$tagN-$tabN\" 
data-tabpos=\"$tabN\">$label</label><wbr/>";
        }
        
        /**
@@ -252,21 +275,8 @@
        public function getSafeAttrs($attr, &$safe = array()) {
                $safeAttrs = array('class', 'id', 'title', 'style');
                $attrStr = '';
-               // Apply width style if width attribute is defined, and no 
styles are defined OR width is not defined in the styles.
-               $widhigh = array('width', 'height');
-               foreach ($widhigh as $i) {
-                       $setStyles = isset($attr['style']) ? $attr['style'] : 
false;
-                       // If the attribute 'width' or 'height' is defined, AND 
either no styles have yet been set, OR those set stiles have no defined 'width' 
or 'height'.
-                       if (isset($attr[$i]) && (!$setStyles || 
!preg_match("/$i\s*:/", $setStyles))) {
-                               $whAttr = $attr[$i];
-                               $whAttr .= preg_match("/^\d+$/", $whAttr) ? 
'px' : ''; // append px when no unit is defined
-                               // insert the 'width' or 'height' style at the 
start of the styles to prevent having to insert a semicolon at the end of the 
current style list, and possibly getting double semicolons.
-                               $attr['style'] = "$i: $whAttr; $setStyles";
-                       }
-               }
-
                foreach ($safeAttrs as $i) {
-                       if (array_key_exists($i,$attr)) {
+                       if (isset($attr[$i])) {
                                $safe[$i] = htmlspecialchars(trim($attr[$i]));
                                $attrStr .= " $i=\"".$safe[$i].'"';
                        } else
@@ -278,24 +288,35 @@
        /**
         * Insert the static and dynamic CSS and JS into the page
         * @param Parser $parser
-        * @param boolean $firstrun Set to true if the initial scripts need to 
be loaded. Default: only the dynamic styles are refreshed.
+        * @return string Returns the form the input elements are assigned to 
via their form="" attribute for semantic purposes.
         */
-       public function insertCSSJS($parser, $firstrun = false) {
-               $parserOutput = $parser->getOutput();
-               $parserOutput->addHeadItem($this->createDynamicCss(), 
'TabsStyles');
-               if ($firstrun) {
-                       $parserOutput->addModuleStyles('ext.tabs');
-                       $parserOutput->addModuleScripts('ext.tabs');
+       public function insertCSSJS(&$parser) {
+               $parserOut = $parser->getOutput();
+               $parserOut->addHeadItem($this->createDynamicCss($parser), 
'TabsStyles');
+               if (!$parser->tabsData['addedStatics']) {
+                       $parser->tabsData['addedStatics'] = true;
+                       $parserOut->addModuleStyles('ext.tabs');
+                       $parserOut->addModuleScripts('ext.tabs');
+                       global $wgOut;
+                       // this form is here to use for the form="" attribute 
in the inputs, for semantically correct usage of the <input> tag outside a 
<form> tag.
+                       return '<form id="tabs-inputform" class="tabs 
tabs-inputform" action="#"></form>';
                }
+               return '';
        }
 
-       public function createDynamicCss() {
-               // TODO: add <form> using prependHTML() for the form="" 
attribute of inputs, for HTML5 semantic compatibility
-               $css = "<style type=\"text/css\">/*<![CDATA[*/\n/* Dynamically 
generated tabs styles */\n";
-               for ($i=1;$i<=$this->toStyle;$i++) {
-                       $css .= ".tabs-input-$i:checked ~ .tabs-container 
.tabs-content-$i,\n";
+       public function createDynamicCss(&$parser) {
+               $css = '';
+               $class = array('', '.tabs-inline', '.tabs-block');
+               $style = array('inline-block', 'inline', 'block');
+               foreach ($class as $n => $c) {
+                       for ($i=1;$i<=$parser->tabsData['toStyle'];$i++) {
+                               $css .= ".tabs-input-$i:checked ~ 
.tabs-container $c.tabs-content-$i,\n";
+                       }
+                       $css .= ".tabs-input-0:checked ~ .tabs-container 
$c.tabs-content-1 {display:".$style[$n].";}\n";
                }
-               $css .= '.tabs-input-0:checked ~ .tabs-container 
.tabs-content-1 {display:inline-block;}';
-               return "$css\n/*]]>*/</style>";
+               $css .= "/* The same styles, but with .checked instead of 
:checked, for browsers that rely on the JavaScript fallback */\n".
+                       str_replace(':checked','.checked', $css);
+               $css .= ".tabs-dropdown .tabs-content, .tabs-dropdown 
.tabs-container, .tabs-dropdown li, .tabs-dropdown ul, .tabs-dropdown ol 
{background-color:".wfMessage('tabs-dropdown-bgcolor').'}';
+               return "<style type=\"text/css\" 
id=\"tabs-dynamic-styles\">/*<![CDATA[*/\n/* Dynamically generated tabs styles 
*/\n$css\n/*]]>*/</style>";
        }
 }
\ No newline at end of file
diff --git a/Tabs.examples.txt b/Tabs.examples.txt
deleted file mode 100644
index c36250d..0000000
--- a/Tabs.examples.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-<tab>
-This is the simplest togglebox, with just a tab tag without any attributes, 
surrounding this text.
-
-Its label will switch between the value of 
[[MediaWiki:tabs-toggle-open-placeholder]] and 
[[MediaWiki:tabs-toggle-close-placeholder]].
-</tab>
-
-<tabs style="font-weight:bold;" class="foo" id="bar">
-<tab name="hello">
-Tab 1 is a named tab without specified index.
-</tab>
-<tab name="world" index="2">
-Tab 2 is a named tab, but with a specified index equal to the default 2.
-</tab>
-<tab index="4" name="">
-Tab 3 is an unnamed tab, with a specified index (4) of higher than the default 
(3), which makes it fall back to the name attribute's value. Its name 
attribute, even though it's defined, is left blank though, so it will fall back 
to the default, defined in [[MediaWiki:tabs-tab-label-placeholder]].
-</tab>
-<tab index="1">
-This is another tab tag, but has a specified ''index'' of 1, so this shows 
when tab 1 is selected
-</tab>
-<tab name="world" style="font-style:italic;" class="bar" id="foo" title="See?">
-This is another tab tag, but has a specified ''name'' of equal to the second 
tab's ("world"), so this shows when tab 2 is selected. It also has a defined 
style, class, id and title attribute.
-</tab>
-<tab name="Tab 3">
-This is another tab tag, but has a specified ''name'' of equal to the third 
tab's ("Tab 3", the default value). This still shows when tab 3 is selected, 
even though tab 3 had no name specified itself.
-</tab>
-
-This bottom text always shows, since it's not placed within a tab tag. This 
parent ''tabs'' tag is also a demonstration of the style, class and id 
attributes.
-</tabs>
-
-<tabs container="border-color:red;">
-This is an <tab index="1" name="happy">inline</tab> example<tab index="2" 
name="sad">&nbsp;of inline tabs</tab>, which <tab 
index="1">demonstrates</tab><tab index="2">shows</tab><tab index="3">gives 
you</tab> the freedom in choosing where <tab index="2">you want</tab> to place 
your nested tabs.
-<tab index="3" name="meh" width="200">
-And this part will only show for tab 3.
-
-Look, it's multiline!
-
-This also demonstrates that tab contents use the 
<code>display:inline-block;</code> style, which can be changed by either adding 
the ''inline'' or ''block'' attribute, and not setting its value to "false" or 
"0". 
-</tab>
-<tab index="3" block>
-This part also only shows for tab 3, but this has a ''block'' attribute that's 
not set to "false" or "0".
-</tab>
-
-Note that the third tab has the default tab label. This is because a tab tag 
without defined name was used first, and then only after that the name was 
defined. It is important to define the name in the first usage of the tab, 
because only the name assigned to the first usage will be used.
-</tabs>
-
-<tab openname="Open this tab" closename="Close this tab" name="you won't see 
this" collapsed>
-This togglebox demonstrates the use of openname and closename attributes, and 
has a ''collapsed'' attribute that's not set to "false" or "0".<br/>
-It also has a defined name attribute, which is not used, since the 
open/closename attributes are defined.
-</tab>
-<tab name="Open/close" index="1" title="The title attribute works too." 
container="background:#ABCDEF;padding:0;">This togglebox has a name, container 
and title attribute, as well as an index attribute. The index attribute has no 
purpose in unnested tab tags though, so that is ignored.</tab>
-
-Here you can see an inline togglebox. <tab inline collapsed>It just shows up 
out of thin air!</tab> This togglebox has an ''inline'' attribute that's not 
set to "false" or "0".
-
-<tabs>
-<tab name="foo"></tab>
-<tab name="bar"></tab>
-This tabsbox has a list of tabs with a name defined earlier at the top of this 
tab. This is useful when making templates that might want to use tabs to switch 
at multiple locations within its body. Referring to the tabs can then be done 
simply via assigning the index attribute to it.
-
-----
-
-This text has <tab index="1">a lot of</tab><tab index="2">many</tab> switching 
parts, <tab index="1">which</tab><tab index="2">and that</tab> makes it <tab 
index="1">easier</tab><tab index="2">simpler</tab> to just use <tab 
index="1">the same</tab><tab index="2">identical</tab> syntax <tab 
index="1">everywhere</tab><tab index="2">for each tab</tab>.
-</tabs>
-
-<tab name="{{#if:1||No #ifs in the attributes}}">This togglebox's contents do 
{{#if:1||not}} allow parser functions like <code>#if:</code> to be used</tab>
-
-<tabs>
-This tabs tag is left without any &lt;tab&gt; tags in it. No tabs will be 
rendered, but the styling of the tab content will remain.
-</tabs>
-
-<tab>
-This is an example of a <code>&lt;tabs&gt;</code> tag nested inside a 
<code>&lt;tab&gt;</code> tag.
-
-<tabs>
-{{#tag:tab|This is a tab inside a tabs inside a tab tag.}}
-{{#tag:tab|And this is tab 2}}
-</tabs>
-</tab>
-
-<tabs>
-<tab>
-This is a test of a <code>&lt;tab&gt;</code> tag within another 
<code>&lt;tab&gt;</code> tag within a <code>&lt;tabs&gt;</code> tag: 
{{#tag:tab|But you won't see this until you open it|collapsed=true}}
-</tab>
-</tabs>
-
-<tabs>
-{{#tag:tab|
-{{#tag:tabs|<tab>If for some reason someone thinks he's funny by nesting 2 
<code>&lt;tabs&gt;</code> tags within each other, this will happen.</tab>}}
-}}
-</tabs>
\ No newline at end of file
diff --git a/Tabs.i18n.magic.php b/Tabs.i18n.magic.php
new file mode 100644
index 0000000..f9238d6
--- /dev/null
+++ b/Tabs.i18n.magic.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Internationalisation file for Tabs extension.
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+$magicWords = array();
+
+/** English
+ * @author Pim (Joeytje50)
+ */
+$magicWords['en'] = array(
+       'tab' => array(0, 'tab'),
+);
\ No newline at end of file
diff --git a/Tabs.php b/Tabs.php
index 0dabea5..074d742 100644
--- a/Tabs.php
+++ b/Tabs.php
@@ -20,7 +20,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
- *
+ * 
  * @file
  */
 
@@ -28,23 +28,25 @@
        'path'           => __FILE__,
        'name'           => 'Tabs',
        'author'         => 'Joeytje50',
-       'url'            => '',
+       'url'            => 'https://www.mediawiki.org/wiki/Extension:Tabs',
        'descriptionmsg' => 'tabs-desc',
 );
 
 $dir = __DIR__ . '/';
 $wgAutoloadClasses['Tabs'] = $dir . 'Tabs.body.php';
-$wgMessagesDirs['Tabs'] = __DIR__ . '/i18n';
 $wgExtensionMessagesFiles['Tabs'] =  $dir . 'Tabs.i18n.php';
+$wgExtensionMessagesFiles['TabsMagic'] =  $dir . 'Tabs.i18n.magic.php';
 $wgHooks['ParserFirstCallInit'][] = 'Tabs::init';
 $wgResourceModules['ext.tabs'] = array(
        'scripts' => 'ext.tabs.js',
        'styles' => 'ext.tabs.css',
        'messages' => array(
-               'tabs-tab-label-placeholder',
-               'tabs-toggle-open-placeholder',
-               'tabs-toggle-close-placeholder',
+               'tabs-tab-label',
+               'tabs-toggle-open',
+               'tabs-toggle-close',
+               'tabs-dropdown-label',
+               'tabs-dropdown-bgcolor',
        ),
        'localBasePath' => __DIR__,
        'remoteExtPath' => 'Tabs',
-);
+);
\ No newline at end of file
diff --git a/ext.tabs.css b/ext.tabs.css
index f4d75c8..7b98ff2 100644
--- a/ext.tabs.css
+++ b/ext.tabs.css
@@ -14,23 +14,65 @@
  * :not(oldbrowser) is chosen as selector, since the <body> tag can't also be 
an <oldbrowser> tag at the same time.
  * The only browsers with :checked support, but without :not() support are 
Opera 9.0-9.5 and Safari 3.1.*
  * Those browsers will have to rely on the JS alternative. If JS is disabled 
for them, all tabs will show at once.
+ * this needs to be a seperate style, since old browsers will ignore the rule 
with :not() altogether.
  * Sources: 
https://developer.mozilla.org/en-US/docs/Web/CSS/:checked#Browser_compatibility,
  *          
https://developer.mozilla.org/en-US/docs/Web/CSS/:not#Browser_compatibility
  */
+body:not(oldbrowser) .tabs-content {display:none;}
 
-body:not(oldbrowser) .tabs-content {display:none;} /* this needs to be a 
seperate style, since old browsers will ignore the rule with :not() altogether 
*/
+/**
+ * This is for testing if the browser supports the :not() selector. !important 
is used to ensure this style doesn't change.
+ * The "sans-serif" ("without-serif") and "serif" fonts are used to indicate 
"sans" :not()-support or with.
+ * This form is used as a "testcase" because it is hidden from view anyway, 
and always present when any <tab> or <tabs> tags are present.
+ * The margin:0px is to determine whether the browser supports the general 
sibling selector ~. If it doesn't, there is "no margin" for interactivity, so 
JS is not activated.
+ */
+#tabs-inputform {font-family:sans-serif !important;margin:0px !important;}
+head~body #tabs-inputform {margin:1px !important;}
+body:not(oldbrowser) #tabs-inputform {font-family:serif !important;}
+
 /**
  * max-height prevents font-boosting on tabs in mobile browsers even when not 
in mobile skin.
  * Font-boosting causes weird differences between tab contents and surrounding 
text (most specifically for inline tabs), so disabling it altogether.
  * If font-boosting doesn't create difference in size between text and inline 
tab contents anymore, remove or comment out the next line.
  */
 .tabs, .tabs * {max-height:1000000px;}
-.tabs-input, .tabs-close {display:none;}
+.tabs-input, .tabs-close, #tabs-inputform, body.tabs-oldbrowserscript 
.tabs-content {display:none;}
 .tabs-tabbox, .tabs-togglebox {margin:10px 0;}
 .tabs-label {
        cursor:pointer;
-       padding:2px 10px;
+       padding:1px 6px;
        background-color:#DDD;
+       border:1px solid #AAA;
+}
+.tabs-togglebox.tabs-inline {display:inline-block;}
+
+/**
+ * Regarding the * html and *+html selectors
+ * 
+ * IE ver. 5.5-7 support no inline-block on divs.
+ * These selectors manage to select the <html> tag in versions 6 and 7 of IE, 
respectively.
+ * Do not change .tabs-togglebox to a <span> just for supporting these 
versions of IE though, because block-level elements will be placed within it
+ *     and it is not allowed to nest block-level elements inside span elements.
+ * Sources: http://blogs.msdn.com/b/ie/archive/2005/09/02/460115.aspx
+ *          http://www.webdevout.net/css-hacks#in_css-selectors
+ *          https://en.wikipedia.org/wiki/CSS_hack#Star_plus_hack
+ */
+* html .tabs-togglebox .tabs-inline {display:inline;}/*IE6 and below*/
+*+html .tabs-togglebox .tabs-inline {display:inline;}/*IE7 only*/
+
+/**
+ * The following is an alternative to the non-IE<9 `:first-of-type` and 
selects the first tabs-label,
+ * since only the first label is positioned behind 2 inputs in a row.
+ */
+.tabs-tabbox > .tabs-input+ .tabs-input+ .tabs-label {margin-left:10px;}
+.tabs-tabbox > .tabs-container {
+       margin-top:-1px;
+       padding:2px 6px;
+       border-radius:8px;
+       position:relative;
+       border:1px solid #AAA;
+       width:inherit; /*This will cause the width to be inherited from the 
main tab, and enables the possibility to use width:inherit within the tab 
itself too */
+       z-index:1; /* unselected tab is positioned below the content this way */
 }
 .tabs-tabbox > .tabs-label {
        margin:0 2px;
@@ -38,37 +80,20 @@
        border-radius:7px 7px 0 0;
        position:relative;
        display:inline-block;
+       vertical-align:bottom;
 }
-.tabs-container, .tabs-label {border:1px solid #AAA;}
-.tabs-inline {display:inline-block;}
-.tabs-block {display:block;}
-/**
- * Regarding the * html and *+html selectors
- * 
- * IE ver. 5.5-7 support no inline-block on divs.
- * These selectors manage to select the <html> tag in versions 6 and 7 of IE, 
respectively.
- * Do not change .tabs-togglebox to a <span> just for supporting these 
versions of IE though, because block-level elements will occur within it
- *     and it is not allowed to nest block-level elements inside span elements.
- * Sources: http://blogs.msdn.com/b/ie/archive/2005/09/02/460115.aspx
- *          http://www.webdevout.net/css-hacks#in_css-selectors
- *          https://en.wikipedia.org/wiki/CSS_hack#Star_plus_hack
- */
-* html .tabs-inline {display:inline;}/*IE6 and below*/
-*+html .tabs-inline {display:inline;}/*IE7 only*/
-
-/**
- * The following is an alternative to the non-IE<9 `:first-of-type` and 
selects the first tabs-label,
- *     since only the first label is positioned behind 2 inputs in a row.
- */
-.tabs-tabbox > .tabs-input+ .tabs-input+ .tabs-label {margin-left:10px;}
-.tabs-tabbox > .tabs-container {
-       margin-top:-1px;
-       padding:2px 5px;
+.tabs-plain > .tabs-label {
+       border:1px solid #AAA;
        border-radius:8px;
-       position:relative;
-       width:inherit; /*This will cause the width to be inherited from the 
main tab, and enables the possibility to use width:inherit within the tab 
itself too */
-       z-index:1; /* unselected tab is positioned below the content this way */
+       margin:2px;
 }
+.tabs-plain > .tabs-container {
+       border-radius:0;
+       border:none;
+       padding:0;
+       margin-top:1px;
+}
+
 .tabs-togglebox > .tabs-container {
        display:inline-block; /* this is to make the box the minimal width it 
needs to be */
        padding:0;
@@ -78,27 +103,201 @@
        display:block;
        text-align:center;
        border-radius:7px;
+       padding:1px 5px;
        margin:0;
-       border:none;
+       outline:none; /* prevent :focus outline */
 }
 .tabs-togglebox >*> .tabs-content {
-       padding:0 5px;
+       padding:2px 6px;
        border-radius:0 0 7px 7px;
-       border-top:1px solid #AAA;
+       border:1px solid #AAA;
+       border-top:none;
        vertical-align:top;
 }
+
+.tabs-dropdown .tabs-container {
+       width:inherit;
+       position:relative;
+}
+.tabs-dropdown >*> .tabs-content {border-radius:0;}
+.tabs-dropdown p {margin:0;}
+.tabs-dropdown >*> .tabs-label {
+       margin-right:-14px; /* This is to align the label with the tabs content 
correctly: it becomes 2*7px (padding + border-width on tabs-content) wider. */
+}
+.tabs-dropdown {margin-right:14px;} /*Cancel out the -14px margin to prevent 
clipping problems*/
+.tabs-dropdown >*> .tabs-content {
+       position:absolute;
+       z-index:100000;
+       cursor:default;
+       margin:0;
+       padding:0 6px;
+       display:block; /* tabs-content is display:block by default, but is 
hidden by moving it off the screen to allow delaying the showing of the 
contents, via CSS transitions */
+       left:-1000000px; /*move the menu off the screen. As opposed to 
display:none, this does allow transition-delay.*/
+}
+.tabs-dropdown >*> .tabs-content,
+.tabs-dropdown li ul,
+.tabs-dropdown li ol {
+       width:inherit;
+       box-shadow:2px 3px 5px #888;
+}
+.tabs-dropdown li {width:inherit;}
+
+.tabs-dropdown >*> .tabs-label,
+.tabs-dropdown >*> .tabs-content,
+.tabs-dropdown ul, .tabs-dropdown ul:before,
+.tabs-dropdown ol, .tabs-dropdown ol:before {
+       /* Delay opening the togglebox to prevent accidental opening when 
moving the mouse over it. this should be enough delay to accomplish this. */
+       -webkit-transition-property: left, margin-left, border-radius; 
-webkit-transition-delay: 0.2s;
+       -moz-transition-property: left, margin-left, border-radius; 
-moz-transition-delay: 0.2s;
+       -o-transition-property: left, margin-left, border-radius; 
-o-transition-delay: 0.2s;
+       transition-property: left, margin-left, border-radius; 
transition-delay: 0.2s;
+}
+
+.tabs-dropdown .tabs-dropdown {
+       margin-left:-7px; /* prevent overflowing for nested dropdowns. */
+}
+.tabs-dropdown li li .tabs-dropdown {
+       margin-left:0; /* this negative margin is not necessary in sub-menus */
+}
+
+.tabs-dropdown li,
+.tabs-dropdown >*> .tabs-content> a,
+.tabs-dropdown >*> .tabs-content>p> a,
+.tabs-dropdown ol>li> a {
+       display:list-item;
+       list-style:none;
+       margin:-1px -6px 0 -6px; /*These margins and padding styles cause the 
<li> to take up the full width of the dropdown: -6px cancels out the original 
padding.*/
+       padding:2px 6px;
+       border-top:1px solid #AAA;
+       position:relative;
+}
+
+.tabs-dropdown ol>li> a {
+       border:none;
+       margin:-2px -6px;
+       padding:2px 6px;
+}
+.tabs-dropdown li li a {
+       margin:-2px 0;
+}
+.tabs-dropdown li li,
+.tabs-dropdown li li:last-child {
+       margin-left:0; /* cancel out negative margins for the nested <li>s */
+       margin-right:0;
+       padding:2px 0;
+}
+.tabs-dropdown >*> .tabs-content ul,
+.tabs-dropdown >*> .tabs-content ol {
+       margin:0; /*remove initial margins*/
+       width:inherit;
+}
+.tabs-dropdown li ul,
+.tabs-dropdown li ol {
+       position:absolute;
+       border:1px solid #AAA;
+       top:-1px;
+       left:-1000012px;
+}
+.tabs-dropdown li ul ~ ul, .tabs-dropdown li ul ~ ol,
+.tabs-dropdown li ol ~ ul, .tabs-dropdown li ol ~ ol {
+       display:none; /*This prevents multiple different types of lists from 
overlapping within sub-menus. Sub-menus should always use the same type of list 
for all items.*/
+}
+.tabs-dropdown li ul:before,
+.tabs-dropdown li ol:before {
+       content: ">";
+       color:#88F;
+       font-weight:bold;
+       position:absolute;
+       left:100%;
+       margin-left:1000012px;
+}
+.tabs-dropdown li li ul:before,
+.tabs-dropdown li li ol:before {
+       margin-left:1000000px;
+}
+
 /* Interactivity styles */
 
-.tabs-label:hover {background-color:#CCC;}
-.tabs-label:active {background-color:#CCE;}
-.tabs-tabbox > .tabs-input:checked + .tabs-label,
+.tabs-label:hover {
+       background-color:#CCC;
+}
+.tabs-label:active, .tabs-label:focus {
+       background-color:#CCE;
+}
+.tabs-tabbox > .tabs-input:checked + .tabs-label, 
 .tabs-input-0:checked + .tabs-input-1 + .tabs-label {
        z-index:2;
        background-color:#FFF;
 }
-.tabs-togglebox >*> .tabs-input:checked + .tabs-label {border-radius:7px 7px 0 
0;}
-.tabs-togglebox >*> .tabs-input:checked ~ .tabs-content {
+.tabs-togglebox >*> .tabs-input:checked + .tabs-label,
+.tabs-dropdown >*> .tabs-label:focus, .tabs-dropdown:hover >*> .tabs-label 
{border-radius:7px 7px 0 0;}
+
+.tabs-togglebox >*> .tabs-input:checked ~ .tabs-content {display:block;}
+/* tabs-close is hidden by default, tabs-open is shown by default. Swap this 
when the tab is opened. */
+.tabs-togglebox .tabs-input:checked + * .tabs-close {display:inline;}
+.tabs-togglebox .tabs-input:checked + * .tabs-open {display:none;}
+
+
+.tabs-dropdown >*> .tabs-content li:hover {
+       background:#CCC;
+}
+.tabs-dropdown a,
+.tabs-dropdown a:hover,
+.tabs-dropdown a:visited {
+       color:#15B;
+}
+.tabs-dropdown a:active {
+       color:#108;
+}
+.tabs-dropdown >*> .tabs-content> a:hover,
+.tabs-dropdown >*> .tabs-content>p> a:hover,
+.tabs-dropdown ol>li> a:hover {
+       background:#CCE;
+       text-decoration:none;
+}
+
+.tabs-dropdown >*> .tabs-label:focus + .tabs-content, .tabs-dropdown:hover >*> 
.tabs-content {left:0;}
+.tabs-dropdown >*> .tabs-content li:hover > ul,
+.tabs-dropdown >*> .tabs-content li:hover > ol {
+       left:100%;
+}
+.tabs-dropdown >*> .tabs-content li:hover > ul:before,
+.tabs-dropdown >*> .tabs-content li:hover > ol:before {
+       margin-left:0;
+       left:-12px;
+}
+
+/***** The same :checked interactivity styles, but for non-:checked browsers 
with JS *****/
+.tabs-tabbox > .tabs-input.checked + .tabs-label,
+.tabs-input-0.checked + .tabs-input-1 + .tabs-label {
+       z-index:2;
+       background-color:#FFF;
+}
+.tabs-togglebox >*> .tabs-input.checked ~ .tabs-content {display:block;}
+.tabs-togglebox >*> .tabs-input.checked + * .tabs-close {display:inline;}
+.tabs-togglebox >*> .tabs-input.checked + * .tabs-open {display:none;}
+
+/**
+ * The following is an alternative toggle system for Android Browser using 
<detail> and <summary> tags
+ * which is based on http://stackoverflow.com/q/21357641/1256925 
+ */
+
+summary::-webkit-details-marker {
+       display:none;
+}
+.tabs-togglebox details.tabs-container:not([open]) .tabs-content {
+       display:none;
+}
+.tabs-togglebox details.tabs-container[open] .tabs-content {
        display:block;
 }
-.tabs-togglebox >*> .tabs-input:checked + * .tabs-close {display:inline;} /* 
tabs-close is hidden by default, tabs-open is shown by default. Swap this when 
the tab is opened. */
-.tabs-togglebox >*> .tabs-input:checked + * .tabs-open {display:none;}
\ No newline at end of file
+
+.tabs-togglebox details.tabs-container:not([open]) .tabs-label {
+       border-radius: 7px;
+}
+.tabs-togglebox details.tabs-container[open] .tabs-label {
+       border-radius: 7px 7px 0 0;
+}
+
+.tabs-togglebox details.tabs-container[open] .tabs-close {display:inline;}
+.tabs-togglebox details.tabs-container[open] .tabs-open {display:none;}
\ No newline at end of file
diff --git a/ext.tabs.js b/ext.tabs.js
index f2ac60f..0d0f407 100644
--- a/ext.tabs.js
+++ b/ext.tabs.js
@@ -1,4 +1,63 @@
 $(function() {
-       if (document.getElementById(document.location.hash.substr(1))) {} // 
TODO: #hash -> label -> data-tabpos -> contentdiv
-       // TODO: IE8- support
+       if ($('#tabs-inputform').css('font-family').replace(/["']/g,'') == 
'sans-serif' && $('#tabs-inputform').css('margin') == '1px') {
+       // Credit for this testing method: 2astalavista @ 
http://stackoverflow.com/a/21095568/1256925
+               $(function() {
+                       $('body').addClass('tabs-oldbrowserscript'); // Make 
the unselected tabs hide when the browser loads this script
+                       $('.tabs-label').click(function(e) { 
$('#'+$(this).attr('for')).click(); e.preventDefault(); return false; });
+                       $('.tabs-input').each(function() {
+                               if (this.checked) $(this).addClass('checked'); 
// Adds checked class to each checked box
+                       }).change(function() {
+                               if (!this.checked) return 
$(this).removeClass('checked'); // for toggleboxes
+                               
$(this).siblings('.checked').removeClass('checked'); // Uncheck all currently 
checked siblings
+                               $(this).addClass('checked'); // and do check 
this box
+                               
$(this).parents('.tabs').toggleClass('tabs').toggleClass('tabs'); // remove and 
readd class to recalculate styles for its children.
+                               // Credit: Fabrício Matté @ 
http://stackoverflow.com/a/21122724/1256925
+                       });
+                       moveToHash();
+               });
+       } else
+               $(moveToHash);
+
+       /**
+        * Imitates the normal feature in browsers to scroll to an id that has 
the same id as the url fragment/hash.
+        * This makes it unnecessary to use actual ids on the tabs, which could 
cause the same id to occur twice in the same document.
+        * Does not scroll to exactly the tab's height, but just a bit above it.
+        */
+       function moveToHash() {
+               var hash = location.hash.substr(1).replace(/_/g,' ').trim();
+               if (!hash || $(location.hash).length) return; // if there's no 
hash defined, or an element on the page with the same hash already, stop 
looking for tabs
+               $('.tabs-tabbox 
.tabs-label:contains('+hash+')').each(function() {
+                       // double-check if the hash is indeed exactly the same 
as the label.
+                       // Does not match if hash is only a part of the label's 
contents, unlike jQuery's :contains() selector
+                       if (this.innerHTML.trim() !== hash) return true; // 
continue the $.each() function
+                       this.click(); // open the selected tab by default.
+                       document.documentElement.scrollTop = this.offsetTop;
+                       return false; // stop the $.each() function after the 
first match.
+               });
+       }
+       
+       /*
+        * System to fix toggle boxes in Android Browser
+        * Browser detection based on 
http://stackoverflow.com/a/15591516/1256925
+        * Idea for the use of <detail> and <summary> based on 
http://stackoverflow.com/q/21357641/1256925
+        */
+       var nua = navigator.userAgent;
+       var is_android = ((nua.indexOf('Mozilla/5.0') > -1 && 
nua.indexOf('Android ') > -1 && nua.indexOf('AppleWebKit') > -1) && 
!(nua.indexOf('Chrome') > -1));
+       if (is_android) {
+               function replaces() { //General replacement function for both 
tags
+                       var tagName = $(this).is('.tabs-container') ? 'details' 
: 'summary'; //determine the required tag name
+                       var $newNode = $('<'+tagName+'/>').html($(this).html());
+                       for (var i=0;i<this.attributes.length;i++) { //copy all 
attributes from the original element
+                               if (this.attributes[i].nodeName === 'for') 
continue; //don't copy the label's for="" attribute, since it's not needed here.
+                               $newNode.attr(this.attributes[i].nodeName, 
this.attributes[i].value);
+                       }
+                       return $newNode;
+               }
+               $('.tabs-togglebox .tabs-container').not('.tabs-dropdown 
.tabs-container').replaceWith(replaces); //do not select dropdowns, which 
already work in Android
+               $('.tabs-togglebox .tabs-label').not('.tabs-dropdown 
.tabs-label').each(function() {
+                       if ($(this).prevAll('input').prop('checked')) { 
//preserve open state of the toggle box
+                               $(this).parents('details').prop('open', true);
+                       }
+               }).replaceWith(replaces); //Run this *after* the 
.tabs-container has finished, otherwise all .tabs-label elements will be 
skipped.
+       }
 });
\ No newline at end of file
diff --git a/i18n/en.json b/i18n/en.json
index 0dc5ad8..63e0946 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1,11 +1,13 @@
 {
-    "@metadata": {
-        "authors": [
-            "Pim (Joeytje50)"
-        ]
-    },
-    "tabs-desc": "Adds <code>&lt;tabs&gt;</code>, <code>&lt;tab&gt;</code> and 
<code>&lt;tabdef&gt;</code> tags for creating tabbed layout.",
-    "tabs-tab-label-placeholder": "Tab $1",
-    "tabs-toggle-open-placeholder": "Show contents",
-    "tabs-toggle-close-placeholder": "Hide contents"
+       "@metadata": {
+               "authors": [
+                       "Pim (Joeytje50)"
+               ]
+       },
+       "tabs-desc": "Adds <code>&lt;tabs&gt;</code>, <code>&lt;tab&gt;</code> 
and <code>&lt;tabdef&gt;</code> tags for creating tabbed layout.",
+       "tabs-tab-label": "Tab $1",
+       "tabs-toggle-open": "Show contents",
+       "tabs-toggle-close": "Hide contents",
+       "tabs-dropdown-label": "Show dropdown",
+       "tabs-dropdown-bgcolor": "white"
 }
diff --git a/i18n/nl.json b/i18n/nl.json
index 9466a31..a6f848c 100644
--- a/i18n/nl.json
+++ b/i18n/nl.json
@@ -1,11 +1,12 @@
 {
-    "@metadata": {
-        "authors": [
-            "Pim (Joeytje50)"
-        ]
-    },
-    "tabs-desc": "Voegt <code>&lt;tabs&gt;</code>, <code>&lt;tab&gt;</code> 
and <code>&lt;tabdef&gt;</code> toe voor opmaak met tabbladen.",
-    "tabs-tab-label-placeholder": "Tab $1",
-    "tabs-toggle-open-placeholder": "Toon inhoud",
-    "tabs-toggle-close-placeholder": "Verberg inhoud"
+       "@metadata": {
+               "authors": [
+                       "Pim (Joeytje50)"
+               ]
+       },
+       "tabs-desc": "Voegt <code>&lt;tabs&gt;</code>, <code>&lt;tab&gt;</code> 
and <code>&lt;tabdef&gt;</code> toe voor opmaak met tabbladen.",
+       "tabs-tab-label": "Tab $1",
+       "tabs-toggle-open": "Inhoud weergeven",
+       "tabs-toggle-close": "Inhoud verbergen",
+       "tabs-dropdown-label": "Uitklapmenu weergeven",
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
new file mode 100644
index 0000000..d9f612a
--- /dev/null
+++ b/i18n/qqq.json
@@ -0,0 +1,13 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Pim (Joeytje50)"
+               ]
+       },
+       "tabs-desc": 
"{{desc|name=Tabs|url=http://www.mediawiki.org/wiki/Extension:Tabs}}";,
+       "tabs-tab-label": "The default label for a tabs menu. Parameter $1 
stands for the index of the tab.",
+       "tabs-toggle-open": "The default opening label for toggle boxes.",
+       "tabs-toggle-close": "The default closing label for toggle boxes.",
+       "tabs-dropdown-label": "The default label for a dropdown menu.",
+       "tabs-dropdown-bgcolor": "{{notranslate}} The default background-color 
for dropdown menus."
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/145559
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I713bef02f2955e3cc16918e2b1fcd447d5293ebc
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/extensions/Tabs
Gerrit-Branch: master
Gerrit-Owner: Joeytje50 <joeytj...@gmail.com>
Gerrit-Reviewer: Joeytje50 <joeytj...@gmail.com>
Gerrit-Reviewer: Raimond Spekking <raimond.spekk...@gmail.com>
Gerrit-Reviewer: Siebrand <siebr...@kitano.nl>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to