Add first pass at XLSX Utilities plugin

Thanks to @stevesunypoly for help with preparing the demo spreadsheet
This commit is contained in:
Jermolene 2016-10-23 22:49:59 +01:00
parent e9470169d8
commit 8de4583d6c
51 changed files with 14201 additions and 0 deletions

View File

@ -9,6 +9,7 @@ type: text/vnd.tiddlywiki
!! New Plugins
* Added [[XLSX Utilities Edition|XLSX Utilities plugin]] for importing Excel-compatible spreadsheets
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/22c1b04ee79a5ccc25cbc33cc91bf5daac1df831]] QR code generator plugin
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/7f11c151f06cd039d1887a6940075237ccb4b7a9]] BibTeX importer plugin

View File

@ -0,0 +1,9 @@
created: 20161023202301847
modified: 20161023202301847
tags: Editions
title: XLSX Utilities Edition
type: text/vnd.tiddlywiki
The ''XLSX Utilities'' edition of TiddlyWiki contains tools to work with `.XLSX` spreadsheets generated by applications like Microsoft Excel and Google Sheets. It can be used in the browser or under Node.js.
http://tiddlywiki.com/editions/xlsx-utils/

View File

@ -0,0 +1,19 @@
{
"description": "Server configuration of the xlsx-utils edition",
"plugins": [
"tiddlywiki/tiddlyweb",
"tiddlywiki/filesystem",
"tiddlywiki/jszip",
"tiddlywiki/xlsx-utils"
],
"themes": [
"tiddlywiki/vanilla",
"tiddlywiki/snowwhite"
],
"includeWikis": [
"../xlsx-utils"
],
"config": {
"default-tiddler-location": "../xlsx-utils/tiddlers"
}
}

View File

@ -0,0 +1,5 @@
title: $:/DefaultTiddlers
[[HelloThere]]
[[$:/plugins/tiddlywiki/xlsx-utils]]
[[Presidents Demo]]

View File

@ -0,0 +1,9 @@
title: HelloThere
This is a demo of the ''xlsx-utils'' plugin for TiddlyWiki.
{{$:/plugins/tiddlywiki/xlsx-utils/readme}}
!! Demos
* [[Presidents Demo]]

View File

@ -0,0 +1,6 @@
title: $:/_Macros
tags: $:/tags/Macro
\define download-xlsx-tiddler(title,caption)
<a href={{{ [[data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,]addsuffix{$title$}] }}} download="$title$">$caption$</a>
\end

View File

@ -0,0 +1,27 @@
title: Presidents Demo
\define tv-config-toolbar-icons() yes
\define tv-config-toolbar-text() yes
# Visit the ''XLSX Utilities'' tab of control panel and ensure the current import specification is set to ''Presidents and Justices demo''
# Download the demo spreadsheet: <<download-xlsx-tiddler "Presidents and Justices.xlsx" "Presidents and Justices.xlsx">>
# Explore the contents of the file to understand the data and how it is structured
# Import the spreadsheet back into TiddlyWiki
#* Use the {{$:/core/ui/Buttons/import}} button here or in the ''Tools'' sidebar tab --or--
#* Drag and drop the file into the browser
# Click the ''import'' button on the $:/Import tiddler
# Explore the imported data using the table of contents below
# Explore the ''Presidents and Justices demo'' import specification to see how the spreadsheet data was converted into tiddlers
! Output
<$list filter="[role[president]limit[1]]" emptyMessage="""
//Follow the instructions above and the results will appear here//
""">
</$list>
<div class="tc-table-of-contents">
<<toc-selective-expandable 'States'>>
</div>

View File

@ -0,0 +1,3 @@
title: $:/SiteSubtitle
a demo of the XLSX utilities plugin for TiddlyWiki

View File

@ -0,0 +1,3 @@
title: $:/SiteTitle
xlsx-utils

View File

@ -0,0 +1,6 @@
created: 20161021164330811
modified: 20161021164331841
title: $:/config/plugins/tiddlywiki/xlsx-utils/default-import-spec
type: text/vnd.tiddlywiki
$:/_importspec/Presidents and Justices/

View File

@ -0,0 +1,2 @@
title: $:/state/plugin-info--1909267488-$:/plugins/tiddlywiki/xlsx-utils---1477676357
text: controls

View File

