ConfiForms MultiSelect into multiple rows
Asked by Sven B:

Hi,

I have a form, which alows the entry of a multiselect field.  
Something like: \| Key \| Value \| Multi1, 2, 3 \|

I would need this multiselect field in another tableView to be displayed as single rows.

\| Key \| Value \| Multi1 \|  
\| Key \| Value \| Multi2 \|  
\| Key \| Value \| Multi3 \|

Can someone help me out?


Answers:
author: Alex Medved _ConfiForms_
body: Probably you can just use the ConfiForms TableView Merger macro and set the parameter to "flatten entries"

![Screenshot 2019-04-30 at 13.39.17.png](https://community.atlassian.com/t5/image/serverpage/image-id/53063i687E30B5C8BB286B/image-dimensions/334x189?v=v2 "Screenshot 2019-04-30 at 13.39.17.png")

comments: author: Davin Studer
body: Seriously! Um ... yeah, I guess that is way better. I totally forgot about that macro ... I way over engineered it.


author: Davin Studer
body: Not sure there is any easy way to do this with the display of the TableView macro. However, you can set the TableView macro to be able to export. A couple of the options for the export are CSV (flatten) and XLS (flatten). The flatten exports will do exactly what you are asking.

![image.png](https://community.atlassian.com/t5/image/serverpage/image-id/52991i62F3CCC4DF99003C/image-size/large?v=v2&px=999 "image.png")

![image.png](https://community.atlassian.com/t5/image/serverpage/image-id/52992i2A8878EBB1062196/image-size/large?v=v2&px=999 "image.png")

comments: author: Davin Studer
body: After thinking about it a little more I realized that I do have a way to do with combining a user macro I wrote a couple years ago and the method above. Here is the user macro. It will display a CSV that is either attached to a page or accessible via URL as a table on a Confluence page. With the method above you could get the URL for the flattened CSV and then put that URL in the below user macro and it would be displayed on the page as a table. The URL for the flattened CSV would look like this. Change it to fit your setup. Also, see the screenshot for how it would look. The top table is the TableView macro and the bottom is the user macro.

![image.png](https://community.atlassian.com/t5/image/serverpage/image-id/52994i63F2E89246AE4109/image-size/large?v=v2&px=999 "image.png")**CSV User Macro Code**

**Macro Name:**csv_table

**Macro Title:**CSV Table

**Macro Body Processing:**No macro body

**Template:**

```
## Developed by: Davin Studer## Date created: 05/07/2014## @param CSVName:title=CSV File|type=string|required=false|desc=If the CSV is attached to a page use this field.## @param Page:title=Page Title|type=confluence-content|required=false|desc=If not specified, the current page is used.## @param CSVURL:title=CSV URL|type=string|required=false|desc=If the CSV is not attached to a page but is accessible via URL use this field.## @param TopHeader:title=Top Header Row|type=boolean|required=false|default=false|desc=Check if the top row should be a header row?############################################################################# These are used for getting around velocity issues when writing jQuery ##############################################################################set($d = '$')#set($p = '#')#set($error = "")#if($paramCSVName && $paramCSVName != "" && $paramCSVURL && $paramCSVURL)    #set($error = $error + "<p>Use either the CSV File field or the CSV URL field. Not both.</p>")#end################################ Create a unique id value #################################set( $id=$action.dateFormatter.calendar.timeInMillis )#if( $paramPage && $paramPage != "" )    ##########################    ## Get the page manager ##    ##########################    #set( $containerManagerClass=$content.class.forName('com.atlassian.spring.container.ContainerManager') )    #set( $getInstanceMethod=$containerManagerClass.getDeclaredMethod('getInstance',null) )    #set( $containerManager=$getInstanceMethod.invoke(null,null) )    #set( $containerContext=$containerManager.containerContext )    #set( $pageManager=$containerContext.getComponent('pageManager') )    ##########################    ## Find the page        ##    ##########################    #set( $parts = $paramPage.split(":") )    #set( $i = 0 )    #set( $len = 0 )    #set( $key = "" )    #set( $name = "" )    ##Having trouble finding out the length/size of $parts ... brute force it    #foreach( $part in $parts )        #set( $len = $len + 1 )    #end        #if( $len == 1 )        #set( $key = $content.spaceKey )        #set( $name = $paramPage )    #else        #foreach( $part in $parts )            #if( $i == 0 )              #set( $key = $part )              #set( $i = $i + 1 )           #else              #set( $name = $part )           #end        #end    #end    #set( $tempcontent = "" )    #if( $pageManager )        #set( $tempcontent = $pageManager.getPage($key, $name) )    #end    #if( $tempcontent && $tempcontent != "" )        #set( $content = $tempcontent )    #else        The page "$paramPage" was not found in this space.        #set( $content = "" )    #end#end#set( $attachments = $attachmentManager.getLatestVersionsOfAttachments($content) )############################################################################## Could not find a method to sort the $attachments in Alphabetical order #### Must sort them myself ... bubble sort                                  ###############################################################################set( $size = $attachments.size() )#foreach( $junk in $attachments )    #set( $count = -1 )    #foreach( $line in $attachments )        #set( $count = $count + 1 )        #if( $velocityCount < $size )            #if( $line.getTitle().compareToIgnoreCase($attachments.get($velocityCount).getTitle()) > 0 )                #set( $tmp = $attachments.get($velocityCount) )                #set( $junk = $attachments.set($velocityCount, $line) )                #set( $junk = $attachments.set($count, $tmp) )            #end        #end    #end#end#if($paramCSVURL && $paramCSVURL != "")    #set($csvURL = $paramCSVURL)#else    #set( $baseUrl = $action.getGlobalSettings().getBaseUrl() )        #foreach( $attachment in $attachments )        #if( $attachment.getTitle().toLowerCase() == $paramCSVName.toLowerCase() )            #set( $url = $attachment.getDownloadPathWithoutVersion() )        #end    #end    #set($csvURL = ${baseUrl} + ${url})#end########################################################################### This will only run on the macro properties dialog. It will add a    #### dropdown to select a CSV file.                                      ###########################################################################<script type="text/javascript">AJS.toInit(function(){    /////////////////////////////////////////////////    // Are we on the macro properties edit screen? //    /////////////////////////////////////////////////    if(self != top && window.parent.AJS.${d}('${p}macro-browser-preview').length > 0) {        var options = '<option value="">Select a file</option>';        var csvInput = window.parent.AJS.${d}('${p}macro-param-CSVName');        var pageInput = window.parent.AJS.${d}('${p}macro-param-Page');        var refresh = window.parent.AJS.${d}('${p}macro-browser-preview-link');        var secondBlur = false;                //Hide cvsInput ... this will be updated programatically by our new dropdown        csvInput.css('display','none');        //Remove copy input if it exists ... macro preview refresh        window.parent.AJS.${d}('${p}macro-param-CSVName-copy').remove();        //Add copy field        csvInput.before('<select class="select" id="macro-param-CSVName-copy" name="macro-param-CSVName-copy"></select>');        //Reference to new field        var csvInputCopy = window.parent.AJS.${d}('${p}macro-param-CSVName-copy');        //Change original csvInput field when dropdown copy is changed        csvInputCopy.change(function(){            csvInput.val(csvInputCopy.val());        });        //Register change event for page input to populate the attachments for that page        //This focus/blur workaround is because if you select a page from the page hint        //popup the blur and change events won't have the full value right away. They will        //only see what the user typed which may not be the complete page title. So, after 500        //milliseconds we will focus it and then blur it to get the real value. The secondBlur boolean        //is to make sure we only run the blur event on the second time around.        pageInput.change(function(){            secondBlur = false;                        setTimeout(function(){                secondBlur = true;                window.parent.AJS.${d}('${p}macro-param-Page').focus();                window.parent.AJS.${d}('${p}macro-param-Page').blur();            }, 500);        });        pageInput.blur(function(){            if(secondBlur) {                secondBlur = false;                                //Clear csvInput since we are doing a preview refresh to get new dropdown values                csvInput.val('');                //Refresh the preview window which will trigger a fetch of the attachments from the specified page.                refresh.click();            }        });                csvInputCopy.html('');        #foreach( $attachment in $attachments )            #if($attachment.getFileExtension() == "csv")                #if($attachment.getTitle().toLowerCase() == $paramCSVName.toLowerCase())                    #set( $selected = ' selected="selected"' )                #else                    #set( $selected = '' )                #end            options += '<option value="$attachment.getTitle()"$selected>$attachment.getTitle()</option>';            #end        #end        if(options == '<option value="">Select a file</option>') {            csvInput.val('');        }        csvInputCopy.html(options);    }});</script>########################################################################### End                                                                 ####################################################################################################### Render the CSV table #############################if($error && $error != "")    $error#else    #if((${url} && ${url} != "") || ($paramCSVURL && $paramCSVURL != ""))    <script type="text/javascript">    //CSV parser from https://github.com/evanplaice/jquery-csv    RegExp.escape=function(e){return e.replace(/[-\/\\^${d}*+?.()|[\]{}]/g,"\\${d}&")};AJS.${d}.csv={defaults:{separator:",",delimiter:'"',headers:true},hooks:{castToScalar:function(e,t){var n=/\./;if(isNaN(e)){return e}else{if(n.test(e)){return parseFloat(e)}else{var r=parseInt(e);if(isNaN(r)){return null}else{return r}}}}},parsers:{parse:function(e,t){function f(){o=0;u="";if(t.start&&t.state.rowNum<t.start){s=[];t.state.rowNum++;t.state.colNum=1;return}if(t.onParseEntry===undefined){i.push(s)}else{var e=t.onParseEntry(s,t.state);if(e!==false){i.push(e)}}s=[];if(t.end&&t.state.rowNum>=t.end){a=true}t.state.rowNum++;t.state.colNum=1}function l(){if(t.onParseValue===undefined){s.push(u)}else{var e=t.onParseValue(u,t.state);if(e!==false){s.push(e)}}u="";o=0;t.state.colNum++}var n=t.separator;var r=t.delimiter;if(!t.state.rowNum){t.state.rowNum=1}if(!t.state.colNum){t.state.colNum=1}var i=[];var s=[];var o=0;var u="";var a=false;var c=RegExp.escape(n);var h=RegExp.escape(r);var p=/(D|S|\r\n|\n|\r|[^DS\r\n]+)/;var d=p.source;d=d.replace(/S/g,c);d=d.replace(/D/g,h);p=RegExp(d,"gm");e.replace(p,function(e){if(a){return}switch(o){case 0:if(e===n){u+="";l();break}if(e===r){o=1;break}if(/^(\r\n|\n|\r)${d}/.test(e)){l();f();break}u+=e;o=3;break;case 1:if(e===r){o=2;break}u+=e;o=1;break;case 2:if(e===r){u+=e;o=1;break}if(e===n){l();break}if(/^(\r\n|\n|\r)${d}/.test(e)){l();f();break}throw new Error("CSVDataError: Illegal State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");case 3:if(e===n){l();break}if(/^(\r\n|\n|\r)${d}/.test(e)){l();f();break}if(e===r){throw new Error("CSVDataError: Illegal Quote [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}throw new Error("CSVDataError: Illegal Data [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}});if(s.length!==0){l();f()}return i},splitLines:function(e,t){function a(){s=0;if(t.start&&t.state.rowNum<t.start){o="";t.state.rowNum++;return}if(t.onParseEntry===undefined){i.push(o)}else{var e=t.onParseEntry(o,t.state);if(e!==false){i.push(e)}}o="";if(t.end&&t.state.rowNum>=t.end){u=true}t.state.rowNum++}var n=t.separator;var r=t.delimiter;if(!t.state.rowNum){t.state.rowNum=1}var i=[];var s=0;var o="";var u=false;var f=RegExp.escape(n);var l=RegExp.escape(r);var c=/(D|S|\n|\r|[^DS\r\n]+)/;var h=c.source;h=h.replace(/S/g,f);h=h.replace(/D/g,l);c=RegExp(h,"gm");e.replace(c,function(e){if(u){return}switch(s){case 0:if(e===n){o+=e;s=0;break}if(e===r){o+=e;s=1;break}if(e==="\n"){a();break}if(/^\r${d}/.test(e)){break}o+=e;s=3;break;case 1:if(e===r){o+=e;s=2;break}o+=e;s=1;break;case 2:var i=o.substr(o.length-1);if(e===r&&i===r){o+=e;s=1;break}if(e===n){o+=e;s=0;break}if(e==="\n"){a();break}if(e==="\r"){break}throw new Error("CSVDataError: Illegal state [Row:"+t.state.rowNum+"]");case 3:if(e===n){o+=e;s=0;break}if(e==="\n"){a();break}if(e==="\r"){break}if(e===r){throw new Error("CSVDataError: Illegal quote [Row:"+t.state.rowNum+"]")}throw new Error("CSVDataError: Illegal state [Row:"+t.state.rowNum+"]");default:throw new Error("CSVDataError: Unknown state [Row:"+t.state.rowNum+"]")}});if(o!==""){a()}return i},parseEntry:function(e,t){function u(){if(t.onParseValue===undefined){i.push(o)}else{var e=t.onParseValue(o,t.state);if(e!==false){i.push(e)}}o="";s=0;t.state.colNum++}var n=t.separator;var r=t.delimiter;if(!t.state.rowNum){t.state.rowNum=1}if(!t.state.colNum){t.state.colNum=1}var i=[];var s=0;var o="";if(!t.match){var a=RegExp.escape(n);var f=RegExp.escape(r);var l=/(D|S|\n|\r|[^DS\r\n]+)/;var c=l.source;c=c.replace(/S/g,a);c=c.replace(/D/g,f);t.match=RegExp(c,"gm")}e.replace(t.match,function(e){switch(s){case 0:if(e===n){o+="";u();break}if(e===r){s=1;break}if(e==="\n"||e==="\r"){break}o+=e;s=3;break;case 1:if(e===r){s=2;break}o+=e;s=1;break;case 2:if(e===r){o+=e;s=1;break}if(e===n){u();break}if(e==="\n"||e==="\r"){break}throw new Error("CSVDataError: Illegal State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");case 3:if(e===n){u();break}if(e==="\n"||e==="\r"){break}if(e===r){throw new Error("CSVDataError: Illegal Quote [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}throw new Error("CSVDataError: Illegal Data [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}});u();return i}},helpers:{collectPropertyNames:function(e){var t,n,r=[];for(t in e){for(n in e[t]){if(e[t].hasOwnProperty(n)&&r.indexOf(n)<0&&typeof e[t][n]!=="function"){r.push(n)}}}return r}},toArray:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;var i=t.state!==undefined?t.state:{};var t={delimiter:r.delimiter,separator:r.separator,onParseEntry:t.onParseEntry,onParseValue:t.onParseValue,state:i};var s=AJS.${d}.csv.parsers.parseEntry(e,t);if(!r.callback){return s}else{r.callback("",s)}},toArrays:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;var i=[];var t={delimiter:r.delimiter,separator:r.separator,onPreParse:t.onPreParse,onParseEntry:t.onParseEntry,onParseValue:t.onParseValue,onPostParse:t.onPostParse,start:t.start,end:t.end,state:{rowNum:1,colNum:1}};if(t.onPreParse!==undefined){t.onPreParse(e,t.state)}i=AJS.${d}.csv.parsers.parse(e,t);if(t.onPostParse!==undefined){t.onPostParse(i,t.state)}if(!r.callback){return i}else{r.callback("",i)}},toObjects:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;r.headers="headers"in t?t.headers:AJS.${d}.csv.defaults.headers;t.start="start"in t?t.start:1;if(r.headers){t.start++}if(t.end&&r.headers){t.end++}var i=[];var s=[];var t={delimiter:r.delimiter,separator:r.separator,onPreParse:t.onPreParse,onParseEntry:t.onParseEntry,onParseValue:t.onParseValue,onPostParse:t.onPostParse,start:t.start,end:t.end,state:{rowNum:1,colNum:1},match:false,transform:t.transform};var o={delimiter:r.delimiter,separator:r.separator,start:1,end:1,state:{rowNum:1,colNum:1}};if(t.onPreParse!==undefined){t.onPreParse(e,t.state)}var u=AJS.${d}.csv.parsers.splitLines(e,o);var a=AJS.${d}.csv.toArray(u[0],t);var i=AJS.${d}.csv.parsers.splitLines(e,t);t.state.colNum=1;if(a){t.state.rowNum=2}else{t.state.rowNum=1}for(var f=0,l=i.length;f<l;f++){var c=AJS.${d}.csv.toArray(i[f],t);var h={};for(var p in a){h[a[p]]=c[p]}if(t.transform!==undefined){s.push(t.transform.call(undefined,h))}else{s.push(h)}t.state.rowNum++}if(t.onPostParse!==undefined){t.onPostParse(s,t.state)}if(!r.callback){return s}else{r.callback("",s)}},fromArrays:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;var i="",s,o,u,a;for(u=0;u<e.length;u++){s=e[u];o=[];for(a=0;a<s.length;a++){var f=s[a]===undefined||s[a]===null?"":s[a].toString();if(f.indexOf(r.delimiter)>-1){f=f.replace(r.delimiter,r.delimiter+r.delimiter)}var l="\n|\r|S|D";l=l.replace("S",r.separator);l=l.replace("D",r.delimiter);if(f.search(l)>-1){f=r.delimiter+f+r.delimiter}o.push(f)}i+=o.join(r.separator)+"\r\n"}if(!r.callback){return i}else{r.callback("",i)}},fromObjects:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;r.headers="headers"in t?t.headers:AJS.${d}.csv.defaults.headers;r.sortOrder="sortOrder"in t?t.sortOrder:"declare";r.manualOrder="manualOrder"in t?t.manualOrder:[];r.transform=t.transform;if(typeof r.manualOrder==="string"){r.manualOrder=AJS.${d}.csv.toArray(r.manualOrder,r)}if(r.transform!==undefined){var i=e;e=[];var s;for(s=0;s<i.length;s++){e.push(r.transform.call(undefined,i[s]))}}var o=AJS.${d}.csv.helpers.collectPropertyNames(e);if(r.sortOrder==="alpha"){o.sort()}if(r.manualOrder.length>0){var u=[].concat(r.manualOrder);var a;for(a=0;a<o.length;a++){if(u.indexOf(o[a])<0){u.push(o[a])}}o=u}var f,a,l,c=[],h;if(r.headers){c.push(o)}for(f=0;f<e.length;f++){l=[];for(a=0;a<o.length;a++){h=o[a];if(h in e[f]&&typeof e[f][h]!=="function"){l.push(e[f][h])}else{l.push("")}}c.push(l)}return AJS.${d}.csv.fromArrays(c,t,r.callback)}}        AJS.toInit(function(){        AJS.${d}.get("${csvURL}", function( data ) {            var result = AJS.${d}.csv.toArrays(data);            var html = '';            var count = 0;            var topHeader = $paramTopHeader;                for(var row in result) {                                if(count == 0) {                    if(topHeader) {                        html += '<thead>\r\n';                        html += '<tr>\r\n';                        for(var item in result[row]) {                            html += '<th class="confluenceTh">' + result[row][item] + '</th>\r\n';                        }                        html += '</tr>\r\n';                        html += '</thead>\r\n';                        html += '<tbody>\r\n';                    } else {                        html += '<tbody>\r\n';                        html += '<tr>\r\n';                        for(var item in result[row]) {                            html += '<td class="confluenceTd">' + result[row][item] + '</td>\r\n';                        }                        html += '</tr>\r\n';                    }                } else {                    html += '<tr>\r\n';                    for(var item in result[row]) {                        html += '<td class="confluenceTd">' + result[row][item] + '</td>\r\n';                    }                    html += '</tr>\r\n';                }                count++            }            html += '</tbody>\r\n';            AJS.$('#csv-table-$id').html(html);        });    });    </script>    #end    <table id="csv-table-$id" class="confluenceTable tablesorter">    </table>#end
```


author: Davin Studer
body: After thinking about it a bit there is a way to show it as a table on a page. You can get the URL for the flattened CSV file from the method above. It would look like this ...

```
https://{your server}/ajax/confiforms/export.action?t=flatten.csv&pageId={your page id}&fd={your form name}%3A{your page id ... again}&fields={field 1}%2C{field 2}%2C{field 3}%2C{field n+1}&filter=
```

From there you could use a user macro that I wrote a couple of years ago to display the CSV as a table. The user macro code is below. Also there is and example screenshot of what it looks like. The top table is the TableView macro and the bottom table is the flattened CSV version of that table displayed via the user macro.

![image.png](https://community.atlassian.com/t5/image/serverpage/image-id/52995iD4E4C109D1719A8A/image-size/large?v=v2&px=999 "image.png")**CSV Table User Macro Code**

**Macro Name:**csv_table

**Macro Title:**CSV Table

**Macro Body Processing:**No macro body

**Template**

```
## Developed by: Davin Studer## Date created: 05/07/2014## @param CSVName:title=CSV File|type=string|required=false|desc=If the CSV is attached to a page use this field.## @param Page:title=Page Title|type=confluence-content|required=false|desc=If not specified, the current page is used.## @param CSVURL:title=CSV URL|type=string|required=false|desc=If the CSV is not attached to a page but is accessible via URL use this field.## @param TopHeader:title=Top Header Row|type=boolean|required=false|default=false|desc=Check if the top row should be a header row?############################################################################# These are used for getting around velocity issues when writing jQuery ##############################################################################set($d = '$')#set($p = '#')#set($error = "")#if($paramCSVName && $paramCSVName != "" && $paramCSVURL && $paramCSVURL)    #set($error = $error + "<p>Use either the CSV File field or the CSV URL field. Not both.</p>")#end################################ Create a unique id value #################################set( $id=$action.dateFormatter.calendar.timeInMillis )#if( $paramPage && $paramPage != "" )    ##########################    ## Get the page manager ##    ##########################    #set( $containerManagerClass=$content.class.forName('com.atlassian.spring.container.ContainerManager') )    #set( $getInstanceMethod=$containerManagerClass.getDeclaredMethod('getInstance',null) )    #set( $containerManager=$getInstanceMethod.invoke(null,null) )    #set( $containerContext=$containerManager.containerContext )    #set( $pageManager=$containerContext.getComponent('pageManager') )    ##########################    ## Find the page        ##    ##########################    #set( $parts = $paramPage.split(":") )    #set( $i = 0 )    #set( $len = 0 )    #set( $key = "" )    #set( $name = "" )    ##Having trouble finding out the length/size of $parts ... brute force it    #foreach( $part in $parts )        #set( $len = $len + 1 )    #end        #if( $len == 1 )        #set( $key = $content.spaceKey )        #set( $name = $paramPage )    #else        #foreach( $part in $parts )            #if( $i == 0 )              #set( $key = $part )              #set( $i = $i + 1 )           #else              #set( $name = $part )           #end        #end    #end    #set( $tempcontent = "" )    #if( $pageManager )        #set( $tempcontent = $pageManager.getPage($key, $name) )    #end    #if( $tempcontent && $tempcontent != "" )        #set( $content = $tempcontent )    #else        The page "$paramPage" was not found in this space.        #set( $content = "" )    #end#end#set( $attachments = $attachmentManager.getLatestVersionsOfAttachments($content) )############################################################################## Could not find a method to sort the $attachments in Alphabetical order #### Must sort them myself ... bubble sort                                  ###############################################################################set( $size = $attachments.size() )#foreach( $junk in $attachments )    #set( $count = -1 )    #foreach( $line in $attachments )        #set( $count = $count + 1 )        #if( $velocityCount < $size )            #if( $line.getTitle().compareToIgnoreCase($attachments.get($velocityCount).getTitle()) > 0 )                #set( $tmp = $attachments.get($velocityCount) )                #set( $junk = $attachments.set($velocityCount, $line) )                #set( $junk = $attachments.set($count, $tmp) )            #end        #end    #end#end#if($paramCSVURL && $paramCSVURL != "")    #set($csvURL = $paramCSVURL)#else    #set( $baseUrl = $action.getGlobalSettings().getBaseUrl() )        #foreach( $attachment in $attachments )        #if( $attachment.getTitle().toLowerCase() == $paramCSVName.toLowerCase() )            #set( $url = $attachment.getDownloadPathWithoutVersion() )        #end    #end    #set($csvURL = ${baseUrl} + ${url})#end########################################################################### This will only run on the macro properties dialog. It will add a    #### dropdown to select a CSV file.                                      ###########################################################################<script type="text/javascript">AJS.toInit(function(){    /////////////////////////////////////////////////    // Are we on the macro properties edit screen? //    /////////////////////////////////////////////////    if(self != top && window.parent.AJS.${d}('${p}macro-browser-preview').length > 0) {        var options = '<option value="">Select a file</option>';        var csvInput = window.parent.AJS.${d}('${p}macro-param-CSVName');        var pageInput = window.parent.AJS.${d}('${p}macro-param-Page');        var refresh = window.parent.AJS.${d}('${p}macro-browser-preview-link');        var secondBlur = false;                //Hide cvsInput ... this will be updated programatically by our new dropdown        csvInput.css('display','none');        //Remove copy input if it exists ... macro preview refresh        window.parent.AJS.${d}('${p}macro-param-CSVName-copy').remove();        //Add copy field        csvInput.before('<select class="select" id="macro-param-CSVName-copy" name="macro-param-CSVName-copy"></select>');        //Reference to new field        var csvInputCopy = window.parent.AJS.${d}('${p}macro-param-CSVName-copy');        //Change original csvInput field when dropdown copy is changed        csvInputCopy.change(function(){            csvInput.val(csvInputCopy.val());        });        //Register change event for page input to populate the attachments for that page        //This focus/blur workaround is because if you select a page from the page hint        //popup the blur and change events won't have the full value right away. They will        //only see what the user typed which may not be the complete page title. So, after 500        //milliseconds we will focus it and then blur it to get the real value. The secondBlur boolean        //is to make sure we only run the blur event on the second time around.        pageInput.change(function(){            secondBlur = false;                        setTimeout(function(){                secondBlur = true;                window.parent.AJS.${d}('${p}macro-param-Page').focus();                window.parent.AJS.${d}('${p}macro-param-Page').blur();            }, 500);        });        pageInput.blur(function(){            if(secondBlur) {                secondBlur = false;                                //Clear csvInput since we are doing a preview refresh to get new dropdown values                csvInput.val('');                //Refresh the preview window which will trigger a fetch of the attachments from the specified page.                refresh.click();            }        });                csvInputCopy.html('');        #foreach( $attachment in $attachments )            #if($attachment.getFileExtension() == "csv")                #if($attachment.getTitle().toLowerCase() == $paramCSVName.toLowerCase())                    #set( $selected = ' selected="selected"' )                #else                    #set( $selected = '' )                #end            options += '<option value="$attachment.getTitle()"$selected>$attachment.getTitle()</option>';            #end        #end        if(options == '<option value="">Select a file</option>') {            csvInput.val('');        }        csvInputCopy.html(options);    }});</script>########################################################################### End                                                                 ####################################################################################################### Render the CSV table #############################if($error && $error != "")    $error#else    #if((${url} && ${url} != "") || ($paramCSVURL && $paramCSVURL != ""))    <script type="text/javascript">    //CSV parser from https://github.com/evanplaice/jquery-csv    RegExp.escape=function(e){return e.replace(/[-\/\\^${d}*+?.()|[\]{}]/g,"\\${d}&")};AJS.${d}.csv={defaults:{separator:",",delimiter:'"',headers:true},hooks:{castToScalar:function(e,t){var n=/\./;if(isNaN(e)){return e}else{if(n.test(e)){return parseFloat(e)}else{var r=parseInt(e);if(isNaN(r)){return null}else{return r}}}}},parsers:{parse:function(e,t){function f(){o=0;u="";if(t.start&&t.state.rowNum<t.start){s=[];t.state.rowNum++;t.state.colNum=1;return}if(t.onParseEntry===undefined){i.push(s)}else{var e=t.onParseEntry(s,t.state);if(e!==false){i.push(e)}}s=[];if(t.end&&t.state.rowNum>=t.end){a=true}t.state.rowNum++;t.state.colNum=1}function l(){if(t.onParseValue===undefined){s.push(u)}else{var e=t.onParseValue(u,t.state);if(e!==false){s.push(e)}}u="";o=0;t.state.colNum++}var n=t.separator;var r=t.delimiter;if(!t.state.rowNum){t.state.rowNum=1}if(!t.state.colNum){t.state.colNum=1}var i=[];var s=[];var o=0;var u="";var a=false;var c=RegExp.escape(n);var h=RegExp.escape(r);var p=/(D|S|\r\n|\n|\r|[^DS\r\n]+)/;var d=p.source;d=d.replace(/S/g,c);d=d.replace(/D/g,h);p=RegExp(d,"gm");e.replace(p,function(e){if(a){return}switch(o){case 0:if(e===n){u+="";l();break}if(e===r){o=1;break}if(/^(\r\n|\n|\r)${d}/.test(e)){l();f();break}u+=e;o=3;break;case 1:if(e===r){o=2;break}u+=e;o=1;break;case 2:if(e===r){u+=e;o=1;break}if(e===n){l();break}if(/^(\r\n|\n|\r)${d}/.test(e)){l();f();break}throw new Error("CSVDataError: Illegal State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");case 3:if(e===n){l();break}if(/^(\r\n|\n|\r)${d}/.test(e)){l();f();break}if(e===r){throw new Error("CSVDataError: Illegal Quote [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}throw new Error("CSVDataError: Illegal Data [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}});if(s.length!==0){l();f()}return i},splitLines:function(e,t){function a(){s=0;if(t.start&&t.state.rowNum<t.start){o="";t.state.rowNum++;return}if(t.onParseEntry===undefined){i.push(o)}else{var e=t.onParseEntry(o,t.state);if(e!==false){i.push(e)}}o="";if(t.end&&t.state.rowNum>=t.end){u=true}t.state.rowNum++}var n=t.separator;var r=t.delimiter;if(!t.state.rowNum){t.state.rowNum=1}var i=[];var s=0;var o="";var u=false;var f=RegExp.escape(n);var l=RegExp.escape(r);var c=/(D|S|\n|\r|[^DS\r\n]+)/;var h=c.source;h=h.replace(/S/g,f);h=h.replace(/D/g,l);c=RegExp(h,"gm");e.replace(c,function(e){if(u){return}switch(s){case 0:if(e===n){o+=e;s=0;break}if(e===r){o+=e;s=1;break}if(e==="\n"){a();break}if(/^\r${d}/.test(e)){break}o+=e;s=3;break;case 1:if(e===r){o+=e;s=2;break}o+=e;s=1;break;case 2:var i=o.substr(o.length-1);if(e===r&&i===r){o+=e;s=1;break}if(e===n){o+=e;s=0;break}if(e==="\n"){a();break}if(e==="\r"){break}throw new Error("CSVDataError: Illegal state [Row:"+t.state.rowNum+"]");case 3:if(e===n){o+=e;s=0;break}if(e==="\n"){a();break}if(e==="\r"){break}if(e===r){throw new Error("CSVDataError: Illegal quote [Row:"+t.state.rowNum+"]")}throw new Error("CSVDataError: Illegal state [Row:"+t.state.rowNum+"]");default:throw new Error("CSVDataError: Unknown state [Row:"+t.state.rowNum+"]")}});if(o!==""){a()}return i},parseEntry:function(e,t){function u(){if(t.onParseValue===undefined){i.push(o)}else{var e=t.onParseValue(o,t.state);if(e!==false){i.push(e)}}o="";s=0;t.state.colNum++}var n=t.separator;var r=t.delimiter;if(!t.state.rowNum){t.state.rowNum=1}if(!t.state.colNum){t.state.colNum=1}var i=[];var s=0;var o="";if(!t.match){var a=RegExp.escape(n);var f=RegExp.escape(r);var l=/(D|S|\n|\r|[^DS\r\n]+)/;var c=l.source;c=c.replace(/S/g,a);c=c.replace(/D/g,f);t.match=RegExp(c,"gm")}e.replace(t.match,function(e){switch(s){case 0:if(e===n){o+="";u();break}if(e===r){s=1;break}if(e==="\n"||e==="\r"){break}o+=e;s=3;break;case 1:if(e===r){s=2;break}o+=e;s=1;break;case 2:if(e===r){o+=e;s=1;break}if(e===n){u();break}if(e==="\n"||e==="\r"){break}throw new Error("CSVDataError: Illegal State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");case 3:if(e===n){u();break}if(e==="\n"||e==="\r"){break}if(e===r){throw new Error("CSVDataError: Illegal Quote [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}throw new Error("CSVDataError: Illegal Data [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+t.state.rowNum+"][Col:"+t.state.colNum+"]")}});u();return i}},helpers:{collectPropertyNames:function(e){var t,n,r=[];for(t in e){for(n in e[t]){if(e[t].hasOwnProperty(n)&&r.indexOf(n)<0&&typeof e[t][n]!=="function"){r.push(n)}}}return r}},toArray:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;var i=t.state!==undefined?t.state:{};var t={delimiter:r.delimiter,separator:r.separator,onParseEntry:t.onParseEntry,onParseValue:t.onParseValue,state:i};var s=AJS.${d}.csv.parsers.parseEntry(e,t);if(!r.callback){return s}else{r.callback("",s)}},toArrays:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;var i=[];var t={delimiter:r.delimiter,separator:r.separator,onPreParse:t.onPreParse,onParseEntry:t.onParseEntry,onParseValue:t.onParseValue,onPostParse:t.onPostParse,start:t.start,end:t.end,state:{rowNum:1,colNum:1}};if(t.onPreParse!==undefined){t.onPreParse(e,t.state)}i=AJS.${d}.csv.parsers.parse(e,t);if(t.onPostParse!==undefined){t.onPostParse(i,t.state)}if(!r.callback){return i}else{r.callback("",i)}},toObjects:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;r.headers="headers"in t?t.headers:AJS.${d}.csv.defaults.headers;t.start="start"in t?t.start:1;if(r.headers){t.start++}if(t.end&&r.headers){t.end++}var i=[];var s=[];var t={delimiter:r.delimiter,separator:r.separator,onPreParse:t.onPreParse,onParseEntry:t.onParseEntry,onParseValue:t.onParseValue,onPostParse:t.onPostParse,start:t.start,end:t.end,state:{rowNum:1,colNum:1},match:false,transform:t.transform};var o={delimiter:r.delimiter,separator:r.separator,start:1,end:1,state:{rowNum:1,colNum:1}};if(t.onPreParse!==undefined){t.onPreParse(e,t.state)}var u=AJS.${d}.csv.parsers.splitLines(e,o);var a=AJS.${d}.csv.toArray(u[0],t);var i=AJS.${d}.csv.parsers.splitLines(e,t);t.state.colNum=1;if(a){t.state.rowNum=2}else{t.state.rowNum=1}for(var f=0,l=i.length;f<l;f++){var c=AJS.${d}.csv.toArray(i[f],t);var h={};for(var p in a){h[a[p]]=c[p]}if(t.transform!==undefined){s.push(t.transform.call(undefined,h))}else{s.push(h)}t.state.rowNum++}if(t.onPostParse!==undefined){t.onPostParse(s,t.state)}if(!r.callback){return s}else{r.callback("",s)}},fromArrays:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;var i="",s,o,u,a;for(u=0;u<e.length;u++){s=e[u];o=[];for(a=0;a<s.length;a++){var f=s[a]===undefined||s[a]===null?"":s[a].toString();if(f.indexOf(r.delimiter)>-1){f=f.replace(r.delimiter,r.delimiter+r.delimiter)}var l="\n|\r|S|D";l=l.replace("S",r.separator);l=l.replace("D",r.delimiter);if(f.search(l)>-1){f=r.delimiter+f+r.delimiter}o.push(f)}i+=o.join(r.separator)+"\r\n"}if(!r.callback){return i}else{r.callback("",i)}},fromObjects:function(e,t,n){var t=t!==undefined?t:{};var r={};r.callback=n!==undefined&&typeof n==="function"?n:false;r.separator="separator"in t?t.separator:AJS.${d}.csv.defaults.separator;r.delimiter="delimiter"in t?t.delimiter:AJS.${d}.csv.defaults.delimiter;r.headers="headers"in t?t.headers:AJS.${d}.csv.defaults.headers;r.sortOrder="sortOrder"in t?t.sortOrder:"declare";r.manualOrder="manualOrder"in t?t.manualOrder:[];r.transform=t.transform;if(typeof r.manualOrder==="string"){r.manualOrder=AJS.${d}.csv.toArray(r.manualOrder,r)}if(r.transform!==undefined){var i=e;e=[];var s;for(s=0;s<i.length;s++){e.push(r.transform.call(undefined,i[s]))}}var o=AJS.${d}.csv.helpers.collectPropertyNames(e);if(r.sortOrder==="alpha"){o.sort()}if(r.manualOrder.length>0){var u=[].concat(r.manualOrder);var a;for(a=0;a<o.length;a++){if(u.indexOf(o[a])<0){u.push(o[a])}}o=u}var f,a,l,c=[],h;if(r.headers){c.push(o)}for(f=0;f<e.length;f++){l=[];for(a=0;a<o.length;a++){h=o[a];if(h in e[f]&&typeof e[f][h]!=="function"){l.push(e[f][h])}else{l.push("")}}c.push(l)}return AJS.${d}.csv.fromArrays(c,t,r.callback)}}        AJS.toInit(function(){        AJS.${d}.get("${csvURL}", function( data ) {            var result = AJS.${d}.csv.toArrays(data);            var html = '';            var count = 0;            var topHeader = $paramTopHeader;                for(var row in result) {                                if(count == 0) {                    if(topHeader) {                        html += '<thead>\r\n';                        html += '<tr>\r\n';                        for(var item in result[row]) {                            html += '<th class="confluenceTh">' + result[row][item] + '</th>\r\n';                        }                        html += '</tr>\r\n';                        html += '</thead>\r\n';                        html += '<tbody>\r\n';                    } else {                        html += '<tbody>\r\n';                        html += '<tr>\r\n';                        for(var item in result[row]) {                            html += '<td class="confluenceTd">' + result[row][item] + '</td>\r\n';                        }                        html += '</tr>\r\n';                    }                } else {                    html += '<tr>\r\n';                    for(var item in result[row]) {                        html += '<td class="confluenceTd">' + result[row][item] + '</td>\r\n';                    }                    html += '</tr>\r\n';                }                count++            }            html += '</tbody>\r\n';            AJS.$('#csv-table-$id').html(html);        });    });    </script>    #end    <table id="csv-table-$id" class="confluenceTable tablesorter">    </table>#end
```


Tags: confiforms

confluence-server

forms

multi-select

server