jenkins-bot has submitted this change and it was merged.

Change subject: snakview: Refactored drawing mechanism
......................................................................


snakview: Refactored drawing mechanism

- untangled draw() / drawProperty() relationship moving Property specific logic 
out of draw()
- drawProperty() does not (re)render when previously generated HTML is detected
- Property, Snak type and Variation are not (re)rendered when they are locked 
and previously
  generated HTML is detected.
- Made updateVariation() public. There is no sense in being able to (re)draw 
the Variation without
  being able to update it.
- Removed parameter from updateVariation() as it is supposed to always reflect 
the current value.
- Removed parameter from drawProperty as it is supposed to always reflect the 
current value.
- Applied Deferred mechanism to functions responsible for drawing the Property 
DOM.

Bug: T88425
Change-Id: If45c707c08ba710fe5fec456fef29c2b60586dae
---
M lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
M lib/resources/jquery.wikibase/snakview/snakview.js
2 files changed, 148 insertions(+), 91 deletions(-)

Approvals:
  Adrian Lang: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
index 0b487bb..d3f1d72 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
@@ -227,7 +227,8 @@
                        autoStartEditing: false,
                        dataTypeStore: this.options.dataTypeStore,
                        entityStore: this.options.entityStore,
-                       valueViewBuilder: this.options.valueViewBuilder
+                       valueViewBuilder: this.options.valueViewBuilder,
+                       encapsulatedBy: ':' + this.widgetFullName.toLowerCase()
                } );
        },
 
diff --git a/lib/resources/jquery.wikibase/snakview/snakview.js 
b/lib/resources/jquery.wikibase/snakview/snakview.js
index 1635e2d..ca328aa 100644
--- a/lib/resources/jquery.wikibase/snakview/snakview.js
+++ b/lib/resources/jquery.wikibase/snakview/snakview.js
@@ -42,6 +42,10 @@
  * @param {dataTypes.DataTypeStore} options.dataTypeStore
  *        Required to retrieve and evaluate a proper `dataTypes.DataType` 
object when interacting on
  *        a "value" `Variation`.
