Daniel Werner has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/76744


Change subject: valueview experts have a clear definition of destroy now
......................................................................

valueview experts have a clear definition of destroy now

- documented destroy properly, removed related TODOs
- implemented missing destroy methods
- added tests for destroy to testExpert and improved some other existing tests

Change-Id: I634c67b27e30f3b8d3a3202f1908b9752aded7a3
---
M ValueView/resources/jquery.valueview/valueview.Expert.js
M 
ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
M ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
M ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
M ValueView/resources/jquery.valueview/valueview.valueview.js
M ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
6 files changed, 116 insertions(+), 37 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues 
refs/changes/44/76744/1

diff --git a/ValueView/resources/jquery.valueview/valueview.Expert.js 
b/ValueView/resources/jquery.valueview/valueview.Expert.js
index da531cb..56c532b 100644
--- a/ValueView/resources/jquery.valueview/valueview.Expert.js
+++ b/ValueView/resources/jquery.valueview/valueview.Expert.js
@@ -88,7 +88,7 @@
                if( viewPortNode instanceof $
                        && viewPortNode.length === 1
                ) {
-                       viewPortNode = viewPortNode[0];
+                       viewPortNode = viewPortNode.get( 0 );
                }
 
                if( !( viewPortNode.nodeType ) ) { // IE8 can't check for 
instanceof HTMLELement
@@ -158,18 +158,25 @@
                _init: function() {},
 
                /**
-                * Gets called when the valueview's destroy function is called.
+                * Destroys the expert. All generated viewport output is being 
deleted and all resources
+                * (private members, events handlers) will be released.
                 *
-                * TODO: think about and document definition of this destroy. 
What is the destroy supposed
-                *  to do exactly? E.g. when having an expert responsible for 
displaying an input, should
-                *  the destroy leave the input or load an expert for 
displaying the value statically first?
+                * This will not preserve the plain text of the last 
represented value as one might expect
+                * when thinking about the common jQuery.Widget's behavior. 
This is mostly because it is
+                * not the Expert's responsibility to be able to serve a plain 
text representation of the
+                * value. If the value should be represented as plain text 
after the expert's construction,
+                * let the responsible controller simply use a value formatter 
for that.
                 *
                 * @since 0.1
                 */
                destroy: function() {
-                       this.$viewPort.removeClass( this.uiBaseClass );
+                       this.$viewPort.removeClass( this.uiBaseClass ).empty();
+
                        this.$viewPort = null;
                        this._viewState = null;
+                       this._viewNotifier = null;
+                       this._messageProvider = null;
+                       this._options = null;
                },
 
                /**
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
index 1474c86..aee4ca3 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
@@ -148,18 +148,32 @@
                 * @see jQuery.valueview.Expert.destroy
                 */
                destroy: function() {
-                       this.$precision.data( 'listrotator' ).destroy();
-                       this.$precision.remove();
-                       this.$precisionContainer.remove();
+                       if( !this.$input ) {
+                               return; // destroyed already
+                       }
 
-                       var previewElement = this.preview.element;
-                       this.preview.destroy();
-                       previewElement.remove();
+                       if( this.preview ) {
+                               this.preview.destroy();
+                               this.preview.element.remove();
+                       }
 
-                       this.$input.data( 'inputextender' ).destroy();
-                       this.$input.remove();
+                       var listRotator = this.$precision.data( 'listrotator' );
+                       if( listRotator ) {
+                               listRotator.destroy();
+                       }
 
-                       PARENT.prototype.destroy.call( this );
+                       var inputExtender = this.$input.data( 'inputextender' );
+                       if( inputExtender ) {
+                               inputExtender.destroy();
+                       }
+
+                       this.$input.off( 'eachchange' );
+
+                       this.$input = null;
+                       this.$precision = null;
+                       this.$precisionContainer = null;
+
+                       PARENT.prototype.destroy.call( this ); // empties 
viewport
                },
 
                /**
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
index 39d1eea..8e6581f 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.StringValue.js
@@ -52,9 +52,19 @@
                 * @see jQuery.valueview.Expert.destroy
                 */
                destroy: function() {
-                       PARENT.prototype.destroy.call( this );
-                       // TODO: destroy input. Should unbind "eachchange" 
event and remove "inputAutoExpand"
-                       //  functionality. Also see valueview.Expert's destroy 
TODO.
+                       if( !this.$input ) {
+                               return; // destroyed already
+                       }
+
+                       var inputExtender = this.$input.data( 'inputextender' );
+                       if( inputExtender ) {
+                               inputExtender.destroy();
+                       }
+
+                       this.$input.off( 'eachchange' );
+                       this.$input = null;
+
+                       PARENT.prototype.destroy.call( this );  // empties 
viewport
                },
 
                /**
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
index 06d0dc2..7935158 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
@@ -245,25 +245,36 @@
                 * @see jQuery.valueview.Expert.destroy
                 */
                destroy: function() {
-                       this.$precision.data( 'listrotator' ).destroy();
-                       this.$precision.remove();
-                       this.$precisionContainer.remove();
+                       if( !this.$input ) {
+                               return; // destroyed already
+                       }
 
-                       this.$calendar.data( 'listrotator' ).destroy();
-                       this.$calendar.remove();
-                       this.$calendarContainer.remove();
+                       if( this.preview ) {
+                               this.preview.destroy();
+                               this.preview.element.remove();
+                       }
 
-                       this.$calendarhint.remove();
+                       var timeInput = this.$input.data( 'timeinput' );
+                       if( timeInput ) {
+                               timeInput.destroy();
+                       }
 
-                       var previewElement = this.preview.element;
-                       this.preview.destroy();
-                       previewElement.remove();
+                       var inputExtender = this.$input.data( 'inputextender' );
+                       if( inputExtender ) {
+                               // Explicitly destroy calendar and precision 
list rotators:
+                               inputExtender.$extension.find( 
':ui-listrotator' ).listrotator( 'destroy' );
+                               inputExtender.destroy();
+                       }
 
-                       this.$input.data( 'inputextender' ).destroy();
-                       this.$input.data( 'timeinput' ).destroy();
-                       this.$input.remove();
+                       this.$input.off( 'eachchange' );
 
-                       PARENT.prototype.destroy.call( this );
+                       this.$input = null;
+                       this.$precision = null;
+                       this.$precisionContainer = null;
+                       this.$calendar = null;
+                       this.$calendarContainer = null;
+
+                       PARENT.prototype.destroy.call( this ); // empties 
viewport
                },
 
                /**
diff --git a/ValueView/resources/jquery.valueview/valueview.valueview.js 
b/ValueView/resources/jquery.valueview/valueview.valueview.js
index fecda82..8ac1ec7 100644
--- a/ValueView/resources/jquery.valueview/valueview.valueview.js
+++ b/ValueView/resources/jquery.valueview/valueview.valueview.js
@@ -168,6 +168,10 @@
                        this._expert = null;
                }
 
+               // TODO: destroying the expert will leave no plain text of the 
last value. Once we
+               //  implemented formatters, think about leaving a formatted 
text here. On the other hand,
+               //  formatting will be assynchronous which would be a problem 
in this situation.
+
                return PARENT.prototype.destroy.call( this );
        },
 
diff --git 
a/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js 
b/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
index 6d4dac0..0e91706 100644
--- a/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
+++ b/ValueView/tests/qunit/jquery.valueview/valueview.tests.testExpert.js
@@ -58,7 +58,7 @@
                        }, {
                                title: 'instance with notifier',
                                args: [
-                                       $( '<div/>' ),
+                                       document.createElement( 'div' ),
                                        new valueview.MockViewState(),
                                        new Notifier()
                                ]
@@ -126,9 +126,32 @@
                        args.expert instanceof valueview.Expert,
                        'expert instance of jQuery.valueview.Expert'
                );
+
+               var viewPortArg = args.constructorArgs[0],
+                       viewPortElement = viewPortArg instanceof $ ? 
viewPortArg.get( 0 ) : viewPortArg;
+
+               assert.ok(
+                       args.expert.$viewPort.get( 0 ) === viewPortElement,
+                       'View port node given to constructor is used as the 
actual view port of the expert'
+               );
        } );
 
-       expertCases.test( 'parser', function( args, assert ) {
+       expertCasesTestAndCleanup( 'destroy', function( args, assert ) {
+               var $viewPort = $( args.constructorArgs[0] );
+
+               args.expert.destroy();
+
+               assert.ok(
+                       $viewPort.children().length === 0 && $viewPort.text() 
=== '',
+                       'Viewport is empty after expert\'s destruction'
+               );
+
+               args.expert.destroy();
+               assert.ok( true, 'Calling destroy() again will not lead to 
unexpected error.' );
+
+       } );
+
+       expertCasesTestAndCleanup( 'parser', function( args, assert ) {
                var valueParser = args.expert.parser();
 
                assert.ok(
@@ -253,16 +276,26 @@
                } );
        } );
 
-       var expertCasesMemberCallTest = function( memberName ) {
-               expertCases.test( memberName, function( args, assert ) {
+       var expertCasesMemberCallTest = function( memberName, 
additionalAssertionsFn ) {
+               expertCasesTestAndCleanup( memberName, function( args, assert ) 
{
                        args.expert[ memberName ]();
                        assert.ok(
                                true,
                                memberName + '() has been called'
                        );
+                       if( additionalAssertionsFn ) {
+                               additionalAssertionsFn( args, assert );
+                       }
                } );
        };
-       expertCasesMemberCallTest( 'draw' );
+       expertCasesMemberCallTest( 'draw', function( args, assert ) {
+               var $viewPort = $( args.constructorArgs[0] );
+
+               assert.ok(
+                       $viewPort.text() !== '' || $viewPort.children.length > 
0,
+                       'Viewport node is not empty after draw()'
+               );
+       } );
        expertCasesMemberCallTest( 'focus' );
        expertCasesMemberCallTest( 'blur' );
 

-- 
To view, visit https://gerrit.wikimedia.org/r/76744
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I634c67b27e30f3b8d3a3202f1908b9752aded7a3
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Daniel Werner <daniel.wer...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to