@ -0,0 +1,10 @@
created: 20161021165241843
import-field-column: Description
import-field-name: text
import-field-source: column
import-field-type: string
import-spec-role: field
modified: 20161023172126055
title: $:/_importspec/Presidents and Justices/Justices/Main/modified
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021165214228
import-field-name: role
import-field-source: constant
import-field-value: justice
import-spec-role: field
modified: 20161023172127108
title: $:/_importspec/Presidents and Justices/Justices/Main/role
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,11 @@
created: 20161009181413650
import-field-column: President
import-field-list-op: append
import-field-name: tags
import-field-source: column
import-field-type: string
import-spec-role: field
modified: 20161023172128142
title: $:/_importspec/Presidents and Justices/Justices/Main/tags
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021165211404
import-field-column: Justice
import-field-name: title
import-field-source: column
import-spec-role: field
modified: 20161023172125012
title: $:/_importspec/Presidents and Justices/Justices/Main/title
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,10 @@
created: 20161021165829079
import-field-column: Trivial Facts
import-field-name: trivia
import-field-source: column
import-field-type: string
import-spec-role: field
modified: 20161023172129150
title: $:/_importspec/Presidents and Justices/Justices/Main/trivia
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,10 @@
created: 20161021164844363
import-field-column: State
import-field-list-op: append
import-field-name: tags
import-field-source: column
import-spec-role: field
modified: 20161023172106663
title: $:/_importspec/Presidents and Justices/Presidents/Main/parent
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164839163
import-field-name: role
import-field-source: constant
import-field-value: president
import-spec-role: field
modified: 20161023172105656
title: $:/_importspec/Presidents and Justices/Presidents/Main/role
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161023172104652
import-field-column: Description
import-field-name: text
import-field-source: column
import-spec-role: field
modified: 20161023172104652
title: $:/_importspec/Presidents and Justices/Presidents/Main/text
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164831260
import-field-column: President
import-field-name: title
import-field-source: column
import-spec-role: field
modified: 20161023172103626
title: $:/_importspec/Presidents and Justices/Presidents/Main/title
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164652535
import-field-name: role
import-field-source: constant
import-field-value: state
import-spec-role: field
modified: 20161023172038126
title: $:/_importspec/Presidents and Justices/States/Main/role
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,12 @@
created: 20161021171230908
import-field-column: Column Name
import-field-list-op: append
import-field-name: tags
import-field-source: constant
import-field-type: string
import-field-value: States
import-spec-role: field
modified: 20161023172043708
title: $:/_importspec/Presidents and Justices/States/Main/tags
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161023172033792
import-field-column: Description
import-field-name: text
import-field-source: column
import-spec-role: field
modified: 20161023172033792
title: $:/_importspec/Presidents and Justices/States/Main/text
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164642751
import-field-column: State
import-field-name: title
import-field-source: column
import-spec-role: field
modified: 20161023172029372
title: $:/_importspec/Presidents and Justices/States/Main/title
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,8 @@
created: 20161009181413651
import-spec-role: row
list: [[$:/_importspec/Presidents and Justices/Justices/Main/title]] [[$:/_importspec/Presidents and Justices/Justices/Main/modified]] [[$:/_importspec/Presidents and Justices/Justices/Main/role]] [[$:/_importspec/Presidents and Justices/Justices/Main/tags]] [[$:/_importspec/Presidents and Justices/Justices/Main/trivia]]
modified: 20161023172129146
tags:
title: $:/_importspec/Presidents and Justices/Justices/Main
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,8 @@
created: 20161021164852566
import-spec-role: row
list: [[$:/_importspec/Presidents and Justices/Presidents/Main/title]] [[$:/_importspec/Presidents and Justices/Presidents/Main/text]] [[$:/_importspec/Presidents and Justices/Presidents/Main/role]] [[$:/_importspec/Presidents and Justices/Presidents/Main/parent]]
modified: 20161023172106661
tags:
title: $:/_importspec/Presidents and Justices/Presidents/Main
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,8 @@
created: 20161021164655367
import-spec-role: row
list: [[$:/_importspec/Presidents and Justices/States/Main/title]] [[$:/_importspec/Presidents and Justices/States/Main/text]] [[$:/_importspec/Presidents and Justices/States/Main/role]] [[$:/_importspec/Presidents and Justices/States/Main/tags]]
modified: 20161023172043705
tags:
title: $:/_importspec/Presidents and Justices/States/Main
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164943746
import-sheet-name: Justices
import-spec-role: sheet
list: [[$:/_importspec/Presidents and Justices/Justices/Main]]
modified: 20161021165827475
tags:
title: $:/_importspec/Presidents and Justices/Justices
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164721439
import-sheet-name: Presidents
import-spec-role: sheet
list: [[$:/_importspec/Presidents and Justices/Presidents/Main]]
modified: 20161021164903102
tags:
title: $:/_importspec/Presidents and Justices/Presidents
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
created: 20161021164354030
import-sheet-name: States
import-spec-role: sheet
list: [[$:/_importspec/Presidents and Justices/States/Main]]
modified: 20161021164745886
tags:
title: $:/_importspec/Presidents and Justices/States
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,9 @@
caption: Presidents and Justices demo
created: 20161021163735946
import-spec-role: workbook
list: [[$:/_importspec/Presidents and Justices/States]] [[$:/_importspec/Presidents and Justices/Presidents]] [[$:/_importspec/Presidents and Justices/Justices]]
modified: 20161021164938592
tags:
title: $:/_importspec/Presidents and Justices/
type: text/vnd.tiddlywiki

View File

@ -0,0 +1,2 @@
title: Presidents and Justices.xlsx
type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

View File

@ -0,0 +1,17 @@
{
"description": "Demo of the XLSX utilities plugin",
"plugins": [
"tiddlywiki/jszip",
"tiddlywiki/xlsx-utils"
],
"themes": [
"tiddlywiki/vanilla",
"tiddlywiki/snowwhite"
],
"includeWikis": [
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","index.html","text/plain"]
}
}

View File