+ * @param {string} [options.encapsulatedBy]
+ *        If the `snakview`s DOM node has a parent that is selectable by the 
provided CSS selector,
+ *        the `Property` part of the `snakview` is not (re-)rendered when 
initializing the
+ *        `snakview` unless the `snakview`s whole DOM structure is empty.
  */
 /**
  * @event afterstartediting
@@ -74,9 +78,9 @@
                template: 'wikibase-snakview',
                templateParams: [ '', '', '' ],
                templateShortCuts: {
-                       '$property': '.wikibase-snakview-property',
-                       '$snakValue': '.wikibase-snakview-value',
-                       '$snakTypeSelector': '.wikibase-snakview-typeselector'
+                       $property: '.wikibase-snakview-property',
+                       $snakValue: '.wikibase-snakview-value',
+                       $snakTypeSelector: '.wikibase-snakview-typeselector'
                },
                value: {
                        snaktype: wb.datamodel.PropertyValueSnak.TYPE
@@ -88,31 +92,9 @@
                autoStartEditing: true,
                entityStore: null,
                valueViewBuilder: null,
-               dataTypeStore: null
+               dataTypeStore: null,
+               encapsulatedBy: null
        },
-
-       /**
-        * The DOM node of the `entityselector` for choosing a `Property` or 
the node with plain text of
-        * the `Property`'s label.
-        * @property {jQuery}
-        * @readonly
-        */
-       $property: null,
-
-       /**
-        * The DOM node of the `Snak`'s value, some message if the value is not 
supported or "no value"/
-        * "some value" message.
-        * @property {jQuery}
-        * @readonly
-        */
-       $snakValue: null,
-
-       /**
-        * The DOM node of the `snaktypeselector` widget.
-        * @type {jQuery}
-        * @readonly
-        */
-       $snakTypeSelector: null,
 
        /**
         * `Variation` object responsible for presenting the essential parts of 
a certain kind of
@@ -162,13 +144,43 @@
 
                this._cachedValues = {};
 
-               this.value( this.options.value );
+               this.updateVariation();
+
+               // Re-render on previously generated DOM should be avoided. 
However, when regenerating the
+               // whole snakview, every component needs to be drawn.
+               var propertyIsEmpty = !this.$property.contents().length,
+                       snakTypeSelectorIsEmpty = 
!this.$snakTypeSelector.contents().length,
+                       snakValueIsEmpty = !this.$snakValue.contents().length;
+
+               if( propertyIsEmpty && !this._isEncapsulated() ) {
+                       this.drawProperty();
+               }
+
+               if( snakTypeSelectorIsEmpty ) {
+                       this.drawSnakTypeSelector();
+               }
+
+               if( snakValueIsEmpty ) {
+                       this.drawVariation();
+               }
 
                if( this.option( 'autoStartEditing' ) && !this.snak() ) {
                        // If no Snak is represented, offer UI to build one.
                        // This clearly implies draw() since it requires visual 
changes!
                        this.startEditing();
                }
+       },
+
+       /**
+        * @private
+        *
+        * @return {boolean}
+        */
+       _isEncapsulated: function() {
+               return !!(
+                       this.options.encapsulatedBy
+                       && this.element.closest( this.options.encapsulatedBy 
).length
+               );
        },
 
        /**
@@ -197,10 +209,7 @@
                var response = PARENT.prototype._setOption.apply( this, 
arguments );
 
                if( key === 'value' ) {
-                       value = this.value();
-
-                       this._updateVariation( value );
-
+                       this.updateVariation();
                        this.draw();
                } else if( key === 'disabled' ) {
                        var propertySelector = this._getPropertySelector(),
@@ -245,7 +254,7 @@
                        // remove out-dated variations
                        if( self._variation ) {
                                self.drawSnakTypeSelector();
-                               self._updateVariation( self.value() );
+                               self.updateVariation();
                                self.drawVariation();
                                self._trigger( 'change' );
                        }
@@ -257,7 +266,7 @@
                        );
 
                        self.options.entityStore.get( entityId ).done( 
function( entity ) {
-                               self._updateVariation( self.value() );
+                               self.updateVariation();
                                self.drawSnakTypeSelector();
                                self.drawVariation();
 
@@ -632,18 +641,15 @@
        },
 
        /**
-        * Checks whether the `Snak` type has been changed by the user and will 
build a new `Variation`
-        * object for that type if necessary.
-        * @private
-        * @since 0.4
-        *
-        * @param {Object} value (In)complete `Snak` serialization.
+        * Updates the `Variation` according to the widget's current value.
+        * @since 0.5
         */
