@@ -43,20 +43,12 @@ interface EventListenerOptions {
4343export abstract class BaseView < T extends HTMLElement | SVGElement > {
4444 readonly _data : Obj < unknown > = { } ;
4545 readonly _events : Obj < EventCallback [ ] > = { } ;
46- _mutationObserver : MutationObserver | undefined ;
47- private readonly _mutationObserverCallbacks : Obj < EventCallback [ ] > = { } ;
4846 readonly type : string = 'default' ;
4947 model ?: Observable ;
50- isDeleted ?: boolean ;
5148
52- constructor ( readonly __el : T ) {
49+ constructor ( readonly _el : T ) {
5350 // Store a reference to this element within the native browser DOM.
54- __el . _view = this ;
55- }
56-
57- get _el ( ) {
58- if ( this . isDeleted ) console . error ( 'Trying to access a deleted element:' , this ) ;
59- return this . __el ;
51+ _el . _view = this ;
6052 }
6153
6254 get id ( ) {
@@ -606,33 +598,12 @@ export abstract class BaseView<T extends HTMLElement|SVGElement> {
606598 }
607599 }
608600
609- /** Removes listeners and model data from el */
610- private unsubscribe ( ) {
611- this . isDeleted = true ;
612- this . model ?. clear ( ) ;
613- this . _mutationObserver ?. disconnect ( ) ;
614- this . offAll ( ) ;
615-
616- for ( const child of this . children ) {
617- child . unsubscribe ( ) ;
618- }
619-
620- /* Disabled temporarily
621- // hack to avoid TS notification
622- // about setting undefined value to readonly properties
623- delete (this as any)._el;
624- delete (this as any)._data;
625- delete (this as any)._events;
626-
627- // remove mutation observer instances
628- delete (this as any)._mutationObserver;
629- delete (this as any)._mutationObserverCallbacks; */
630- }
631-
632601 /** Removes this element. */
633602 remove ( ) {
634603 this . detach ( ) ;
635- this . unsubscribe ( ) ;
604+ // TODO Remove event listeners (including children)
605+ // TODO Remove model bindings (including children)
606+ // this._el = this._data = this._events = undefined;
636607 }
637608
638609 /** Removes all children of this element. */
@@ -678,24 +649,13 @@ export abstract class BaseView<T extends HTMLElement|SVGElement> {
678649 */
679650 off ( events : string , callback ?: EventCallback ) {
680651 for ( const e of words ( events ) ) {
681- if ( callback ) {
682- this . _events [ e ] = this . _events [ e ] . filter ( fn => fn !== callback ) ;
683- unbindEvent ( this , e , callback ) ;
684- continue ;
652+ if ( e in this . _events ) {
653+ this . _events [ e ] = callback ? this . _events [ e ] . filter ( fn => fn !== callback ) : [ ] ;
685654 }
686- for ( const eventsCallback of this . _events [ e ] ) unbindEvent ( this , e , eventsCallback ) ;
655+ unbindEvent ( this , e , callback ) ;
687656 }
688657 }
689658
690- /**
691- * Removes all event listeners from this element
692- */
693- offAll ( ) {
694- Object . entries ( this . _events ) . forEach ( ( [ eventName , callbacks ] ) => {
695- callbacks . forEach ( ( callback ) => this . off ( eventName , callback ) ) ;
696- } ) ;
697- }
698-
699659 /** Triggers a specific event on this element. */
700660 trigger ( events : string , args : unknown = { } ) {
701661 for ( const e of words ( events ) ) {
@@ -713,41 +673,28 @@ export abstract class BaseView<T extends HTMLElement|SVGElement> {
713673 const keyNames = new Set ( words ( keys ) ) ;
714674 const event = options ?. up ? 'keyup' : 'keydown' ;
715675
716- const eventFunction = ( e : KeyboardEvent ) => {
676+ const target = ( this . _el === document . body ? document : this . _el ) as HTMLElement ;
677+ target . addEventListener ( event , ( e : KeyboardEvent ) => {
717678 const key = keyCode ( e ) ;
718679 if ( options ?. meta ? ! e . ctrlKey && ! e . metaKey : e . ctrlKey || e . metaKey ) return ;
719680 if ( ! key || ! keyNames . has ( key ) ) return ;
720681 if ( document . activeElement !== this . _el && document . activeElement ?. shadowRoot ?. activeElement !== this . _el && Browser . formIsActive ) return ;
721682 callback ( e as KeyboardEvent , key ) ;
722- } ;
723-
724- const target = ( this . _el === document . body ? document : this . _el ) as HTMLElement ;
725- target . addEventListener ( event , eventFunction ) ;
726-
727- if ( ! ( event in this . _events ) ) this . _events [ event ] = [ ] ;
728- this . _events [ event ] . push ( eventFunction ) ;
683+ } ) ;
729684 }
730685
731- /**
732- * Bind an listener when element attribute changed
733- */
734686 onAttr ( name : string , callback : ( value : string , initial ?: boolean ) => void ) {
735- if ( ! this . _mutationObserver ) {
736- this . _mutationObserver = new MutationObserver ( ( mutations ) => {
737- for ( const m of mutations ) {
738- if ( m . type === 'attributes' && m . attributeName === name ) {
739- for ( const attributeCallback of this . _mutationObserverCallbacks [ name ] ) {
740- attributeCallback ( this . attr ( name ) ) ;
741- }
742- }
743- }
744- } ) ;
745- this . _mutationObserver . observe ( this . _el , { attributes : true } ) ;
746- }
687+ // TODO Reuse existing observers, remove events, disconnect when deleting.
747688
748- if ( ! ( name in this . _mutationObserverCallbacks ) ) this . _mutationObserverCallbacks [ name ] = [ ] ;
749- this . _mutationObserverCallbacks [ name ] . push ( callback ) ;
689+ const observer = new MutationObserver ( ( mutations ) => {
690+ for ( const m of mutations ) {
691+ if ( m . type === 'attributes' && m . attributeName === name ) {
692+ callback ( this . attr ( name ) ) ;
693+ }
694+ }
695+ } ) ;
750696
697+ observer . observe ( this . _el , { attributes : true } ) ;
751698 callback ( this . attr ( name ) , true ) ;
752699 }
753700
@@ -1199,7 +1146,7 @@ export class WindowView extends HTMLBaseView<HTMLHtmlElement|HTMLBodyElement> {
11991146 }
12001147
12011148 get scrollTop ( ) {
1202- return window . scrollY ;
1149+ return window . pageYOffset ;
12031150 }
12041151
12051152 set scrollTop ( y ) {
@@ -1208,7 +1155,7 @@ export class WindowView extends HTMLBaseView<HTMLHtmlElement|HTMLBodyElement> {
12081155 }
12091156
12101157 get scrollLeft ( ) {
1211- return window . scrollX ;
1158+ return window . pageXOffset ;
12121159 }
12131160
12141161 set scrollLeft ( x ) {
0 commit comments