@ -0,0 +1,365 @@
title: $:/plugins/tiddlywiki/xlsx-utils/controls
caption: XLSX Utilities
tags: $:/tags/ControlPanel
\define help-button(state)
<$button popup="""$:/state/expand-help/$state$""" class="tc-btn-invisible tc-popup-keep">
{{$:/core/images/help}}
</$button>
\end
\define help-content(type,state)
<$reveal tag="span" state="""$:/state/expand-help/$state$""" type="popup" position="below">
<div class="tc-drop-down tc-popup-keep" style="padding: 0.5em; max-width: 30em; white-space: normal;">
<$transclude tiddler="""$:/plugins/tiddlywiki/xlsx-utils/docs/$type$""" mode="block"/>
</div>
</$reveal>
\end
\define renameProxyTitle()
$:/state/plugins/tiddlywiki/xlsx-utils/rename-$(currentTiddler)$
\end
\define rename-current-tiddler()
<$edit-text tag="input" tiddler=<<renameProxyTitle>> placeholder="Rename" default=<<currentTiddler>> size="50"/>
<$reveal type="nomatch" state="""$(renameProxyTitle)$""" text=<<currentTiddler>> default=<<currentTiddler>> tag="span">
<$button>
<$action-deletetiddler $tiddler=<<renameProxyTitle>>/>
cancel
</$button>
<$button>
<$action-sendmessage $message="tm-rename-tiddler" from=<<currentTiddler>> to={{$(renameProxyTitle)$}}/>
<$action-deletetiddler $tiddler=<<renameProxyTitle>>/>
rename
</$button>
<$set name="proxy-title" value={{$(renameProxyTitle)$}}>
<$list filter="""[<proxy-title>is[tiddler]]""">
Warning: tiddler already exists
</$list>
</$set>
</$reveal>
\end
\define expand-collapse-button(state)
<$reveal state="""$:/state/expand/$state$""" type="match" text="yes" default="no" tag="span">
<$button class="tc-btn-invisible">
<$action-setfield $tiddler="""$:/state/expand/$state$""" $value="no"/>
{{$:/core/images/down-arrow}}
</$button>
</$reveal>
<$reveal state="""$:/state/expand/$state$""" type="nomatch" text="yes" default="no" tag="span">
<$button class="tc-btn-invisible">
<$action-setfield $tiddler="""$:/state/expand/$state$""" $value="yes"/>
{{$:/core/images/right-arrow}}
</$button>
</$reveal>
\end
\define expand-collapse-content(state,content,class)
<$reveal state="""$:/state/expand/$state$""" type="match" text="yes" default="no" tag="div" class="""$class$""" animate="yes" retain="yes">
$content$
</$reveal>
\end
\define up-down-buttons(parent,child)
<$list filter="[list<$parent$>butfirst[]field:title<$child$>limit[1]]" variable="listItem">
<$button class="tc-btn-invisible">
<$action-listops $tiddler=<<$parent$>> $subfilter="+[move:-1<$child$>]"/>
{{$:/core/images/chevron-up}}
</$button>
</$list>
<$list filter="[list<$parent$>butlast[]field:title<$child$>limit[1]]" variable="listItem">
<$button class="tc-btn-invisible">
<$action-listops $tiddler=<<$parent$>> $subfilter="+[move:1<$child$>]"/>
{{$:/core/images/chevron-down}}
</$button>
</$list>
\end
\define edit-button(state)
<$reveal state="""$:/state/edit/$state$""" type="nomatch" text="yes" default="no" tag="span">
<$button class="tc-btn-invisible">
<$action-setfield $tiddler="""$:/state/edit/$state$""" $value="yes"/>
<$action-setfield $tiddler="""$:/state/expand/$state$""" $value="yes"/>
{{$:/core/images/edit-button}}
</$button>
</$reveal>
<$reveal state="""$:/state/edit/$state$""" type="match" text="yes" default="no" tag="span">
<$button class="tc-btn-invisible">
<$action-setfield $tiddler="""$:/state/edit/$state$""" $value="no"/>
{{$:/core/images/done-button}} Finish editing
</$button>
</$reveal>
\end
\define delete-item-button(filter,parent,title,prompt)
<$button class="tc-btn-invisible">
<$action-deletetiddler $filter="""$filter$"""/>
<$action-listops $tiddler="""$parent$""" $subfilter="-[[$title$]]"/>
{{$:/core/images/delete-button}}$prompt$
</$button>
\end
\define edit-field()
<$select tiddler=<<field>> field="import-field-list-op" default="none">
<option value="none">Set field</option>
<option value="append">Append to list field</option>
</$select>
<$edit-text tiddler=<<field>> field="import-field-name" size="10" tag="input" placeholder="field name"default=""/>
<$reveal state="""$(field)$!!import-field-list-op""" type="match" text="none" default="none" tag="span">
to
</$reveal>
<$reveal state="""$(field)$!!import-field-list-op""" type="match" text="append" default="none" tag="span">
the
</$reveal>
<$select tiddler=<<field>> field="import-field-type" default="string">
<option value="date">date</option>
<option value="string">string</option>
</$select>
<$select tiddler=<<field>> field="import-field-source" default="column">
<option value="column">from column</option>
<option value="constant">constant</option>
</$select>
<$reveal state="""$(field)$!!import-field-source""" type="match" text="column" default="column" tag="span">
<$edit-text tiddler=<<field>> field="import-field-column" tag="input" placeholder="column" default=""/>
prefixed
<$edit-text tiddler=<<field>> field="import-field-prefix" tag="input" placeholder="prefix" default=""/>,
suffixed
<$edit-text tiddler=<<field>> field="import-field-suffix" tag="input" placeholder="suffix" default=""/>
</$reveal>
<$reveal state="""$(field)$!!import-field-source""" type="match" text="constant" default="column" tag="span">
<$edit-text tiddler=<<field>> field="import-field-value" tag="input" placeholder="constant" default=""/>
</$reveal>
<br/>
Title:
<$tiddler tiddler=<<field>>>
<<rename-current-tiddler>>
</$tiddler>
\end
\define view-field()
<$link to=<<field>>>
<$list filter="[<field>!has[import-field-list-op]]" variable="listItem">
Set field ''<$view tiddler=<<field>> field="import-field-name"/>'' to
</$list>
<$list filter="[<field>get[import-field-list-op]prefix[append]]" variable="listItem">
Append to list field ''<$view tiddler=<<field>> field="import-field-name"/>''
</$list>
<$list filter="[<field>has[import-field-prefix]]" variable="listItem">
''<code><$view tiddler=<<field>> field="import-field-prefix"/></code>'' +
</$list>
<$list filter="[<field>get[import-field-type]prefix[date]]" variable="listItem">
date
</$list>
<$list filter="[<field>get[import-field-source]prefix[column]]" variable="listItem">
value from column ''<$view tiddler=<<field>> field="import-field-column"/>''
</$list>
<$list filter="[<field>get[import-field-source]prefix[constant]]" variable="listItem">
constant ''<code><$view tiddler=<<field>> field="import-field-value"/></code>''
</$list>
<$list filter="[<field>has[import-field-suffix]]" variable="listItem">
+ ''<code><$view tiddler=<<field>> field="import-field-suffix"/></code>''
</$list>
</$link>
\end
\define list-fields()
<ul class="tc-import-spec-row-list">
<$list filter="[list<row>]" variable="field" emptyMessage="<div>(No field import specifiers)</div>">
<li class="tc-import-spec-field-wrapper">
<$reveal state="""$:/state/edit/$(row)$""" type="match" text="yes" default="no" tag="span">
<<edit-field>>
<<up-down-buttons parent:"row" child:"field">>
<$macrocall $name="delete-item-button" filter="[<field>]" parent=<<row>> title=<<field>>/>
</$reveal>
<$reveal state="""$:/state/edit/$(row)$""" type="nomatch" text="yes" default="no" tag="span">
<<view-field>>
</$reveal>
</li>
</$list>
</ul>
\end
\define view-row-content()
<$reveal state="""$:/state/edit/$(row)$""" type="match" text="yes" default="no" tag="ul" class="tc-import-spec-row-controls" animate="yes" retain="yes">
<li>
<$macrocall $name="delete-item-button" filter="[<row>] [<row>getlist[]]" parent=<<sheet>> title=<<row>> prompt=" Delete this row"/>
</li>
<li>
Title:
<$tiddler tiddler=<<row>>>
<<rename-current-tiddler>>
</$tiddler>
</li>
<li>
<$button class="tc-btn-invisible">
<$action-createtiddler $basetitle="$:/_ExcelImporter/ImportSpecifiers/Field" $savetitle="$:/temp/newtiddler" import-spec-role="field" import-field-name="fieldname" import-field-type="string" import-field-source="column" import-field-column="Column Name" />
<$action-listops $tiddler=<<row>> $subfilter="[{$:/temp/newtiddler}]"/>
{{$:/core/images/new-button}} Add new field
</$button>
</li>
</$reveal>
<<list-fields>>
\end
\define view-row()
<div class="tc-import-spec-row-wrapper">
<h5>
<$macrocall $name="expand-collapse-button" state=<<row>>/>
Each row: <$list filter="[list<row>import-field-name[title]]" variable="field" emptyMessage="
<$link to=<<field>>>(title field not set)</$link>"><<view-field>></$list>
<$macrocall $name="edit-button" state=<<row>>/>
<<up-down-buttons parent:"sheet" child:"row">>
<$macrocall $name="help-button" state=<<row>>/>
</h5>
<$macrocall $name="help-content" type="row" state=<<row>>/>
<$macrocall $name="expand-collapse-content" state=<<row>> content=<<view-row-content>> class="tc-import-spec-row"/>
</div>
\end
\define list-rows()
<div class="tc-import-spec-sheet-list">
<$list filter="[list<sheet>]" variable="row" emptyMessage="<div>(No row import specifiers)</div>">
<<view-row>>
</$list>
\end
\define view-sheet-content()
<$reveal state="""$:/state/edit/$(sheet)$""" type="match" text="yes" default="no" tag="ul" class="tc-import-spec-sheet-controls" animate="yes" retain="yes">
<li>
<$macrocall $name="delete-item-button" filter="[<sheet>] [<sheet>getlist[]] [<sheet>getlist[]getlist[]]" parent=<<workbook>> title=<<sheet>> prompt=" Delete this sheet"/>
</li>
<li>
Title:
<$tiddler tiddler=<<sheet>>>
<<rename-current-tiddler>>
</$tiddler>
</li>
<li>
Import sheet name:
<$edit-text tiddler=<<sheet>> field="import-sheet-name" size="50"/>
</li>
<li>
<$button class="tc-btn-invisible">
<$action-createtiddler $basetitle="$:/_ExcelImporter/ImportSpecifiers/Row" $savetitle="$:/temp/newtiddler" import-spec-role="row"/>
<$action-listops $tiddler=<<sheet>> $subfilter="[{$:/temp/newtiddler}]"/>
<$action-setfield $tiddler={{{ [{$:/temp/newtiddler}addprefix[$:/state/edit/]] }}} $value="yes"/>
<$action-setfield $tiddler={{{ [{$:/temp/newtiddler}addprefix[$:/state/expand/]] }}} $value="yes"/>
{{$:/core/images/new-button}} Add new row
</$button>
</li>
</$reveal>
<<list-rows>>
\end
\define view-sheet()
<div class="tc-import-spec-sheet-wrapper">
<h4>
<$macrocall $name="expand-collapse-button" state=<<sheet>>/>
Sheet: <$link to=<<sheet>>><$view tiddler=<<sheet>> field="import-sheet-name"/></$link>
<$macrocall $name="edit-button" state=<<sheet>>/>
<<up-down-buttons parent:"workbook" child:"sheet">>
<$macrocall $name="help-button" state=<<sheet>>/>
</h4>
<$macrocall $name="help-content" type="sheet" state=<<sheet>>/>
<$macrocall $name="expand-collapse-content" state=<<sheet>> content=<<view-sheet-content>> class="tc-import-spec-sheet"/>
</div>
\end
\define list-sheets()
<div class="tc-import-spec-workbook-list">
<$list filter="[list<workbook>]" variable="sheet" emptyMessage="<div>(No sheet import specifiers)</div>">
<<view-sheet>>
</$list>
</div>
\end
\define view-workbook-content()
<$reveal state="""$:/state/edit/$(workbook)$""" type="match" text="yes" default="no" tag="ul" class="tc-import-spec-workbook-controls" animate="yes" retain="yes">
<li>
<$macrocall $name="delete-item-button" filter="[<workbook>] [<workbook>getlist[]] [<workbook>getlist[]getlist[]] [<workbook>getlist[]getlist[]getlist[]]" prompt=" Delete this workbook"/>
</li>
<li>
Title:
<$tiddler tiddler=<<workbook>>>
<<rename-current-tiddler>>
</$tiddler>
</li>
<li>
Caption:
<$edit-text tiddler=<<workbook>> field="caption" size="50"/>
</li>
<li>
<$button class="tc-btn-invisible">
<$action-createtiddler $basetitle="$:/_ExcelImporter/ImportSpecifiers/Sheet" $savetitle="$:/temp/newtiddler" import-spec-role="sheet" import-sheet-name="Sheet name"/>
<$action-listops $tiddler=<<workbook>> $subfilter="[{$:/temp/newtiddler}]"/>
<$action-setfield $tiddler={{{ [{$:/temp/newtiddler}addprefix[$:/state/edit/]] }}} $value="yes"/>
<$action-setfield $tiddler={{{ [{$:/temp/newtiddler}addprefix[$:/state/expand/]] }}} $value="yes"/>
{{$:/core/images/new-button}} Add new sheet
</$button>
</li>
</$reveal>
<<list-sheets>>
\end
\define view-workbook()
<div class="tc-import-spec-workbook-wrapper">
<h3>
<$macrocall $name="expand-collapse-button" state=<<workbook>>/>
Workbook: <$link to=<<workbook>>><$view tiddler=<<workbook>> field="caption"/></$link>
<$macrocall $name="edit-button" state=<<workbook>>/>
<$macrocall $name="help-button" state=<<workbook>>/>
</h3>
<$macrocall $name="help-content" type="workbook" state=<<workbook>>/>
<$macrocall $name="expand-collapse-content" state=<<workbook>> content=<<view-workbook-content>> class="tc-import-spec-workbook"/>
</div>
\end
\define list-workbooks()
<ul class="tc-import-spec-editor-controls">
<li>
<$button class="tc-btn-invisible">
<$action-createtiddler $basetitle="$:/_ExcelImporter/ImportSpecifiers/Workbook" $savetitle="$:/temp/newtiddler" import-spec-role="workbook" caption="New workbook"/>
<$action-setfield $tiddler={{{ [{$:/temp/newtiddler}addprefix[$:/state/edit/]] }}} $value="yes"/>
<$action-setfield $tiddler={{{ [{$:/temp/newtiddler}addprefix[$:/state/expand/]] }}} $value="yes"/>
{{$:/core/images/new-button}} Add new workbook
</$button>
</li>
</ul>
<div class="tc-import-spec-editor-list">
<$list filter="[all[shadows+tiddlers]import-spec-role[workbook]sort[caption]]" variable="workbook">
<<view-workbook>>
</$list>
</div>
\end
<h1>
Controls for XLSX Spreadsheet Utilities
</h1>
<div class="tc-import-spec-selector">
<h2>
Current Import Specification
</h2>
<$list filter="[all[shadows+tiddlers]import-spec-role[workbook]limit[1]]" emptyMessage="""
There are no import specifications available. Use the controls below to create one
""">
This is the import specification that will be used for the next import of an `.XLSX` file
<$select tiddler="$:/config/plugins/tiddlywiki/xlsx-utils/default-import-spec">
<$list filter="[all[shadows+tiddlers]import-spec-role[workbook]sort[caption]]">
<option value=<<currentTiddler>>><$text text={{!!caption}}/></option>
</$list>
</$select>
</$list>
</div>
<div class="tc-import-spec-editor-wrapper">
<h2>
Import Specifications
<$macrocall $name="help-button" state=""/>
</h2>
<$macrocall $name="help-content" type="editor" state=""/>
<div class="tc-import-spec-editor">
<<list-workbooks>>
</div>
</div>