-       _updateVariation: function( value ) {
-               var variationsFactory = $.wikibase.snakview.variations,
+       updateVariation: function() {
+               var value = this.value(),
+                       propertyId = value ? value.property : null,
                        snakType = value ? value.snaktype : null,
-                       VariationConstructor = snakType ? 
variationsFactory.getVariation( snakType ) : null,
-                       propertyId = value ? value.property : null;
+                       variationsFactory = $.wikibase.snakview.variations,
+                       VariationConstructor = snakType ? 
variationsFactory.getVariation( snakType ) : null;
 
                if( this._variation
                        && ( !propertyId || this._variation.constructor !== 
VariationConstructor )
@@ -693,82 +699,136 @@
        },
 
        /**
-        * Renders the `snakview`'s current state considering edit mode, 
current value, etc..
+        * (Re-)renders the widget.
         * @since 0.4
         */
        draw: function() {
-               var self = this,
-                       value = this.value(),
-                       propertyId = value ? value.property : null;
-
-               // NOTE: Order of these shouldn't matter; If for any reasons 
draw functions start changing
-               //  the outcome of the variation (or Snak type), then something 
must be incredibly wrong!
-               if( propertyId ) {
-                       this.options.entityStore.get( propertyId ).done( 
function( fetchedProperty ) {
-                               self.drawProperty(
-                                       fetchedProperty ? 
fetchedProperty.getContent() : null,
-                                       fetchedProperty ? 
fetchedProperty.getTitle() : null
-                               );
-                       } );
-               } else {
-                       this.drawProperty( null, null );
-               }
+               this.drawProperty();
                this.drawSnakTypeSelector();
                this.drawVariation();
        },
 
        /**
-        * Ensures the current `Snak`'s `Property` is displayed properly. If no 
`Snak` is set, the input
-        * form for specifying the `Snak`'s `Property` will be rendered.
-        * @since 0.4
+        * (Re-)renders the Property DOM structure according to the current 
value. The `Property` DOM
+        * is not (re-)rendered if changing the `Property` is locked via the 
`locked` option and
+        * previously generated HTML is detected.
+        * @since 0.5
         *
-        * @param {wikibase.datamodel.Property|null} property
-        * @param {mediawiki.Title|null} title Only supposed to be `null` if 
`property` is `null`.
+        * @return {Object} jQuery.Promise
+        * @return {Function} return.done
+        * @return {Function} return.fail
         */
-       drawProperty: function( property, title ) {
-               var $propertyDom,
-                       value = this.value(),
-                       propertyId = value ? value.property : null;
+       drawProperty: function() {
+               var self = this,
+                       deferred = $.Deferred(),
+                       propertyId = this.value().property;
+
+               if( this.options.locked.property
+                       && ( this.$property.contents().length || 
this._isEncapsulated() )
+               ) {
+                       return deferred.resolve().promise();
+               }
+
+               this._getPropertyDOM( propertyId )
+               .done( function( $property ) {
+                       self.$property.empty().append( $property );
+                       deferred.resolve();
+               } )
+               .fail( function() {
+                       self.$property.empty().text( propertyId );
+                       deferred.reject();
+               } );
+
+               return deferred.promise();
+       },
+
+       /**
+        * Retrieves the DOM structure representing the `Property` of the 
`Snak` represented by the
+        * `snakview`.
+        * @private
+        *
+        * @param {string} [propertyId]
+        * @return {Object} jQuery.Promise
+        * @return {Function} return.done
+        * @return {jQuery} return.$property
+        * @return {Function} return.fail
+        */
+       _getPropertyDOM: function( propertyId ) {
+               var self = this,
+                       deferred = $.Deferred();
+
+               if( propertyId ) {
+                       this.options.entityStore.get( propertyId )
+                       .done( function( fetchedProperty ) {
+                               deferred.resolve( self._createPropertyDOM(
+                                       fetchedProperty ? 
fetchedProperty.getContent() : undefined,
+                                       fetchedProperty ? 
fetchedProperty.getTitle() : undefined
+                               ) );
+                       } )
+                       .fail( deferred.reject );
+               } else {
+                       deferred.resolve( this._createPropertyDOM() );
+               }
+
+               return deferred.promise();
+       },
+
+       /**
+        * Creates the DOM structure specific for a `Property`-`Title` 
combination, a generic DOM
+        * structure or an input element if parameters are omitted.
+        * @private
+        *
+        * @param {wikibase.datamodel.Property} [property] `Property` object or 
`Property` id. Returns
+        *        generic DOM structure if omitted.
+        * @param {mediawiki.Title} [title]
+        * @return {jQuery}
+        */
+       _createPropertyDOM: function( property, title ) {
+               var $propertyDom;
 
                if( this.options.locked.property || !this.isInEditMode() ) {
-                       // property set and can't be changed afterwards, only 
display label
-                       $propertyDom = property
+                       // Property is set already and cannot be changed, 
display label only:
+                       $propertyDom = property instanceof wb.datamodel.Property
                                ? wb.utilities.ui.buildLinkToEntityPage( 
property, title )
                                // shouldn't usually happen, only in non-edit 
mode, while no Snak is set:
-                               : wb.utilities.ui.buildMissingEntityInfo( 
propertyId, wb.datamodel.Property );
+                               : wb.utilities.ui.buildMissingEntityInfo( 
property, wb.datamodel.Property );
                } else {
-                       // no property set for this Snak, serve edit view to 
specify it:
+                       // No Property set for this Snak, serve edit view to 
specify it:
                        var propertySelector = this._getPropertySelector(),
-                               propertyLabel = 
wb.utilities.ui.buildPrettyEntityLabelText( property );
+                               propertyLabel = property instanceof 
wb.datamodel.Property
+                                       ? 
wb.utilities.ui.buildPrettyEntityLabelText( property )
+                                       : property;
 
                        // TODO: use selectedEntity() or other command to set 
selected entity in both cases!
-                       if( propertySelector && property ) {
+                       if( propertySelector ) {
                                // property selector in DOM already, just 
replace current value
                                var currentValue = 
propertySelector.widget().val();
                                // Impose case-insensitivity:
                                if( propertyLabel.toLowerCase() !== 
currentValue.toLocaleLowerCase() ) {
                                        propertySelector.widget().val( 
propertyLabel );
                                }
-                               return;
-                       } else if( !propertySelector ) {
-                               // Create property selector and set value:
+                       } else {
                                $propertyDom = 
this._buildPropertySelector().val( propertyLabel );
 
                                // propagate snakview state:
                                $propertyDom.data( 'entityselector' ).option( 
'disabled', this.options.disabled );
-                       } else {
-                               return;
                        }
                }
 
-               this.$property.empty().append( $propertyDom );
+               return $propertyDom;
        },
 
        /**
-        * Updates the `snaktypeselector` for choosing the `Snak` type.
+        * Updates the `SnakTypeSelector` for choosing the `Snak` type. The 
`SnakTypeSelector` DOM
+        * is not (re-)rendered if changing the `Snak` type is locked via the 
`locked` option and
+        * previously generated HTML is detected.
         * @since 0.4
         */
        drawSnakTypeSelector: function() {
+               if( this.options.locked.snaktype && 
this.$snakTypeSelector.contents().length ) {
+                       return;
+               }
+
                var snakTypes = 
$.wikibase.snakview.variations.getCoveredSnakTypes(),
                        selector = this._getSnakTypeSelector();
 
@@ -801,11 +861,7 @@
                this.$snakTypeSelector[ ( this.value().property ? 'show' : 
'hide' ) ]();
 
                // propagate snakview state:
-               if ( this.options.disabled ) {
-                       selector.disable();
-               } else {
-                       selector.enable();
-               }
+               selector.option( 'disabled', this.options.disabled );
        },
 
        /**
@@ -838,7 +894,7 @@
                                // NOTE: instead of doing this here and 
checking everywhere whether this._variation
                                //  is set, we could as well use variations for 
displaying system messages like
                                //  this, e.g. having a UnsupportedSnakType 
variation which is not registered for a
-                               //  specific snak type but is known to 
_updateVariation().
+                               //  specific snak type but is known to 
updateVariation().
                        }
                }
        },
@@ -863,7 +919,7 @@
 
                // bind user interaction on selector to snakview's state:
                $anchor.on( changeEvent + '.' + this.widgetName, function( 
event ) {
-                       self._updateVariation( self.value() );
+                       self.updateVariation();
                        self.drawVariation();
                        if( self._variation ) {
                                self._variation.focus();

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

Gerrit-MessageType: merged
Gerrit-Change-Id: If45c707c08ba710fe5fec456fef29c2b60586dae
Gerrit-PatchSet: 16
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Henning Snater <[email protected]>
Gerrit-Reviewer: Adrian Lang <[email protected]>
Gerrit-Reviewer: Henning Snater <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to