Skip to content

Commit 522cdb9

Browse files
committed
resizable wikitextTable
1 parent d2d94f5 commit 522cdb9

File tree

2 files changed

+287
-22
lines changed

2 files changed

+287
-22
lines changed

resizer/plugin.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "Resizer",
44
"description": "General-purpose resizer widget for TiddlyWiki5",
55
"author": "Simon Huber",
6-
"version": "0.4.4",
6+
"version": "0.4.5",
77
"core-version": ">=5.3.0",
88
"source": "https://github.com/BurningTreeC/resizer",
99
"plugin-type": "plugin",

resizer/ui/panels/panels.tid

Lines changed: 286 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,14 @@ code-body: yes
307307
\end
308308

309309
\function tf.get.table.width() [<stateTiddlerPrefix>addsuffix[parent-size]get[text]addsuffix[px]]
310-
\function tf.get.max.column.width() [range<columns>!match<colIndex>!match<nextColIndex>] :reduce[addprefix<stateTiddlerPrefix>get[text]!prefix[Infinity]else<cellWidth>add<accumulator>] +[subtract[100]] :map[abs<currentTiddler>subtract<tf.get.min.column.width.percentage>addsuffix[%]]
310+
311+
\function tf.get.max.column.width()
312+
[range<columns>!match<colIndex>!match<nextColIndex>]
313+
:reduce[addprefix<stateTiddlerPrefix>get[text]!prefix[Infinity]else<cellWidth>add<accumulator>]
314+
:and[subtract[100]]
315+
:map[abs<currentTiddler>subtract<tf.get.min.column.width.percentage>addsuffix[%]]
316+
\end
317+
311318
\function tf.get.min.column.width.percentage() [tf.convert.px.to.percentage<tf.get.table.width>,[50px]addsuffix[%]]
312319
\function tf.get.max.column.width.percentage() [<colIndex>!match<columns>then<tf.get.table.width>!is[blank]then<tf.get.max.column.width>]
313320

@@ -330,19 +337,240 @@ code-body: yes
330337
</$let>
331338
\end
332339