View File

@ -0,0 +1,29 @@
/*\
title: $:/plugins/tiddlywiki/xlsx-utils/deserializer.js
type: application/javascript
module-type: tiddlerdeserializer
XLSX file deserializer
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Parse an XLSX file into tiddlers
*/
exports["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = function(text,fields) {
// Collect output tiddlers in an array
var results = [],
XLSXImporter = require("$:/plugins/tiddlywiki/xlsx-utils/importer.js").XLSXImporter,
importer = new XLSXImporter({
text: text
});
// Return the output tiddlers
return importer.importTiddlers();
};
})();

View File

@ -0,0 +1,7 @@
title: $:/plugins/tiddlywiki/xlsx-utils/docs/editor
!!! Import Specifications
Import specifications govern how spreadsheets are converted into individual tiddlers.
Each "workbook" describes how spreadsheets of a particular format should be converted.

View File

@ -0,0 +1,20 @@
title: $:/plugins/tiddlywiki/xlsx-utils/docs/row
!!! Row Import Specifications
Each row import specification describes how one tiddler should be extracted from each row of the current sheet.
Note that using multiple row import specifications within a sheet enables multiple tiddlers to be created from each row of the sheet.
Rows contain a list of field import specifications that describe how each field of the tiddler should be created.
!!! Field Import Specifications
Field import specifications describe the value given to a particular field of a tiddler.
They follow a rich syntax for describing how each field of the tiddler is created. For example:
* Set field `title` to string from column `Organization`
* Set field `role` to string constant `organization`
* Append to list field `list` the string from column `Country` prefixed with `Map:`

