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