@@ -3,18 +3,7 @@ import { DOM } from 'aurelia-pal';
33import { View } from 'aurelia-templating' ;
44import { DomHelper } from './dom-helper' ;
55import { insertBeforeNode } from './utilities' ;
6-
7- export interface ITemplateStrategy {
8- getScrollContainer ( element : Element ) : HTMLElement ;
9- moveViewFirst ( view : View , topBuffer : Element ) : void ;
10- moveViewLast ( view : View , bottomBuffer : Element ) : void ;
11- createTopBufferElement ( element : Element ) : HTMLElement ;
12- createBottomBufferElement ( element : Element ) : HTMLElement ;
13- removeBufferElements ( element : Element , topBuffer : Element , bottomBuffer : Element ) : void ;
14- getFirstElement ( topBuffer : Element ) : Element ;
15- getLastElement ( bottomBuffer : Element ) : Element ;
16- getTopBufferDistance ( topBuffer : Element ) : number ;
17- }
6+ import { ITemplateStrategy } from './interfaces' ;
187
198export class TemplateStrategyLocator {
209
@@ -30,14 +19,96 @@ export class TemplateStrategyLocator {
3019 * Selects the template strategy based on element hosting `virtual-repeat` custom attribute
3120 */
3221 getStrategy ( element : Element ) : ITemplateStrategy {
33- if ( element . parentNode && ( element . parentNode as Element ) . tagName === 'TBODY' ) {
34- return this . container . get ( TableStrategy ) ;
22+ const parent = element . parentElement ;
23+ if ( parent === null ) {
24+ return this . container . get ( DefaultTemplateStrategy ) ;
25+ }
26+ const parentTagName = parent . tagName ;
27+ // placed on tr, as it is automatically wrapped in a TBODY
28+ // if not wrapped, then it is already inside a thead or tfoot
29+ if ( parentTagName === 'TBODY' || parentTagName === 'THEAD' || parentTagName === 'TFOOT' ) {
30+ return this . container . get ( TableRowStrategy ) ;
31+ }
32+ // place on a tbody/thead/tfoot
33+ if ( parentTagName === 'TABLE' ) {
34+ return this . container . get ( TableBodyStrategy ) ;
3535 }
36+ // if (element.parentNode && (element.parentNode as Element).tagName === 'TBODY') {
37+ // return this.container.get(TableStrategy);
38+ // }
3639 return this . container . get ( DefaultTemplateStrategy ) ;
3740 }
3841}
3942
40- export class TableStrategy implements ITemplateStrategy {
43+ export class TableBodyStrategy implements ITemplateStrategy {
44+
45+
46+ getScrollContainer ( element : Element ) : HTMLElement {
47+ return this . getTable ( element ) . parentNode as HTMLElement ;
48+ }
49+
50+ moveViewFirst ( view : View , topBuffer : Element ) : void {
51+ insertBeforeNode ( view , DOM . nextElementSibling ( topBuffer ) ) ;
52+ }
53+
54+ moveViewLast ( view : View , bottomBuffer : Element ) : void {
55+ const previousSibling = bottomBuffer . previousSibling ;
56+ const referenceNode = previousSibling . nodeType === 8 && ( previousSibling as Comment ) . data === 'anchor' ? previousSibling : bottomBuffer ;
57+ insertBeforeNode ( view , referenceNode as Element ) ;
58+ }
59+
60+ createTopBufferElement ( element : Element ) : HTMLElement {
61+ // append tbody with empty row before the element
62+ return element . parentNode . insertBefore ( DOM . createElement ( 'tr' ) , element ) ;
63+ }
64+
65+ createBottomBufferElement ( element : Element ) : HTMLElement {
66+ return element . parentNode . insertBefore ( DOM . createElement ( 'tr' ) , element . nextSibling ) ;
67+ }
68+
69+ removeBufferElements ( element : Element , topBuffer : Element , bottomBuffer : Element ) : void {
70+ DOM . removeNode ( topBuffer ) ;
71+ DOM . removeNode ( bottomBuffer ) ;
72+ }
73+
74+ getFirstElement ( topBuffer : Element ) : Element {
75+ return topBuffer . nextElementSibling ;
76+ }
77+
78+ getLastElement ( bottomBuffer : Element ) : Element {
79+ return bottomBuffer . previousElementSibling ;
80+ }
81+
82+ getTopBufferDistance ( topBuffer : Element ) : number {
83+ return 0 ;
84+ }
85+
86+ private getFirstTbody ( tableElement : HTMLTableElement ) : HTMLTableSectionElement {
87+ let child = tableElement . firstElementChild ;
88+ while ( child !== null && child . tagName !== 'TBODY' ) {
89+ child = child . nextElementSibling ;
90+ }
91+ return child . tagName === 'TBODY' ? child as HTMLTableSectionElement : null ;
92+ }
93+
94+ private _getLastTbody ( tableElement : HTMLTableElement ) : HTMLTableSectionElement {
95+ let child = tableElement . lastElementChild ;
96+ while ( child !== null && child . tagName !== 'TBODY' ) {
97+ child = child . previousElementSibling ;
98+ }
99+ return child . tagName === 'TBODY' ? child as HTMLTableSectionElement : null ;
100+ }
101+
102+ /**
103+ * `element` is actually a comment, acting as anchor for `virtual-repeat` attribute
104+ * `element` will be placed next to a tbody
105+ */
106+ private getTable ( element : Element ) : HTMLTableElement {
107+ return element . parentNode as HTMLTableElement ;
108+ }
109+ }
110+
111+ export class TableRowStrategy implements ITemplateStrategy {
41112
42113 static inject = [ DomHelper ] ;
43114
@@ -80,7 +151,7 @@ export class TableStrategy implements ITemplateStrategy {
80151 createTopBufferElement ( element : Element ) : HTMLElement {
81152 const elementName = / ^ [ U O ] L $ / . test ( ( element . parentNode as Element ) . tagName ) ? 'li' : 'div' ;
82153 const buffer = DOM . createElement ( elementName ) ;
83- const tableElement = element . parentNode . parentNode ;
154+ const tableElement = this . getTable ( element ) ;
84155 tableElement . parentNode . insertBefore ( buffer , tableElement ) ;
85156 buffer . innerHTML = ' ' ;
86157 return buffer ;
@@ -89,7 +160,7 @@ export class TableStrategy implements ITemplateStrategy {
89160 createBottomBufferElement ( element : Element ) : HTMLElement {
90161 const elementName = / ^ [ U O ] L $ / . test ( ( element . parentNode as Element ) . tagName ) ? 'li' : 'div' ;
91162 const buffer = DOM . createElement ( elementName ) ;
92- const tableElement = element . parentNode . parentNode ;
163+ const tableElement = this . getTable ( element ) ;
93164 tableElement . parentNode . insertBefore ( buffer , tableElement . nextSibling ) ;
94165 return buffer ;
95166 }
@@ -131,6 +202,13 @@ export class TableStrategy implements ITemplateStrategy {
131202 }
132203 return child . tagName === 'TBODY' ? child as HTMLTableSectionElement : null ;
133204 }
205+
206+ /**
207+ * `element` is actually a comment, acting as anchor for `virtual-repeat` attribute
208+ */
209+ private getTable ( element : Element ) : HTMLTableElement {
210+ return element . parentNode . parentNode as HTMLTableElement ;
211+ }
134212}
135213
136214export class DefaultTemplateStrategy implements ITemplateStrategy {
0 commit comments