View File

@ -0,0 +1,11 @@
title: $:/plugins/tiddlywiki/xlsx-utils/docs/sheet
!!! Sheet Import Specifications
Each sheet import specification describes how a named sheet within a workbook should be converted into individual tiddlers.
Sheets contain a list of row import specifications that describe how individual rows of the sheet should be handled.
Each sheet has the name of the sheet that it handles.
Note that the first row of each sheet is interpreted as the title of each column.

View File

@ -0,0 +1,11 @@
title: $:/plugins/tiddlywiki/xlsx-utils/docs/workbook
!!! Workbook Import Specifications
Each workbook import specification describes how spreadsheets of a particular format should be converted into individual tiddlers.
Create a new workbook for each type of spreadsheet that you will be working with.
Workbooks contain a list of sheet import specifications that describe how individual sheets of the workbook should be handled.
Each workbook has a caption that you can use to describe its purpose.

View File

@ -0,0 +1,17 @@
Copyright (C) 2012-2015 SheetJS
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Except where noted, this license applies to any and all software programs and associated documentation files created by the Original Author and distributed with the Software:
'jszip.js' is a modified version of JSZip, Copyright (c) Stuart Knightley, David Duponchel, Franz Buchinger, Ant'onio Afonso. JSZip is dual licensed and is used according to the terms of the MIT License.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
{
"tiddlers": [
{
"file": "xlsx.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/xlsx-utils/xlsx.js",
"module-type": "library"
},
"prefix": "var old_exports = exports,JSZip = require(\"$:/plugins/tiddlywiki/jszip/jszip.js\");exports = {};if($tw.browser){module.exports=undefined;};",
"suffix": "$tw.utils.extend(old_exports,exports);exports = old_exports;module.exports=exports;"
},{
"file": "cpexcel.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/xlsx-utils/dist/cpexcel.js",
"module-type": "library"
},
"prefix": "if($tw.browser){Buffer = undefined;};",
"suffix": ""
},{
"file": "LICENSE",
"fields": {
"type": "text/plain",
"title": "$:/plugins/tiddlywiki/xlsx-utils/license"
}
}
]
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,11 @@
title: $:/language/Help/xlsx-import
description: Import tiddlers from an XLSX spreadsheet file
Imports tiddlers from an XLSX spreadsheet file
```
--xlsx-import <filename> <importSpec>
```
* ''filename'': filename of the `.xlsx` file
* ''title'': title of the import specification tiddler to be used for the import