333-
\procedure resizable-table(columns:"", rows:"", columnFilter:"", rowFilter:"", tableHeight:"auto", class:"", headerClass:"", cellClass:"", stateTiddlerPrefix:"$:/state/resizable-table/col-")
340+
\procedure resizable-table-content-inner(filter)
341+
\whitespace trim
342+
<%if [<editable>match[yes]] %>
343+
<$let state={{{ [[$:/state/edit-cell-]addsuffix<colIndex>addsuffix[-]addsuffix<row>addsuffix[-]addsuffix<qualify>] }}}>
344+
<%if [<state>get[text]!match[yes]] [<state>is[missing]] %>
345+
<div style.display="flex">
346+
<div style.flex="1">
347+
<$wikify name="content" text="""<$text text={{{ [subfilter<filter>get<field>] }}}/>""">
348+
<<content>>
349+
</$wikify>
350+
</div>
351+
<div>
352+
<$button class="tc-btn-invisible" set=<<state>> setTo="yes" actions=<<resizable-table-content-create-tiddler-actions>>>
353+
{{$:/core/images/edit-button}}
354+
</$button>
355+
</div>
356+
</div>
357+
<% else %>
358+
<div style.display="flex">
359+
<div style.flex="1">
360+
<$edit-text tag="input" tiddler={{{ [subfilter<filter>] }}} focus="yes" class="tc-width-100"/>
361+
</div>
362+
<div>
363+
<$button class="tc-btn-invisible" set=<<state>> setTo="no">
364+
{{$:/core/images/done-button}}
365+
</$button>
366+
</div>
367+
</div>
368+
<% endif %>
369+
</$let>
370+
<% else %>
371+
<$wikify name="content" text="""<$text text={{{ [subfilter<filter>get<field>] }}}/>""">
372+
<<content>>
373+
</$wikify>
374+
<% endif %>
375+
\end
376+
377+
\procedure resizable-table-content(filter,tableArea)
378+
<%if [<wikitextTable>is[blank]] %>
379+
<$transclude $variable="resizable-table-content-inner" filter=<<filter>>/>
380+
<%elseif [<tableArea>match[header]] %>
381+
<$let tableHeader={{{ [<wikitextTable>splitregexp[\n]suffix[|h]] }}} tableHeaderCell={{{ [<tableHeader>split[|]butfirst[]butlast[]nth<colIndex>] }}}>
382+
<$wikify name="content" text=<<tableHeaderCell>>>
383+
<<content>>
384+
</$wikify>
385+
</$let>
386+
<%elseif [<tableArea>match[rows]] %>
387+
<$let tableRow={{{ [<wikitextTable>splitregexp[\n]!suffix[|h]!suffix[|c]!suffix[|f]!suffix[|k]nth<rowIndex>] }}} tableRowCell={{{ [<tableRow>split[|]butfirst[]butlast[]nth<colIndex>] }}}>
388+
<$wikify name="content" text=<<tableRowCell>>>
389+
<<content>>
390+
</$wikify>
391+
</$let>
392+
<%elseif [<tableArea>match[footer]] %>
393+
<$let tableFooter={{{ [<wikitextTable>splitregexp[\n]suffix[|f]] }}} tableFooterCell={{{ [<tableFooter>split[|]butfirst[]butlast[]nth<colIndex>] }}}>
394+
<$wikify name="content" text=<<tableFooterCell>>>
395+
<<content>>
396+
</$wikify>
397+
</$let>
398+
<% endif %>
399+
\end
400+
401+
402+
<!-- Replace every cell value except ">" or "<" by "1" -->
403+
\function fn.row.value-to-1()
404+
[all[]]
405+
:map[<currentTiddler>!regexp[>|<]then[1]else<currentTiddler>]
406+
:map[<currentTiddler>match[<]then<index>match[0]then[1]else<currentTiddler>]
407+
:map[<currentTiddler>match[>]then<index>match<columnsMinusOne>then[1]else<currentTiddler>]
408+
+[join[ ]]
409+
\end
410+
411+
412+
<!-- Replace every cell value except "~" by "1" -->
413+
\function fn.col.value-to-1()
414+
[all[]]
415+
:map[<currentTiddler>!match[~]then[1]else<currentTiddler>]
416+
:map[<currentTiddler>match[~]then<index>match[0]then[1]else<currentTiddler>]
417+
+[join[ ]]
418+
\end
419+
420+
421+
<!-- Counts the occurrences of "c" in string "s" -->
422+
\function fn.nb(c,s)
423+
[<s>split<c>count[]subtract[1]]
424+
\end
425+
426+
427+
<!-- Replaces sequences of "from" characters by "to" characters -->
428+
\function fn.expand.cell(from,to)
429+
[fn.nb<from>,<cell>!match[0]]
430+
:map:flat[range<currentTiddler>]
431+
:map[<to>]
432+
+[join[]]
433+
\end
434+
435+
436+
<!-- Returns <<cell>> length -->
437+
\function fn.cell.ln() [<cell>split[]count[]]
438+
439+
440+
<!-- Computes current <<cell>> weight -->
441+
\function fn.compute.row.cell(cell)
442+
=[fn.expand.cell[>],[0 ]]
443+
=[fn.cell.ln[]]
444+
=[fn.expand.cell[<],[ 0]]
445+
+[join[]]
446+
\end
447+
448+
449+
<!-- Computes current <<cell>> weight -->
450+
\function fn.compute.col.cell(cell)
451+
=[fn.cell.ln[]]
452+
=[fn.expand.cell[~],[ 0]]
453+
+[join[]]
454+
\end
455+
456+
457+
<!-- Computes current <<row>> weights -->
458+
\function fn.compute.row(row)
459+
=[<row>split[|]]
460+
:map:flat[fn.compute.row.cell<currentTiddler>]
461+
+[join[ ]]
462+
\end
463+
464+
465+
<!-- Computes current <<col>> weights -->
466+
\function fn.compute.col(col)
467+
=[<col>split[|]]
468+
:map:flat[fn.compute.col.cell<currentTiddler>]
469+
+[join[ ]]
470+
\end
471+
472+
473+
<!-- Sanitizes input (not perfect, but you get the idea... -->
474+
\function fn.sanitize()
475+
[all[]]
476+
:map[<currentTiddler>search-replace:g[||],[|x|]search-replace:g:regexp[\|\s+\|],[|x|]]
477+
\end
478+
479+
480+
<!-- Replaces actual cell values by "1"s -->
481+
\function fn.get.row.ones()
482+
[all[]]
483+
:map[<currentTiddler>split[|]butfirst[]butlast[]trim[]fn.row.value-to-1[]enlist-input:raw[]join[|]]
484+
\end
485+
486+
487+
<!-- Replaces actual cell values by "1"s -->
488+
\function fn.get.col.ones()
489+
[all[]]
490+
:map[<currentTiddler>split[|]trim[]butfirst[]butlast[]fn.col.value-to-1[]enlist-input:raw[]join[|]]
491+
\end
492+
493+
494+
<!-- Collapse cells (">|1" becomes ">1" -->
495+
\function fn.row.collapse()
496+
[all[]]
497+
:map[<currentTiddler>search-replace:g[>|],[>]search-replace:g[|<],[<]]
498+
\end
499+
500+
501+
<!-- Collapse cells ("1|~" becomes "1~" -->
502+
\function fn.col.collapse()
503+
[all[]]
504+
:map[<currentTiddler>search-replace:g[|~],[~]]
505+
\end
506+
507+
508+
\function tf.exclude.header.caption.classes.footer() [!suffix[|h]!suffix[|c]!suffix[|f]!suffix[|k]]
509+
\function tf.is.header() [suffix[|h]]
510+
511+
512+
<!-- Maps a table to its colspans -->
513+
\function row.map(table,fn)
514+
[<table>splitregexp[\n]function<fn>] :and[nth<rowIndex>]
515+
:map[<currentTiddler>fn.sanitize[]]
516+
:map[<currentTiddler>fn.get.row.ones[>|<]]
517+
:map[<currentTiddler>fn.row.collapse[]]
518+
:map[fn.compute.row<currentTiddler>]
519+
\end
520+
521+
522+
<!-- Maps a table to its rowspans -->
523+
\function col.map(table,fn)
524+
[<table>splitregexp[\n]function<fn>split[|]butfirst[]butlast[]join[ ]enlist-input:raw[]]
525+
:map:flat[<index>remainder<columns>match<previousColIndex>then<currentTiddler>]
526+
:and[!match[]join[|]] :and[addprefix[|]addsuffix[|]]
527+
:map[<currentTiddler>fn.sanitize[]]
528+
:map[<currentTiddler>fn.get.col.ones[]]
529+
:map[<currentTiddler>fn.col.collapse[]]
530+
:map[fn.compute.col<currentTiddler>]
531+
\end
532+
533+
534+
\function tf.get.colspan() [row.map<wikitextTable>,[tf.exclude.header.caption.classes.footer]split[ ]!match[]nth<colIndex>]
535+
\function tf.get.rowspan() [col.map<wikitextTable>,[tf.exclude.header.caption.classes.footer]split[ ]!match[]nth<rowIndex>]
536+
537+
538+
\function tf.row.split.regexp() [<wikitextTable>splitregexp[\n]!is[blank]]
539+
\function tf.row.split.regexp.count.columns() [function[tf.row.split.regexp]!suffix[|c]!suffix[|k]nth[1]split[|]butfirst[]butlast[]count[]]
540+
\function tf.row.split.regexp.count.rows() [function[tf.row.split.regexp]!suffix[|h]!suffix[|c]!suffix[|f]!suffix[|k]count[]]
541+
\function tf.row.split.regexp.has.header() [function[tf.row.split.regexp]suffix[|h]then[yes]]
542+
\function tf.row.split.regexp.has.footer() [function[tf.row.split.regexp]suffix[|f]then[yes]]
543+
\function tf.row.split.regexp.get.caption() [function[tf.row.split.regexp]suffix[|c]split[|]butfirst[]butlast[]first[]]
544+
545+
546+
\procedure resizable-table(columns:"", rows:"", columnFilter:"", rowFilter:"", footerFilter:"", field:"text", editable:"no", tableHeight:"auto", class:"", headerClass:"", cellClass:"", stateTiddlerPrefix:"$:/state/resizable-table/", caption:"", wikitextTable:"")
334547
\whitespace trim
335-
<$let cellWidth={{{ [[100]divide<columns>addsuffix[%]] }}}>
548+
<$let
549+
columns={{{ [<wikitextTable>!is[blank]then<tf.row.split.regexp.count.columns>] :else[<wikitextTable>is[blank]then<columns>] :else[[0]] }}}
550+
rows={{{ [<wikitextTable>!is[blank]then<tf.row.split.regexp.count.rows>] :else[<wikitextTable>is[blank]then<rows>] :else[[0]] }}}
551+
cellWidth={{{ [[100]divide<columns>addsuffix[%]] }}}
552+
stateTiddlerPrefix={{{ [<stateTiddlerPrefix>addsuffix<columns>addsuffix<qualify>addsuffix[/]addsuffix[col-]] }}}
553+
hasHeader={{{ [<wikitextTable>!is[blank]then<tf.row.split.regexp.has.header>] :else[[no]] }}}
554+
hasFooter={{{ [<wikitextTable>!is[blank]then<tf.row.split.regexp.has.footer>] :else[[no]] }}}
555+
caption={{{ [<wikitextTable>!is[blank]then<tf.row.split.regexp.get.caption>] :else[<caption>!is[blank]] :else[[]] }}}
556+
wikitextClasses={{{ [<wikitextTable>!is[blank]then<tf.row.split.regexp>suffix[|k]split[|]butfirst[]butlast[]first[]] }}}
557+
columnsMinusOne={{{ [<columns>subtract[1]] }}}
558+
>
336559
<div class={{{ tc-resizable-table-wrapper [<class>] +[join[ ]] }}} style.height=<<tableHeight>> style.width="100%">
337-
<table class="tc-resizable-table" style.width="100%">
338-
<%if [<columns>!is[blank]] %>
560+
<table class={{{ tc-resizable-table evenRow [<wikitextClasses>] +[join[ ]] }}} style.width="100%">
561+
<%if [<caption>!is[blank]] %>
562+
<caption>
563+
<<caption>>
564+
</caption>
565+
<% endif %>
566+
<%if [<wikitextTable>is[blank]then<columns>!is[blank]then<columnFilter>!is[blank]] [<wikitextTable>!is[blank]then<hasHeader>match[yes]] %>
339567
<thead>
340568
<tr class={{{ tc-resizable-table-header [<headerClass>] +[join[ ]] }}}>
341569
<$list filter="[range<columns>]" variable="column" counter="colIndex">
342-
<$let nextColIndex={{{ [<colIndex>add[1]] }}}>
570+
<$let nextColIndex={{{ [<colIndex>add[1]] }}} row="0">
343571
<th style.position="relative" style.min-width=<<tf.get.min.column.width.percentage>> style.max-width=<<tf.get.max.column.width.percentage>> style.width={{{ [<stateTiddlerPrefix>addsuffix<colIndex>get[text]!prefix[Infinity]] :else[<cellWidth>] }}}>
344572
<div class="tc-resizable-table-cell" style.width="100%">
345-
<$text text=<<colIndex>>/>
573+
<$transclude $variable="resizable-table-content" filter=<<columnFilter>> tableArea="header"/>
346574
</div>
347575
<%if [<colIndex>!match<columns>] %>
348576
<$resizer
@@ -363,39 +591,76 @@ code-body: yes
363591
</tr>
364592
</thead>
365593
<% endif %>
366-
<%if [<rows>!is[blank]] %>
594+
<%if [<wikitextTable>is[blank]then<rows>!is[blank]then<rowFilter>!is[blank]] [<wikitextTable>!is[blank]] %>
367595
<tbody>
368-
<$list filter="[range<rows>]" variable="row">
369-
<tr class={{{ tc-resizable-table-row [<cellClass>] +[join[ ]] }}}>
596+
<$list filter="[range<rows>]" variable="row" counter="rowIndex">
597+
<tr class={{{ tc-resizable-table-row [<rowIndex>remainder[2]match[1]then[evenRow]else[oddRow]] [<cellClass>] +[join[ ]] }}}>
370598
<$list filter="[range<columns>]" variable="column" counter="colIndex">
371-
<td style.min-width=<<tf.get.min.column.width.percentage>> style.max-width=<<tf.get.max.column.width.percentage>> style.width={{{ [<stateTiddlerPrefix>addsuffix<colIndex>get[text]!prefix[Infinity]] :else[<cellWidth>] }}}>
372-
<div class="tc-resizable-table-cell" style.width="100%">
373-
<$text text={{{ [<row>addsuffix[ - ]addsuffix<colIndex>] }}}/>
374-
</div>
375-
</td>
599+
<$let
600+
previousColIndex={{{ [<colIndex>subtract[1]] }}}
601+
nextColIndex={{{ [<colIndex>add[1]] }}}
602+
colspan={{{ [<wikitextTable>!is[blank]then<tf.get.colspan>] :else[[1]] }}}
603+
rowspan={{{ [<wikitextTable>!is[blank]then<tf.get.rowspan>] :else[[1]] }}}
604+
>
605+
<%if [<colspan>!match[0]then<rowspan>!match[0]] %>
606+
<td style.position="relative" style.min-width=<<tf.get.min.column.width.percentage>> style.max-width=<<tf.get.max.column.width.percentage>> style.width={{{ [<stateTiddlerPrefix>addsuffix<colIndex>get[text]!prefix[Infinity]] :else[<cellWidth>] }}} colspan=<<colspan>> rowspan=<<rowspan>>>
607+
<div class="tc-resizable-table-cell" style.width="100%">
608+
<$transclude $variable="resizable-table-content" filter=<<rowFilter>> tableArea="rows"/>
609+
</div>
610+
<%if [<colIndex>!match<columns>] %>
611+
<$resizer
612+
class="tc-table-column-resizer"
613+
direction="horizontal"
614+
min=<<tf.get.min.column.width.percentage>>
615+
max=<<tf.get.max.column.width.percentage>>
616+
default=<<cellWidth>>
617+
unit="px"
618+
element="parent.parent"
619+
onBeforeResizeStart=<<resizable-table-on-before-resize-start-actions>>
620+
onResize=<<resizable-table-on-resize-actions>>
621+
/>
622+
<% endif %>
623+
</td>
624+
<% endif %>
625+
</$let>
376626
</$list>
377627
</tr>
378628
</$list>
379629
</tbody>
380630
<% endif %>
631+
<%if [<wikitextTable>is[blank]then<footerFilter>!is[blank]] [<wikitextTable>!is[blank]then<hasFooter>match[yes]] %>
632+
<tfoot>
633+
<tr class="evenRow">
634+
<$list filter="[range<columns>]" variable="column" counter="colIndex">
635+
<$let nextColIndex={{{ [<colIndex>add[1]] }}} row={{{ [<rows>add[1]] }}}>
636+
<td style.min-width=<<tf.get.min.column.width.percentage>> style.max-width=<<tf.get.max.column.width.percentage>> style.width={{{ [<stateTiddlerPrefix>addsuffix<colIndex>get[text]!prefix[Infinity]] :else[<cellWidth>] }}}>
637+
<div class="tc-resizable-table-cell" style.width="100%">
638+
<$transclude $variable="resizable-table-content" filter=<<footerFilter>> tableArea="footer"/>
639+
</div>
640+
</td>
641+
</$let>
642+
</$list>
643+
</tr>
644+
</tfoot>
645+
<% endif %>
381646
</table>
382647
</div>
383648
</$let>
384649
\end
385650

386-
\procedure resizable-table-flexbox(columns:"", rows:"", columnFilter:"", rowFilter:"", tableHeight:"auto", class:"", headerClass:"", cellClass:"", stateTiddlerPrefix:"$:/state/resizable-table-flex/col-")
651+
\procedure resizable-table-flexbox(columns:"", rows:"", columnFilter:"", rowFilter:"", editable:"no", tableHeight:"auto", class:"", headerClass:"", cellClass:"", stateTiddlerPrefix:"$:/state/resizable-table-flex/", wikitextTable:"")
387652
\whitespace trim
388-
<$let cellWidth={{{ [[100]divide<columns>addsuffix[%]] }}}>
653+
<$let cellWidth={{{ [[100]divide<columns>addsuffix[%]] }}} stateTiddlerPrefix={{{ [<stateTiddlerPrefix>addsuffix<columns>addsuffix<qualify>addsuffix[/]addsuffix[col-]] }}}>
389654
<div class={{{ tc-resizable-table-flexbox-wrapper [<class>] +[join[ ]] }}} style.height=<<tableHeight>> style.width="100%" style.display="flex" style.flex-direction="column">
390-
<%if [<columns>!is[blank]] %>
655+
<%if [<columns>!is[blank]then<columnFilter>!is[blank]] %>
391656
<div class={{{ tc-resizable-table-flexbox-header [<headerClass>] +[join[ ]] }}} style.display="flex">
392657
<$list filter="[range<columns>]" variable="column" counter="colIndex">
393658
<$let
394659
nextColIndex={{{ [<colIndex>add[1]] }}}
395660
columnZIndex={{{ [<columns>subtract<colIndex>add[1]] }}}
396661
>
397662
<div style.position="relative" style.z-index=<<columnZIndex>> style.min-width=<<tf.get.min.column.width.percentage>> style.max-width=<<tf.get.max.column.width.percentage>> style.width={{{ [<stateTiddlerPrefix>addsuffix<colIndex>get[text]!prefix[Infinity]] :else[<cellWidth>] }}} style.padding="8px" style.font-weight="bold">
398-
<$text text={{{ [[Column ]addsuffix<colIndex>] }}}/>
663+
<$transclude $variable="resizable-table-content" filter=<<columnFilter>>/>
399664
<%if [<colIndex>!match<columns>] %>
400665
<$resizer
401666
class="tc-table-column-resizer-flexbox"
@@ -416,14 +681,14 @@ code-body: yes
416681
<% endif %>
417682
<%if [<rows>!is[blank]] %>
418683
<div class="tc-resizable-table-flexbox-body" style.flex="1" style.overflow="auto">
419-
<$list filter="[range<rows>]" variable="row">
684+
<$list filter="[range<rows>]" variable="row" counter="rowIndex">
420685
<div class={{{ tc-resizable-table-flexbox-row [<cellClass>] +[join[ ]] }}} style.display="flex">
421686
<$list filter="[range<columns>]" variable="column" counter="colIndex">
422687
<$let
423688
nextColIndex={{{ [<colIndex>add[1]] }}}
424689
columnZIndex={{{ [<columns>subtract<colIndex>add[1]] }}}>
425690
<div style.position="relative" style.z-index=<<columnZIndex>> style.min-width=<<tf.get.min.column.width.percentage>> style.max-width=<<tf.get.max.column.width.percentage>> style.width={{{ [<stateTiddlerPrefix>addsuffix<colIndex>get[text]!prefix[Infinity]] :else[<cellWidth>] }}} style.padding="8px" style.word-wrap="break-word" style.overflow-wrap="break-word">
426-
<$text text={{{ [<row>addsuffix[ - ]addsuffix<colIndex>] }}}/>
691+
<$transclude $variable="resizable-table-content" filter=<<rowFilter>>/>
427692
</div>
428693
</$let>
429694
</$list>

0 commit comments

Comments
 (0)