# Changes for page Tabs macro

Last modified by Helge Dahl on 2018/01/22 10:41

#### Export

#### Office Formats

Export as PDF Export as ODT Export as RTF

#### Other Formats

Export as HTML
From empty
To version 1.1
edited by Helge Dahl
on 2018/01/22 10:41
Change comment: Install extension [org.xwiki.contrib:xwiki-macro-tabs/1.0.2]

## Summary

- Page properties (6 modified, 0 added, 0 removed)
- Objects (0 modified, 3 added, 0 removed)
  - XWiki.JavaScriptExtension[0]
  - XWiki.WikiMacroClass[0]
  - XWiki.WikiMacroParameterClass[0]

## Details

Page properties
  Title

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Tabs macro

  Parent

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Macro.WebHome

  Author

    ... | ... | @@ -1,1 +1,1 @@
    1 |  | -XWiki.XWikiGuest
    | 1 | +xwiki:XWiki.hde

  Syntax

    ... | ... | @@ -1,1 +1,1 @@
    1 |  | -XWiki 2.1
    | 1 | +XWiki 2.0

  Content

    ... | ... | @@ -1,0 +1,125 @@
    | 1 | +{{box cssClass="floatinginfobox" title="**Contents**"}}{{toc start="2" depth="6" numbered="false" scope="page" /}}{{/box}}
    | 2 | +
    | 3 | +{{velocity}}
    | 4 | +#macro(tabs $tabsKeyNames)
    | 5 | + ## for debugging, please
    | 6 | + ## 1) copy/paste the macro code from macro object into here
    | 7 | + ## 2) replace #set ($tabsSortedMapString = $context.macro.params.tabsKeyNames) with #set ($tabsSortedMapString = $tabsKeyNames)
    | 8 | +#end
    | 9 | +{{/velocity}}
    | 10 | +
    | 11 | +{{info}}This is home and test page for the "tabs" macro.{{/info}}
    | 12 | +Creates tabbed view for specified content areas wrapped in <div/>s with unique ids
    | 13 | +
    | 14 | +== Usage ==
    | 15 | +
    | 16 | +{{box}}
    | 17 | +1. Define where tabs should be rendered {{{{{tabs idsToLabels='tabId1=Tab One, tabId2=Tab Two, ..., tabIdN=Tab N' /}}}}}
    | 18 | +2. Define tabs content in {{{(%id="<unique tab id>"%)(((<tab content here>)))}}}:
    | 19 | + {{{(%id="tabId1"%)(((Tab 1 Content)))}}}
    | 20 | + {{{(%id="tabId2"%)(((Tab 2 Content)))}}}
    | 21 | + ...
    | 22 | + {{{(%id="tabIdN"%)(((Tab N Content)))}}}
    | 23 | +{{/box}}
    | 24 | +
    | 25 | +== Parameters definition ==
    | 26 | +
    | 27 | +|=Name |=Optional |=Allowed values |=Default value |=Description
    | 28 | +|idsToLabels |no |String | - |This parameter required a comma-separated tab id to tab label values sting formatted like idsToLabels='tabId1=Tab One, tabId2=Tab Two, tabId3=TabThree'.
    | 29 | +
    | 30 | +== Known issues ==
    | 31 | +* Tab size is fixed (toucan skin), labels that do not fit will get trimmed (see [[Tab name too long>>#HTabnametoolong?skin=toucan]])
    | 32 | +* Layout consistency is dependent on white-spaces (see [[Interesting layout bugs>>#HInterestinglayoutbugs]])
    | 33 | +
    | 34 | +== Examples ==
    | 35 | +
    | 36 | +=== Content generated by XWiki-wide macro ===
    | 37 | +{{tabs idsToLabels='tabId11=My xwiki-wide tabs, tabId12=My working tabs :)' /}}
    | 38 | +(%id="tabId11"%)((({{box cssClass="tabId11div"}}
    | 39 | +First tab!
    | 40 | +{{/box}}
    | 41 | +I can post any content here
    | 42 | +)))
    | 43 | +
    | 44 | +(%id="tabId12"%)((({{box cssClass="tabId12div"}}
    | 45 | +Second tab!
    | 46 | +{{/box}}
    | 47 | +And here too
    | 48 | +)))
    | 49 | +
    | 50 | +
    | 51 | +=== Known bugs example ===
    | 52 | +==== Tab name too long ====
    | 53 | +You should view this issue in [[Toucan>>#HTabnametoolong?skin=toucan]] skin.
    | 54 | +Content is generated from this code: ##~{~{tabs idsToLabels='sql2key1=Small tab, sql2key2=**Second large tab with large label**' /~}~}##
    | 55 | +{{tabs idsToLabels='sql2key1=Small tab, sql2key2=Second large tab with large label' /}}
    | 56 | +(%id="sql2key1"%)((({{code language="sql" }}
    | 57 | +SELECT COUNT(ctg_id) AS col_0_0_ FROM categories
    | 58 | +-- some text
    | 59 | +-- several lines
    | 60 | +-- of comments
    | 61 | +-- describing this sql query
    | 62 | +{{/code}})))
    | 63 | +
    | 64 | +(%id="sql2key2"%)((({{code language="sql"}}
    | 65 | +SELECT COUNT(ctg_id) AS col_0_0_ FROM categories2
    | 66 | +-- another tab with text
    | 67 | +
    | 68 | +-- Testing content overflow
    | 69 | +-- Text below this box ...
    | 70 | +-- ... should not get covered with it
    | 71 | +
    | 72 | +-- just check this!!!
    | 73 | +
    | 74 | +-- btw: no extra-paragraph has been added before the macro
    | 75 | +{{/code}})))
    | 76 | +
    | 77 | +==== Interesting layout bugs ====
    | 78 | +===== White spaces before ~(~%id =====
    | 79 | +{{tabs idsToLabels='sql3key1=Tab 1, sql3key2=Tab 2' /}}
    | 80 | + (%id="sql2key1"%)((({{code language="sql" }}
    | 81 | +SELECT COUNT(ctg_id) AS col_0_0_ FROM categories
    | 82 | +-- some text
    | 83 | +-- of comments
    | 84 | +-- describing this sql query
    | 85 | +{{/code}})))
    | 86 | +
    | 87 | +(%id="sql3key2"%)((({{code language="sql"}}
    | 88 | +SELECT COUNT(ctg_id) AS col_0_0_ FROM categories2
    | 89 | +-- another tab with text
    | 90 | +-- some text
    | 91 | +-- more lines in comments
    | 92 | +-- describing this sql query
    | 93 | +{{/code}})))
    | 94 | +
    | 95 | +===== White spaces before ~{~{code =====
    | 96 | +Check this bug in both [[Colibri>>#HWhitespacesbeforecode?skin=colibri]] and [[Toucan>>#HWhitespacesbeforecode?skin=toucan]] skins.
    | 97 | +{{tabs idsToLabels='sql4key1=Tab 1, sql4key2=Tab 2' /}}
    | 98 | +(%id="sql4key1"%)(((
    | 99 | + {{code language="sql" }}
    | 100 | +SELECT COUNT(ctg_id) AS col_0_0_ FROM categories
    | 101 | +-- some text
    | 102 | +-- of comments
    | 103 | +-- describing this sql query
    | 104 | +{{/code}})))
    | 105 | +
    | 106 | +(%id="sql4key2"%)(((
    | 107 | + {{code language="sql"}}
    | 108 | +SELECT COUNT(ctg_id) AS col_0_0_ FROM categories2
    | 109 | +-- another tab with text
    | 110 | +-- some text
    | 111 | +-- more lines in comments
    | 112 | +-- describing this sql query
    | 113 | +{{/code}})))
    | 114 | +
    | 115 | +=== Example for debugging ===
    | 116 | +Content generated by in-page macro (used for quick macro debugging).
    | 117 | +See instructions for debugging at the top of the page
    | 118 | +{{velocity}}#tabs('tabId31=Tab one, tabId32=Tab 2'){{/velocity}}
    | 119 | +(%id="tabId31"%)((({{box }}
    | 120 | +First tab content
    | 121 | +{{/box}})))
    | 122 | +
    | 123 | +(%id="tabId32"%)((({{box }}
    | 124 | +Second tab content
    | 125 | +{{/box}})))

XWiki.JavaScriptExtension[0]
  Caching policy

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +long

  Code

    ... | ... | @@ -1,0 +1,35 @@
    | 1 | +var TAB_LIST_ITEM_ID_PREFIX = "ListItem";
    | 2 | +
    | 3 | +function activateTab(activatedTabId) {
    | 4 | + // mark the tab itself as Active
    | 5 | + document.getElementById(activatedTabId + TAB_LIST_ITEM_ID_PREFIX).className = 'active';
    | 6 | + // show content pane
    | 7 | + var activatedTabContentDiv = document.getElementById(activatedTabId);
    | 8 | + if (activatedTabContentDiv) {
    | 9 | + activatedTabContentDiv.style.display = 'block';
    | 10 | + activatedTabContentDiv.style.margin = 0;
    | 11 | + }
    | 12 | +}
    | 13 | +
    | 14 | +function deactivateTabs(tabsIdsArray, activatedTabId) {
    | 15 | + var deactivatedTabContentDiv = null;
    | 16 | + for (var i = 0; i < tabsIdsArray.length; i++) {
    | 17 | + var deactivatedTabId = tabsIdsArray[i];
    | 18 | + if (activatedTabId == deactivatedTabId) {
    | 19 | + // skip this same tab
    | 20 | + continue;
    | 21 | + }
    | 22 | + // mark the tab itself as Inactive
    | 23 | + document.getElementById(deactivatedTabId + TAB_LIST_ITEM_ID_PREFIX).className = '';
    | 24 | + // hide div
    | 25 | + deactivatedTabContentDiv = document.getElementById(deactivatedTabId);
    | 26 | + if (deactivatedTabContentDiv) {
    | 27 | + deactivatedTabContentDiv.style.display = 'none';
    | 28 | + }
    | 29 | + }
    | 30 | +}
    | 31 | +
    | 32 | +function switchTab(activatedTabId, tabsIdsArray) {
    | 33 | + deactivateTabs(tabsIdsArray, activatedTabId);
    | 34 | + activateTab(activatedTabId);
    | 35 | +}

  Name

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +TabHelper

  Parse content

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Yes

  Use this extension

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +onDemand

XWiki.WikiMacroClass[0]
  Macro code

    ... | ... | @@ -1,0 +1,64 @@
    | 1 | +{{velocity}}
    | 2 | + $xwiki.jsx.use("Macro.TabsMacro")
    | 3 | + #set ($tabsSortedMapString = $context.macro.params.idsToLabels)
    | 4 | + ## split incoming string into 2 velocity arrays
    | 5 | + #set ($tabMapEntriesStringArray = $tabsSortedMapString.split(','))
    | 6 | + #set( $tabIdsArray = [])
    | 7 | + #set( $tabNamesArray = [])
    | 8 | + #foreach($tabEntryString in $tabMapEntriesStringArray )
    | 9 | + #if ("$!tabEntryString" == "" )
    | 10 | + ## ignore null or empty (see http://wiki.apache.org/velocity/CheckingForNull)
    | 11 | + #else
    | 12 | + #set ($tabEntryArray = $tabEntryString.trim().split('='))
    | 13 | + #if ($tabEntryArray.size()!=2)
    | 14 | + {{error}}Parameter $tabEntryString is not a valid key=value pair in the provided map: $tabsSortedMapString{{/error}}
    | 15 | + #else
    | 16 | + #set ($addResult = $tabIdsArray.add($tabEntryArray.get(0).trim()))
    | 17 | + #set ($addResult = $tabNamesArray.add($tabEntryArray.get(1).trim()))
    | 18 | + #end
    | 19 | + #end
    | 20 | + #end
    | 21 | +## generate tabs
    | 22 | +
    | 23 | +
    | 24 | +{{html}}
    | 25 | +<div class="floatcontainer">
    | 26 | + <ul class="xwikitabbar">
    | 27 | + #set ($firstIteration=true)
    | 28 | + #foreach($tabId in $tabIdsArray)
    | 29 | + #set($count = $velocityCount - 1)
    | 30 | + #set ($tabName = $tabNamesArray.get($count))
    | 31 | + #if ($firstIteration) #set ($firstIteration=false)
    | 32 | + <li id="${tabId}ListItem" onclick="switchTab('${tabId}', #constructJsStringArray($tabIdsArray));" class="active"><a href="#" onclick="return false;">${tabName}</a></li>
    | 33 | + #else
    | 34 | + <li id="${tabId}ListItem" onclick="switchTab('${tabId}', #constructJsStringArray($tabIdsArray));"><a href="#" onclick="return false;">${tabName}</a></li>
    | 35 | + #end
    | 36 | + #end
    | 37 | + </ul>
    | 38 | +</div>
    | 39 | +## this script is responsible for initial content re-positioning
    | 40 | +<script language="JavaScript">
    | 41 | + ## set convenience variable
    | 42 | + #set ($firstTabId = $tabIdsArray.get(0))
    | 43 | + // approach borrowed from http://www.daniweb.com/forums/thread20256.html#
    | 44 | + var oldFunction${firstTabId} = null;
    | 45 | + function appendedOnLoadFunction() {
    | 46 | + if (oldFunction${firstTabId}) {
    | 47 | + oldFunction${firstTabId}();
    | 48 | + }
    | 49 | + switchTab('${firstTabId}', #constructJsStringArray($tabIdsArray));
    | 50 | + }
    | 51 | + function loadBody() {
    | 52 | + oldFunction${firstTabId} = window.onload;
    | 53 | + window.onload = appendedOnLoadFunction;
    | 54 | + }
    | 55 | + loadBody();
    | 56 | +</script>
    | 57 | +{{/html}}
    | 58 | +## give the array of strings constructs comma-separated list of
    | 59 | +## string values taken into single quotes and square brackets
    | 60 | +## e.g. ['item 1', 'item 2' , 'item 3']
    | 61 | +#macro(constructJsStringArray $stringArray)
    | 62 | +[#foreach($stringElement in $stringArray)'${stringElement}'#if( $velocityHasNext ), #end#end]
    | 63 | +#end
    | 64 | +{{/velocity}}

  Macro content type

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +No content

  Default category

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Content

  Macro description

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Creates tabbed view for content areas wrapped into <div /> with unique id (see macro home for details)

  Macro id

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +tabs

  Macro name

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Tabbed view renderer

  Supports inline mode

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Yes

  Macro visibility

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Current Wiki

XWiki.WikiMacroParameterClass[0]
  Parameter description

    ... | ... | @@ -1,0 +1,2 @@
    | 1 | +Comma-separated list of name=value pairs e.g.
    | 2 | +'sql1key1=Original SQL, sql1key2=Substituted SQL, sql1key3=Resulting SQL'

  Parameter mandatory

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +Yes

  Parameter name

    ... | ... | @@ -1,0 +1,1 @@
    | 1 | +idsToLabels

# Applications

# Tips

Did you know that you can improve XWiki? Take 5 minutes to fill this survey and help this open source project!

# Need help?

If you need help with XWiki you can contact:

- Community Support
- Professional Support