View File

@ -0,0 +1,148 @@
/*\
title: $:/plugins/tiddlywiki/xlsx-utils/importer.js
type: application/javascript
module-type: library
Class to import an Excel file
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var DEFAULT_IMPORT_SPEC_TITLE = "$:/config/plugins/tiddlywiki/xlsx-utils/default-import-spec";
var XLSX = require("$:/plugins/tiddlywiki/xlsx-utils/xlsx.js"),
JSZip = require("$:/plugins/tiddlywiki/jszip/jszip.js");
var XLSXImporter = function(options) {
this.filename = options.filename;
this.text = options.text;
this.importSpec = options.importSpec || $tw.wiki.getTiddlerText(DEFAULT_IMPORT_SPEC_TITLE);
};
XLSXImporter.prototype.importTiddlers = function() {
var self = this,
results = [],
workbook;
// Check for the JSZIP plugin
if(!JSZip) {
return results;
}
// Read the workbook
if(this.filename) {
workbook = XLSX.readFile(this.filename);
} else if(this.text) {
workbook = XLSX.read(this.text,{type:"base64"});
}
// Read the root import specification
var rootImportSpec = $tw.wiki.getTiddler(this.importSpec);
if(rootImportSpec) {
// Iterate through the sheets specified in the list field
$tw.utils.each(rootImportSpec.fields.list || [],function(sheetImportSpecTitle) {
// Get the sheet import specifier
var sheetImportSpec = $tw.wiki.getTiddler(sheetImportSpecTitle);
if(sheetImportSpec) {
var sheetName = sheetImportSpec.fields["import-sheet-name"],
sheet = workbook.Sheets[sheetName];
// Get the size of the sheet
var sheetSize = self.measureSheet(sheet);
// Read the column names from the first row
var columnsByName = self.findColumns(sheet,sheetSize);
// Iterate through the rows
for(var row=sheetSize.startRow+1; row<=sheetSize.endRow; row++) {
// Iterate through the row import specifiers
$tw.utils.each(sheetImportSpec.fields.list || [],function(rowImportSpecTitle) {
var rowImportSpec = $tw.wiki.getTiddler(rowImportSpecTitle);
if(rowImportSpec) {
var tiddlerFields = {};
// Iterate through the fields for the row
$tw.utils.each(rowImportSpec.fields.list || [],function(fieldImportSpecTitle) {
var fieldImportSpec = $tw.wiki.getTiddler(fieldImportSpecTitle);
if(fieldImportSpec) {
var fieldName = fieldImportSpec.fields["import-field-name"],
value;
switch(fieldImportSpec.fields["import-field-source"]) {
case "column":
var columnName = fieldImportSpec.fields["import-field-column"],
cell = sheet[XLSX.utils.encode_cell({c: columnsByName[columnName], r: row})];
if(cell) {
switch(fieldImportSpec.fields["import-field-type"] || "string") {
case "date":
if(cell.t === "n") {
value = $tw.utils.stringifyDate(new Date((cell.v - (25567 + 2)) * 86400 * 1000));
}
break;
case "string":
// Intentional fall-through
default:
value = cell.w;
break;
}
}
break;
case "constant":
value = fieldImportSpec.fields["import-field-value"]
break;
}
if(fieldImportSpec.fields["import-field-prefix"]) {
value = fieldImportSpec.fields["import-field-prefix"] + value;
}
if(fieldImportSpec.fields["import-field-suffix"]) {
value = value + fieldImportSpec.fields["import-field-suffix"];
}
if(fieldImportSpec.fields["import-field-replace-blank"] && (value || "").trim() === "") {
value = fieldImportSpec.fields["import-field-replace-blank"];
}
switch(fieldImportSpec.fields["import-field-list-op"] || "none") {
case "none":
tiddlerFields[fieldName] = value;
break;
case "append":
var list = $tw.utils.parseStringArray(tiddlerFields[fieldName] || "");
$tw.utils.pushTop(list,value)
tiddlerFields[fieldName] = list;
break;
}
}
});
results.push(tiddlerFields);
}
});
}
}
});
}
return results;
};
XLSXImporter.prototype.measureSheet = function(sheet) {
var sheetRange = XLSX.utils.decode_range(sheet["!ref"]);
return {
startRow: Math.min(sheetRange.s.r,sheetRange.e.r),
endRow: Math.max(sheetRange.s.r,sheetRange.e.r),
startCol: Math.min(sheetRange.s.c,sheetRange.e.c),
endCol: Math.max(sheetRange.s.c,sheetRange.e.c)
}
};
XLSXImporter.prototype.findColumns = function(sheet,sheetSize) {
var columnsByName = {};
for(var col=sheetSize.startCol; col<=sheetSize.endCol; col++) {
var cell = sheet[XLSX.utils.encode_cell({c: col, r: sheetSize.startRow})],
columnName;
if(cell) {
columnName = cell.w;
if(columnName) {
columnsByName[columnName] = col;
}
}
}
return columnsByName;
};
exports.XLSXImporter = XLSXImporter;
})();

View File

@ -0,0 +1,7 @@
{
"title": "$:/plugins/tiddlywiki/xlsx-utils",
"description": "XLSX spreadsheet utilities",
"author": "Jeremy Ruston and SheetJS",
"core-version": ">=5.0.0",
"list": "readme controls license"
}

View File

@ -0,0 +1,24 @@
title: $:/plugins/tiddlywiki/xlsx-utils/readme
This plugin provides a flexible way to import tiddlers from Excel files. It is based on the library [[js-xlsx|https://github.com/SheetJS/js-xlsx]].
The plugin uses //import specifications// to determine how incoming spreadsheets are processed. You can view, create and edit import specifications in the control panel "XLSX Utilities" tab, or directly in the [[plugin controls|$:/plugins/tiddlywiki/xlsx-utils]]. This is also where you select which import specification is selected for use during the next import operation.
Each sheet is expected to consist of a single header row followed by multiple content rows, each consisting of an independent record. The plugin automatically detects the extent of each sheet by looking for the bottom right cell that contains a value. This can lead to unexpected results if a cell is accidentally created with an invisible, blank value.
Import specifications describe how tiddlers are created from a particular row of a sheet; multiple tiddlers can be generated from a single row.
Each field of each tiddler can be assigned a constant value, or a value taken from a named column of the sheet, optionally with a prefix and/or suffix added. There is special support for handling list fields (like the tags field), with the ability to append new items to the list.
Internally, each import specifier is actually modelled as a hierarchy of connected tiddlers with the field ''import-spec-role'' indicating the following roles:
* ''workbook'': describes the sheets to be imported from the workbook
* ''sheet'': describes each sheet to be processed
* ''row'': describes the tiddlers to be imported from each row of each sheet
* ''field'': describes the fields to be assigned to each tiddler from each row of each sheet
The easiest way to understand the structure is to explore the example import specifications, and the corresponding spreadsheets they are designed to handle.
Note that there are many possible different ways of importing a particular spreadsheet, depending on whether the structures are modelled with fields, tags, prefixes or other mechanisms. The plugin is designed to support a wide range of applications.
This plugin also requires the JSZip plugin ([[$:/plugins/tiddlywiki/jszip]]) to be installed.

View File

@ -0,0 +1,29 @@
/*\
title: $:/plugins/tiddlywiki/xlsx-utils/startup.js
type: application/javascript
module-type: startup
Initialisation
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
// Export name and synchronous status
exports.name = "startup";
exports.after = ["load-modules"];
exports.synchronous = true;
exports.startup = function() {
// Check JSZip is installed
if(!$tw.utils.hop($tw.modules.titles,"$:/plugins/tiddlywiki/jszip/jszip.js")) {
// Make a logger
var logger = new $tw.utils.Logger("xlsx-utils");
logger.alert("The plugin 'xlsx-utils' requires the 'jszip' plugin to be installed");
}
};
})();

View File

@ -0,0 +1,176 @@
title: $:/plugins/tiddlywiki/xlsx-utils/styles
tags: [[$:/tags/Stylesheet]]
\define quick-colour-selector-background() #bae3f1
\define quick-colour-selector-border() #97b8c3
\define quick-colour-editor-background() #bae3f1
\define quick-colour-editor-controls() #d2ffff
\define quick-colour-editor-border() #97b8c3
\define quick-colour-workbook-background() #baf1db
\define quick-colour-workbook-controls() #d3fff6
\define quick-colour-workbook-border() #98c3b2
\define quick-colour-sheet-background() #f1ebba
\define quick-colour-sheet-controls() #fffed3
\define quick-colour-sheet-border() #c4be98
\define quick-colour-row-background() #f1baba
\define quick-colour-row-controls() #fed1d2
\define quick-colour-row-border() #c39697
\define quick-colour-field-background() #e0d4fb
\define quick-colour-field-controls() #fcefff
\define quick-colour-field-border() #b6adcb
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline
.tc-import-spec-selector {
border: 1px solid <<quick-colour-editor-border>>;
background-color: <<quick-colour-editor-background>>;
padding: 0.25em;
}
.tc-import-spec-editor-wrapper {
border: 1px solid <<quick-colour-editor-border>>;
background-color: <<quick-colour-editor-background>>;
padding: 0.25em;
}
.tc-import-spec-editor {
border: 1px solid <<quick-colour-editor-border>>;
background-color: <<colour background>>;
margin: 0.25em;
}
.tc-import-spec-editor-controls {
display: block;
background-color: <<quick-colour-editor-controls>>;
border-bottom: 1px solid <<quick-colour-editor-background>>;
padding: 0;
margin: 0;
list-style: none;
}
.tc-import-spec-editor-controls li {
padding: 0.25em 0.5em;
}
.tc-import-spec-editor-controls li:not(:last-child) {
border-bottom: 1px solid <<quick-colour-editor-background>>;
}
.tc-import-spec-editor-list {
}
.tc-import-spec-workbook-wrapper {
border: 1px solid <<quick-colour-workbook-border>>;
background-color: <<quick-colour-workbook-background>>;
padding: 0.25em;
margin: 0.5em;
}
.tc-import-spec-workbook {
border: 1px solid <<quick-colour-workbook-border>>;
background-color: <<colour background>>;
margin: 0.25em;
}
.tc-import-spec-workbook-controls {
display: block;
background-color: <<quick-colour-workbook-controls>>;
border-bottom: 1px solid <<quick-colour-workbook-background>>;
padding: 0;
margin: 0;
list-style: none;
}
.tc-import-spec-workbook-controls li {
padding: 0.25em 0.5em;
}
.tc-import-spec-workbook-controls li:not(:last-child) {
border-bottom: 1px solid <<quick-colour-workbook-background>>;
}
.tc-import-spec-workbook-list {
}
.tc-import-spec-sheet-wrapper {
border: 1px solid <<quick-colour-sheet-border>>;
background-color: <<quick-colour-sheet-background>>;
padding: 0.25em;
margin: 0.5em;
}
.tc-import-spec-sheet {
border: 1px solid <<quick-colour-sheet-border>>;
background-color: <<colour background>>;
margin: 0.25em;
}
.tc-import-spec-sheet-controls {
display: block;
background-color: <<quick-colour-sheet-controls>>;
border-bottom: 1px solid <<quick-colour-sheet-background>>;
padding: 0;
margin: 0;
list-style: none;
}
.tc-import-spec-sheet-controls li {
padding: 0.25em 0.5em;
}
.tc-import-spec-sheet-controls li:not(:last-child) {
border-bottom: 1px solid <<quick-colour-sheet-background>>;
}
.tc-import-spec-sheet-list {
}
.tc-import-spec-row-wrapper {
border: 1px solid <<quick-colour-row-border>>;
background-color: <<quick-colour-row-background>>;
padding: 0.25em;
margin: 0.5em;
}
.tc-import-spec-row {
border: 1px solid <<quick-colour-row-border>>;
background-color: <<colour background>>;
margin: 0.25em;
}
.tc-import-spec-row-controls {
display: block;
background-color: <<quick-colour-row-controls>>;
border-bottom: 1px solid <<quick-colour-row-background>>;
padding: 0;
margin: 0;
list-style: none;
}
.tc-import-spec-row-controls li {
padding: 0.25em 0.5em;
}
.tc-import-spec-row-controls li:not(:last-child) {
border-bottom: 1px solid <<quick-colour-row-background>>;
}
.tc-import-spec-row-list {
list-style: none;
padding: 0;
margin: 0;
}
.tc-import-spec-field-wrapper {
font-size: 0.9em;
border: 1px solid <<quick-colour-field-border>>;
background-color: <<quick-colour-field-background>>;
padding: 0.25em;
margin: 0.5em;
}

View File

@ -0,0 +1,45 @@
/*\
title: $:/plugins/tiddlywiki/xlsx-utils/xlsx-import-command.js
type: application/javascript
module-type: command
Command to import an xlsx file
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "xlsx-import",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing parameters";
}
var self = this,
wiki = this.commander.wiki,
filename = this.params[0],
importSpec = this.params[1],
XLSXImporter = require("$:/plugins/tiddlywiki/xlsx-utils/importer.js").XLSXImporter,
importer = new XLSXImporter({
filename: filename,
importSpec: importSpec
});
$tw.wiki.addTiddlers(importer.importTiddlers());
return null;
};
exports.Command = Command;
})();