jenkins-bot has submitted this change and it was merged. Change subject: Removed jQuery.wikibase.claimview ......................................................................
Removed jQuery.wikibase.claimview As the concept of Claim is to be removed (see https://github.com/wmde/WikibaseDataModel/pull/317), this change removes the corresponding UI concept of claimview and decreases complexity resulting from statementview having to encapsulate claimview while claimview should need to remain an independent widget (as long as there is Claim in the data model). There is no reason to have the concept of claimview, nor the term claim at all remain in the front-end. The change anticipates the data model change by merging main snak and qualifiers related functionality from claimview into statementview. Requires adjusting the browser tests: https://github.com/wmde/WikidataBrowserTests/pull/35 Change-Id: I4060c1f9ff56970e69a59b85ca716848f3dcef53 --- M lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplabelscroll.js M lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js M lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js D lib/resources/jquery.wikibase/jquery.wikibase.claimview.js M lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js M lib/resources/jquery.wikibase/jquery.wikibase.statementview.js M lib/resources/jquery.wikibase/resources.php M lib/resources/jquery.wikibase/toolbar/jquery.wikibase.edittoolbar.js M lib/resources/wikibase.css D lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js M lib/tests/qunit/jquery.wikibase/resources.php M repo/includes/View/ClaimHtmlGenerator.php M repo/resources/templates.php 14 files changed, 1,005 insertions(+), 1,619 deletions(-) Approvals: Thiemo Mättig (WMDE): Looks good to me, approved jenkins-bot: Verified diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplabelscroll.js b/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplabelscroll.js index ae19b6d..4430f6e 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplabelscroll.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplabelscroll.js @@ -114,8 +114,9 @@ expensiveChecks = 0; - var $visibleClaims = - findFirstVisibleMainSnakElementsWithinClaimList( this.element ).closest( '.wb-claim' ); + var $visibleClaims + = findFirstVisibleMainSnakElementsWithinClaimList( this.element ) + .closest( '.wikibase-statementview' ); for( var i = 0; i < $visibleClaims.length; i++ ) { var $visibleClaim = $visibleClaims.eq( i ), @@ -206,7 +207,8 @@ // Caring about the visibility of ".wb-snak-value-container" is better than about ".wb-statement" // or ".wb-claim-mainsnak" since the label will align with the .wb-snak-value-container. - var $mainSnaks = $searchRange.find( '.wb-claim-mainsnak .wb-snak-value-container' ); + var $mainSnaks + = $searchRange.find( '.wikibase-statementview-mainsnak .wb-snak-value-container' ); $mainSnaks.each( function( i, mainSnakNode ) { // Take first Main Snak value in viewport. If value is not fully visible in viewport, @@ -229,7 +231,7 @@ if( result ) { // Don't forget to get the actual Snak node rather than the value container. - result = $( result ).closest( '.wb-claim-mainsnak'); + result = $( result ).closest( '.wikibase-statementview-mainsnak'); } return result; } diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js b/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js index 8f4e372..7a63d38 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js @@ -96,9 +96,9 @@ .on( startEditingEvent, function( event ) { self._addGroupTitleClass( $( event.target ), 'wb-edit' ); } ) - .on( afterRemoveEvent, function( event, value, $claimview ) { + .on( afterRemoveEvent, function( event ) { // Check whether the whole claimlistview may be removed from the claimgrouplistview if - // the last claimview has been removed from the claimlistview. + // the last statementview has been removed from the claimlistview. var $claimlistview = $( event.target ), claimlistview = lia.liInstance( $claimlistview ); @@ -439,7 +439,7 @@ // There should be separate toolbars for managing the content of these two widgets. $.wikibase.toolbarcontroller.definition( 'movetoolbar', { id: 'claimlistview-claimview', - selector: '.wb-claimview', + selector: '.wikibase-statementview', events: { 'claimviewstartediting statementviewstartediting': function( event, toolbarController ) { // Initialize movetoolbar. diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js b/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js index f4f5244..a84f1fc 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js @@ -14,7 +14,7 @@ * * @option {wikibase.datamodel.ClaimGroup|wikibase.datamodel.StatementGroup} [value] * The list of statements to be displayed by this view. If null, the view will initialize an - * empty claimview with edit mode started. + * empty statementview with edit mode started. * Default: null * * @option {wb.store.EntityStore} entityStore @@ -443,15 +443,11 @@ } claimlistview.enterNewItem().done( function( $view ) { - $view.one( - 'claimviewafterstartediting.addtoolbar ' - + 'statementviewafterstartediting.addtoolbar', - function() { - var listview = claimlistview.$listview.data( 'listview' ), - lia = listview.listItemAdapter(); - lia.liInstance( $view ).focus(); - } - ); + $view.one( 'statementviewafterstartediting.addtoolbar', function() { + var listview = claimlistview.$listview.data( 'listview' ), + lia = listview.listItemAdapter(); + lia.liInstance( $view ).focus(); + } ); } ); // Re-focus "add" button after having added or having cancelled adding a statement: diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js b/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js deleted file mode 100644 index 6f1bc70..0000000 --- a/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js +++ /dev/null @@ -1,1099 +0,0 @@ -/** - * - * @licence GNU GPL v2+ - * @author Daniel Werner < daniel.wer...@wikimedia.de > - * @author H. Snater < mediaw...@snater.com > - */ -( function( mw, wb, $ ) { - 'use strict'; - - var PARENT = $.ui.TemplatedWidget; - -/** - * View for displaying and editing Wikibase Claims. - * @since 0.3 - * @extends jQuery.ui.TemplatedWidget - * - * @option {wb.datamodel.Claim|null} value The claim displayed by this view. This can only be set initially, - * the value function doesn't work as a setter in this view. If this is null, this view will - * start in edit mode, allowing the user to define the claim. - * - * @option {wb.store.EntityStore} entityStore - * - * @option {wikibase.ValueViewBuilder} valueViewBuilder - * - * @option {wikibase.entityChangers.ClaimsChanger} [claimsChanger] If not passed, claimview does not save. - * - * @option {dataTypes.DataTypeStore} dataTypeStore - * - * @option {number|null} index The claim's index within the list of claims (if the claim is - * contained within such a list). - * Default: null - * TODO: This option should be removed and a proper mechanism independent from claimview - * should be implemented to manage and store the indices of claims (bug #56050). - * - * @option {Object} predefined Allows to pre-define certain aspects of the Claim to be created. - * Basically, when creating a new Claim, what really is created first is the Main Snak. So, - * this requires a field 'mainSnak' which can have all fields which can be defined in - * jQuery.snakview's option 'predefined'. E.g. "predefined.mainSnak.property = 'q42'" - * TODO: also allow pre-defining aspects of qualifiers. Implementation and whether this - * makes sense here might depend on whether we will have one or several edit buttons. - * - * @option {Object} locked Elements that shall be locked (disabled). - * - * @option {string} helpMessage End-user message explaining how to use the claimview widget. The - * message is most likely to be used inside the tooltip of the toolbar corresponding to - * the claimview. - * - * @event startediting: Triggered when starting the Claim's edit mode. - * (1) {jQuery.Event} - * - * @event afterstartediting: Triggered after having started the Claim's edit mode. - * (1) {jQuery.Event} - * - * @event stopediting: Triggered when stopping the Claim's edit mode. - * (1) {jQuery.Event} - * (2) {boolean} If true, the value from before edit mode has been started will be reinstated - * (basically a cancel/save switch). - * - * @event afterstopediting: Triggered after having stopped the Claim's edit mode. - * (1) {jQuery.Event} - * (2) {boolean} If true, the value from before edit mode has been started will be reinstated - * (basically a cancel/save switch). - * - * @event change: Triggered whenever the claimview's content is changed. - * (1) {jQuery.Event} event - * - * @event toggleerror: Triggered when an error occurred or is resolved. - * (1) {jQuery.Event} event - * (2) {wikibase.api.RepoApiError|undefined} RepoApiError object if an error occurred, undefined if - * the current error state is resolved. - */ -$.widget( 'wikibase.claimview', PARENT, { - /** - * (Additional) default options - * @see jQuery.Widget.options - */ - options: { - template: 'wb-claim', - templateParams: [ - function() { // class='wb-claim-$1' - return ( this._claim && this._claim.getGuid() ) || 'new'; - }, - function() { - return $( '<div/>' ); - }, // .wb-claim-mainsnak - '' // Qualifiers - ], - templateShortCuts: { - '$mainSnak': '.wb-claim-mainsnak > :first-child', - '$qualifiers': '.wb-claim-qualifiers' - }, - value: null, - dataTypeStore: null, - entityStore: null, - valueViewBuilder: null, - claimsChanger: null, - predefined: { - mainSnak: false - }, - locked: { - mainSnak: false - }, - index: null, - helpMessage: mw.msg( 'wikibase-claimview-snak-new-tooltip' ) - }, - - /** - * The node representing the main snak, displaying it in a jQuery.snakview - * @type jQuery - */ - $mainSnak: null, - - /** - * The claim represented by this view or null if this is a view for a user to enter a new claim. - * @type wb.datamodel.Claim|null - */ - _claim: null, - - /** - * Reference to the listview widget managing the qualifier snaklistviews. Basically, just a - * short-cut for this.$qualifiers.data( 'listview' ) - * @type {$.wikibase.listview} - */ - _qualifiers: null, - - /** - * Caches the snak list of the qualifiers the claimview has been initialized with. The - * qualifiers are split into groups featuring the same property. Removing one of those groups - * results in losing the reference to those qualifiers. Therefore, _initialQualifiers is used - * to rebuild the list of qualifiers when cancelling and is used to query whether the qualifiers - * represent the initial state. - * @type {wb.datamodel.SnakList} - */ - _initialQualifiers: null, - - /** - * Whether the Claim is currently in edit mode. - * @type {boolean} - */ - _isInEditMode: false, - - /** - * The claim's initial index within the list of claims (if it is contained within a list of - * claims). The initial index is stored to be able to detect whether the index has changed and - * the claim does not feature its initial value. - * @type {number|null} - */ - _initialIndex: null, - - /** - * @see jQuery.Widget._create - * - * @throws {Error} if any required option is not specified. - */ - _create: function() { - if( - !this.options.entityStore - || !this.options.valueViewBuilder - ) { - throw new Error( 'Required option(s) missing' ); - } - - var self = this; - this._claim = this.option( 'value' ); - - // call template creation, this will require this._claim in template params callback! - PARENT.prototype._create.call( this ); - - // set up event listeners: - this.$mainSnak - .on( - [ - 'snakviewchange.' + this.widgetName, - 'snakviewafterstartediting.' + this.widgetName - ].join( ' ' ), - function( event, status ) { - self._trigger( 'change' ); - } - ); - - this.$mainSnak.snakview( { - value: this.mainSnak() || {}, - locked: this.option( 'locked' ).mainSnak, - autoStartEditing: false, // manually, after toolbar is there, so events can access toolbar - dataTypeStore: this.option( 'dataTypeStore' ), - entityStore: this.options.entityStore, - valueViewBuilder: this.option( 'valueViewBuilder' ) - } ); - - this._initialIndex = this.option( 'index' ); - - // Initialize qualifiers: - this._initialQualifiers = ( this._claim ) ? this._claim.getQualifiers() : new wb.datamodel.SnakList(); - - if( this._claim && this._initialQualifiers.length ) { // TODO: Allow adding qualifiers when adding a new claim. - // Group qualifiers by property id: - this._createQualifiersListview( this._initialQualifiers ); - } - - if ( this._claim || this.options.predefined.mainSnak ) { - var property = this._claim - ? this.mainSnak().getPropertyId() - : this.options.predefined.mainSnak.property; - - var deferred = $.Deferred(); - var helpMessage = this.options.helpMessage; - this.options.helpMessage = deferred.promise(); - - if( property ) { - this.options.entityStore.get( property ).done( function( fetchedProperty ) { - if( fetchedProperty ) { - helpMessage = mw.msg( - 'wikibase-claimview-snak-tooltip', - wb.utilities.ui.buildPrettyEntityLabelText( fetchedProperty.getContent() ) - ); - } - deferred.resolve( helpMessage ); - } ); - } else { - deferred.resolve( helpMessage ); - } - } - }, - - /** - * Creates the listview widget containing the qualifier snaklistview widgets. Omitting - * qualifiers parameter generates an empty list widget. - * @since 0.4 - * - * @param {wb.datamodel.SnakList} [qualifiers] - */ - _createQualifiersListview: function( qualifiers ) { - var self = this, - groupedQualifierSnaks = null; - - // Group qualifiers by property id: - if( qualifiers && qualifiers.length ) { - var propertyIds = qualifiers.getPropertyOrder(); - - groupedQualifierSnaks = []; - - for( var i = 0; i < propertyIds.length; i++ ) { - groupedQualifierSnaks.push( qualifiers.getFilteredSnakList( propertyIds[i] ) ); - } - } - - // Using the property id, qualifier snaks are split into groups of snaklistviews. These - // snaklistviews are managed in a listview: - var $qualifiers = this.$qualifiers.children(); - if( !$qualifiers.length ) { - $qualifiers = $( '<div/>' ).prependTo( this.$qualifiers ); - } - $qualifiers.listview( { - listItemAdapter: new $.wikibase.listview.ListItemAdapter( { - listItemWidget: $.wikibase.snaklistview, - newItemOptionsFn: function( value ) { - return { - value: value || null, - singleProperty: true, - dataTypeStore: self.option( 'dataTypeStore' ), - entityStore: self.option( 'entityStore' ), - valueViewBuilder: self.option( 'valueViewBuilder' ) - }; - } - } ), - value: groupedQualifierSnaks - } ) - .on( 'snaklistviewchange.' + this.widgetName - + ' listviewafteritemmove.' + this.widgetName, - function( event ) { - self._trigger( 'change' ); - } - ) - .on( 'listviewitemremoved.' + this.widgetName, function( event, value, $itemNode ) { - if( event.target === self._qualifiers.element.get( 0 ) ) { - self._trigger( 'change' ); - return; - } - - // Check if last snaklistview of a qualifier listview item has been removed and - // remove the listview item if so: - var $snaklistview = $( event.target ).closest( ':wikibase-snaklistview' ), - snaklistview = $snaklistview.data( 'snaklistview' ); - - if( !snaklistview.value() ) { - self._qualifiers.removeItem( snaklistview.element ); - } - } ); - - this._qualifiers = $qualifiers.data( 'listview' ); - }, - - /** - * Destroys the listview widget containing the qualifier snaklistview widgets. - */ - _destroyQualifiersListView: function() { - if( this._qualifiers ) { - this._qualifiers.destroy(); - this.$qualifiers.empty(); - this._qualifiers = null; - } - }, - - /** - * @see jQuery.Widget.option - * - * @triggers change - */ - option: function( key, value ) { - if( value === this.options[key] ) { - return this; - } - - var self = PARENT.prototype.option.apply( this, arguments ); - - if( key === 'index' && value !== undefined ) { - this._trigger( 'change' ); - } - - return self; - }, - - /** - * Returns the claim's initial index within the list of claims (if in any). - * @since 0.5 - * - * @return {number|null} - */ - getInitialIndex: function() { - return this._initialIndex; - }, - - /** - * Returns whether the claimview is valid according to its current contents. An empty value - * will be considered not valid (also, an empty value can not be saved). - * @since 0.4 - * - * @return {boolean} - */ - isValid: function() { - // Validate qualifiers: - if( this._qualifiers ) { - var snaklistviews = this._qualifiers.value(); - - if( snaklistviews.length ) { - for( var i = 0; i < snaklistviews.length; i++ ) { - if( !snaklistviews[i].isValid() ) { - return false; - } - } - } - } - - try { - this._instantiateClaim( null ); - } catch( e ) { - return false; - } - - return true; - }, - - /** - * Returns whether the current value of this claim (including the qualifiers) equals the value - * the claim has been initialized with. - * @since 0.4 - * - * @return {boolean} - */ - isInitialValue: function() { - if( this.option( 'index' ) !== this._initialIndex ) { - return false; - } - - if( this._claim ) { - var snaklistviews = ( this._qualifiers ) ? this._qualifiers.value() : [], - qualifiers = new wb.datamodel.SnakList(); - - // Generate a SnakList object featuring all current qualifier snaks to be able to - // compare it to the SnakList object the claimview has been initialized with: - if( snaklistviews.length ) { - for( var i = 0; i < snaklistviews.length; i++ ) { - if( snaklistviews[i].value() ) { - qualifiers.merge( snaklistviews[i].value() ); - } - } - } - - if( !qualifiers.equals( this._initialQualifiers ) ) { - return false; - } - } - - return this.$mainSnak.data( 'snakview' ).isInitialSnak(); - }, - - /** - * Starts the Claim's edit mode. - * @since 0.4 - * - * @return {undefined} (allows chaining widget calls) - */ - startEditing: $.NativeEventHandler( 'startEditing', { - // don't start edit mode or trigger event if in edit mode already: - initially: function( e ) { - if( this.isInEditMode() ) { - e.cancel(); - } - }, - // start edit mode if event doesn't prevent default: - natively: function( e ) { - var self = this; - - this.$mainSnak.one( 'snakviewafterstartediting', function() { - if( !self._qualifiers && self._claim ) { - self._createQualifiersListview(); - } - - // Start edit mode of all qualifiers: - if( self._qualifiers ) { - var snaklistviews = self._qualifiers.value(); - if( snaklistviews.length ) { - for( var i = 0; i < snaklistviews.length; i++ ) { - snaklistviews[i].startEditing(); - } - } - // If there are no snaklistviews, there is no way for the "add qualifier" toolbar - // to be - self._qualifiers.element.trigger( 'qualifiersstartediting' ); - } - - - self.element.addClass( 'wb-edit' ); - self._isInEditMode = true; - - self._trigger( 'afterstartediting' ); - } ); - - this.$mainSnak.data( 'snakview' ).startEditing(); - } - } ), - - /** - * Exits the Claim's edit mode. - * @since 0.4 - * - * @param {boolean} [dropValue] If true, the value from before edit mode has been started will - * be reinstated - basically a cancel/save switch. "false" by default. Consider using - * cancelEditing() instead. - * @return {undefined} (allows chaining widget calls) - */ - stopEditing: $.NativeEventHandler( 'stopEditing', { - // don't stop edit mode or trigger event if not in edit mode currently: - initially: function( e, dropValue ) { - if ( - !this.isInEditMode() || ( !this.isValid() || this.isInitialValue() ) && !dropValue - ) { - e.cancel(); - } - - this.element.removeClass( 'wb-error' ); - }, - // stop edit mode if custom event handlers didn't prevent default: - natively: function( e, dropValue ) { - var self = this; - - this.disable(); - - if ( dropValue ) { - if ( this.$mainSnak.data( 'snakview' ) ) { - this.$mainSnak.data( 'snakview' ).stopEditing( dropValue ); - } - - this._stopEditingQualifiers( dropValue ); - - self.enable(); - self.element.removeClass( 'wb-edit' ); - self._isInEditMode = false; - - self._trigger( 'afterstopediting', null, [ dropValue ] ); - } else { - // editing an existing claim - self._saveClaimApiCall() - .done( function( savedClaim ) { - self.$mainSnak.data( 'snakview' ).stopEditing( dropValue ); - - self._stopEditingQualifiers( dropValue ); - - self.enable(); - - if ( !self._claim ) { - // claim must be newly entered, create a new claim: - self._claim = new wb.datamodel.Claim( - self.$mainSnak.data( 'snakview' ).value() - ); - } - - self.element.removeClass( 'wb-edit' ); - self._isInEditMode = false; - - // transform toolbar and snak view after save complete - self._trigger( 'afterstopediting', null, [ dropValue ] ); - } ) - .fail( function( error ) { - self.enable(); - self.setError( error ); - } ); - } - } - } ), - - /** - * Stops editing of the qualifiers listview. - * @since 0.4 - * - * @param {boolean} dropValue - */ - _stopEditingQualifiers: function( dropValue ) { - var snaklistviews, - i; - - if( this._qualifiers ) { - snaklistviews = this._qualifiers.value(); - - if( !dropValue ) { - // When saving the qualifier snaks, reset the initial qualifiers to the new ones. - this._initialQualifiers = new wb.datamodel.SnakList(); - } - - if( snaklistviews.length ) { - for( i = 0; i < snaklistviews.length; i++ ) { - snaklistviews[i].stopEditing( dropValue ); - - if( dropValue && !snaklistviews[i].value() ) { - // Remove snaklistview from qualifier listview if no snakviews are left in - // that snaklistview: - this._qualifiers.removeItem( snaklistviews[i].element ); - } else if ( !dropValue ) { - // Gather all the current snaks in a single SnakList to set to reset the - // initial qualifiers: - this._initialQualifiers.merge( snaklistviews[i].value() ); - } - } - } - } - - // Destroy and (if qualifiers still exist) re-create the qualifier listview in order to - // re-group the qualifiers by their property. This will also send out the event to erase - // the "add qualifier" toolbar. - this._destroyQualifiersListView(); - - if( this._initialQualifiers.length > 0 ) { - // Refill the qualifier listview with the initial (or new initial) qualifiers: - this._createQualifiersListview( this._initialQualifiers ); - } - }, - - /** - * Short-cut for stopEditing( false ). Exits edit mode and restores the value from before the - * edit mode has been started. - * @since 0.4 - * - * @return {undefined} (allows chaining widget calls) - */ - cancelEditing: function() { - return this.stopEditing( true ); // stop editing and drop value - }, - - /** - * Returns whether the Claim is editable at the moment. - * @since 0.4 - * - * @return {boolean} - */ - isInEditMode: function() { - return this._isInEditMode; - }, - - /** - * Instantiates a claim with the claimview's current value. - * @since 0.4 - * - * @param {string} guid - * @return {wb.datamodel.Claim} - * @throws {Error} In case the widget's current value is insufficient for building a claim. - */ - _instantiateClaim: function( guid ) { - var qualifiers = new wb.datamodel.SnakList(), - snaklistviews = this._qualifiers ? this._qualifiers.value() : []; - - // Combine qualifiers grouped by property to a single SnakList: - for( var i = 0; i < snaklistviews.length; i++ ) { - qualifiers.merge( snaklistviews[i].value() ); - } - - return new wb.datamodel.Claim( - this.$mainSnak.data( 'snakview' ).snak(), - qualifiers, - guid - ); - }, - - /** - * Triggers the API call to save the claim. - * @since 0.4 - * - * @return {jQuery.Promise} - */ - _saveClaimApiCall: function() { - var self = this, - guid, - claimsChanger = this.option( 'claimsChanger' ); - - if ( this.value() ) { - guid = this.value().getGuid(); - } else { - var guidGenerator = new wb.utilities.ClaimGuidGenerator(); - guid = guidGenerator.newGuid( mw.config.get( 'wbEntityId' ) ); - } - - if( !claimsChanger ) { - // Don't save if we are not responsible for saving - this._claim = this._instantiateClaim( guid ); - return $.Deferred().resolve().promise(); - } - - return claimsChanger.setClaim( - this._instantiateClaim( guid ), - this.option( 'index' ) - ) - .done( function( savedClaim ) { - // Update model of represented Claim: - self._claim = savedClaim; - } ); - }, - - /** - * Sets/removes error state from the widget. - * @since 0.4 - * - * @param {wikibase.api.RepoApiError} [error] - */ - setError: function( error ) { - if ( error ) { - this.element.addClass( 'wb-error' ); - this._trigger( 'toggleerror', null, [ error ] ); - } else { - this.element.removeClass( 'wb-error' ); - this._trigger( 'toggleerror' ); - } - }, - - /** - * @see $.widget.destroy - */ - destroy: function() { - this.$mainSnak.snakview( 'destroy' ); - this.$mainSnak.off( '.' + this.widgetName ); - PARENT.prototype.destroy.call( this ); - }, - - /** - * Returns the current Claim represented by the view. If null is returned, than this is a - * fresh view where a new Claim is being constructed. - * @since 0.3 - * - * @return wb.datamodel.Claim|null - */ - value: function() { - return this._claim; - }, - - /** - * Returns the current Claim's main snak or null if no Claim is represented by the view - * currently (because Claim not yet constructed). This is a short cut to value().getMainSnak(). - * - * NOTE: this function has been introduced for the big referenceview hack, where we let the - * referenceview widget inherit from the claimview until qualifiers will be implemented - and - * therefore a more generic base widget which will serve as base for both - claimview and - * referenceview. - * - * @deprecated Use .value() instead. - * - * @since 0.4 - * - * @return wb.datamodel.Snak|null - */ - mainSnak: function() { - return this._claim - ? this._claim.getMainSnak() - : ( this.option( 'predefined' ).mainSnak || null ); - }, - - /** - * @see jQuery.Widget._setOption - */ - _setOption: function( key, value ) { - if( key === 'value' ) { - throw new Error( 'Can not set value after initialization' ); - } - - var response = PARENT.prototype._setOption.apply( this, arguments ); - - if( key === 'disabled' ) { - this.$mainSnak.data( 'snakview' ).option( key, value ); - if( this._qualifiers ) { - this._qualifiers.option( key, value ); - } - } - - return response; - }, - - /** - * @see jQuery.ui.TemplatedWidget.focus - */ - focus: function() { - this.$mainSnak.data( 'snakview' ).focus(); - } -} ); - -// Register toolbars: -$.wikibase.toolbarcontroller.definition( 'addtoolbar', { - id: 'claim-qualifiers-snak', - selector: '.wb-claim-qualifiers', - events: { - 'listviewcreate snaklistviewstartediting': function( event, toolbarController ) { - var $target = $( event.target ), - $qualifiers = $target.closest( '.wb-claim-qualifiers' ), - listview = $target.closest( ':wikibase-listview' ).data( 'listview' ), - listviewInited = event.type === 'listviewcreate' && listview.items().length === 0; - - if( - ( listviewInited || event.type === 'snaklistviewstartediting' ) - && !$qualifiers.data( 'addtoolbar' ) - ) { - $qualifiers - .addtoolbar( { - $container: $( '<div/>' ).appendTo( $qualifiers ), - label: mw.msg( 'wikibase-addqualifier' ) - } ) - .off( '.addtoolbar' ) - .on( 'addtoolbaradd.addtoolbar', function( e ) { - listview.enterNewItem().done( function( $snaklistview ) { - var snaklistview = listview.listItemAdapter().liInstance( $snaklistview ); - snaklistview.enterNewItem().done( function( $snakview ) { - var snaklistviewListview = snaklistview.$listview.data( 'listview' ), - lia = snaklistviewListview.listItemAdapter(); - lia.liInstance( $snakview ).focus(); - } ); - } ); - } ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'listviewdestroy snaklistviewafterstopediting', - function( event, toolbarcontroller ) { - var $target = $( event.target ), - $qualifiers = $target.closest( '.wb-claim-qualifiers' ); - - if( $target.parent().get( 0 ) !== $qualifiers.get( 0 ) ) { - // Not the qualifiers main listview. - return; - } - - toolbarcontroller.destroyToolbar( $qualifiers.data( 'addtoolbar' ) ); - } - ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'snaklistviewchange', - function( event ) { - var $target = $( event.target ), - $qualifiers = $target.closest( '.wb-claim-qualifiers' ), - addToolbar = $qualifiers.data( 'addtoolbar' ), - $listview = $target.closest( ':wikibase-listview' ), - snaklistviews = $listview.data( 'listview' ).value(); - - if( addToolbar ) { - addToolbar.enable(); - for( var i = 0; i < snaklistviews.length; i++ ) { - if( !snaklistviews[i].isValid() ) { - addToolbar.disable(); - break; - } - } - } - } - ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - // FIXME: When there are qualifiers, no state change events will be thrown. - 'listviewdisable', - function( event ) { - var $qualifiers = $( event.target ).closest( '.wb-claim-qualifiers' ), - addToolbar = $qualifiers.data( 'addtoolbar' ), - $claimview = $qualifiers.closest( ':wikibase-claimview' ), - claimview = $claimview.data( 'claimview' ); - - // Toolbar might be removed from the DOM already after having stopped edit - // mode. - if( addToolbar ) { - addToolbar[claimview.option( 'disabled' ) ? 'disable' : 'enable'](); - } - } - ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'listviewitemadded listviewitemremoved', - function( event ) { - // Enable "add" link when all qualifiers have been removed: - var $listviewNode = $( event.target ), - listview = $listviewNode.data( 'listview' ), - $snaklistviewNode = $listviewNode.closest( '.wb-snaklistview' ), - snaklistview = $snaklistviewNode.data( 'snaklistview' ), - addToolbar = $snaklistviewNode.data( 'addtoolbar' ); - - // Toolbar is not within the DOM when (re-)constructing the list in non-edit-mode. - if( !addToolbar ) { - return; - } - - // Disable "add" toolbar when the last qualifier has been removed: - if( !snaklistview.isValid() && listview.items().length ) { - addToolbar.disable(); - } else { - addToolbar.enable(); - } - } - ); - - } - } - } -} ); - -$.wikibase.toolbarcontroller.definition( 'removetoolbar', { - id: 'claim-qualifiers-snak', - selector: '.wb-claim-qualifiers', - events: { - 'snakviewstartediting': function( event, toolbarController ) { - var $snakview = $( event.target ), - $snaklistview = $snakview.closest( '.wb-snaklistview' ), - snaklistview = $snaklistview.data( 'snaklistview' ); - - if( !snaklistview ) { - return; - } - - var qualifierPorpertyGroupListview = snaklistview._listview; - - // Create toolbar for each snakview widget: - $snakview - .removetoolbar( { - $container: $( '<div/>' ).appendTo( $snakview ) - } ) - .on( 'removetoolbarremove.removetoolbar', function( event ) { - if( event.target === $snakview.get( 0 ) ) { - qualifierPorpertyGroupListview.removeItem( $snakview ); - } - } ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'snaklistviewafterstopediting', - function( event, toolbarcontroller ) { - // Destroy the snakview toolbars: - var $snaklistviewNode = $( event.target ), - listview = $snaklistviewNode.data( 'snaklistview' )._listview, - lia = listview.listItemAdapter(); - - $.each( listview.items(), function( i, item ) { - var snakview = lia.liInstance( $( item ) ); - toolbarcontroller.destroyToolbar( snakview.element.data( 'removetoolbar' ) ); - } ); - } - ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'snaklistviewdisable', - function( event ) { - var $snaklistviewNode = $( event.target ), - listview = $snaklistviewNode.data( 'snaklistview' )._listview, - lia = listview.listItemAdapter(), - $claimview = $snaklistviewNode.closest( ':wikibase-claimview' ), - claimview = $claimview.data( 'claimview' ); - - $.each( listview.items(), function( i, node ) { - var $snakview = $( node ), - snakview = lia.liInstance( $snakview ), - removeToolbar = $snakview.data( 'removetoolbar' ); - - // Item might be about to be removed not being a list item instance. - if( !snakview || !removeToolbar ) { - return; - } - - $snakview.data( 'removetoolbar' )[claimview.option( 'disabled' ) - ? 'disable' - : 'enable' - ](); - } ); - } - ); - - } - } -} ); - -$.wikibase.toolbarcontroller.definition( 'movetoolbar', { - id: 'claim-qualifiers-snak', - selector: '.wb-claim-qualifiers', - events: { - 'snakviewstartediting': function( event, toolbarController ) { - var $snakview = $( event.target ), - $snaklistview = $snakview.closest( ':wikibase-snaklistview' ), - snaklistview = $snaklistview.data( 'snaklistview' ); - - if( !snaklistview ) { - return; - } - - var $listview = $snaklistview.closest( ':wikibase-listview' ); - - if( !$listview.parent().hasClass( 'wb-claim-qualifiers' ) ) { - return; - } - - var listview = $listview.data( 'listview' ); - - if( $snaklistview.data( 'snaklistview' ).value() !== null ) { - // Create toolbar for each snakview widget: - $snakview.movetoolbar( { - $container: $( '<div/>' ).appendTo( $snakview ) - } ); - - var $topMostSnakview = listview.items().first().data( 'snaklistview' ) - ._listview.items().first(); - var $bottomMostSnakview = listview.items().last().data( 'snaklistview' ) - ._listview.items().last(); - - if ( $topMostSnakview.get( 0 ) === $snakview.get( 0 ) ) { - $snakview.data( 'movetoolbar' ).getButton( 'up' ).disable(); - } - - if( $bottomMostSnakview.get( 0 ) === $snakview.get( 0 ) ) { - $snakview.data( 'movetoolbar' ).getButton( 'down' ).disable(); - } - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'snaklistviewafterstopediting', - function( event, toolbarcontroller ) { - // Destroy the snakview toolbars: - var $snaklistviewNode = $( event.target ), - listview = $snaklistviewNode.data( 'snaklistview' )._listview, - lia = listview.listItemAdapter(); - - $.each( listview.items(), function( i, item ) { - var snakview = lia.liInstance( $( item ) ); - toolbarcontroller.destroyToolbar( snakview.element.data( 'movetoolbar' ) ); - } ); - - // Remove obsolete event handlers attached to the node the toolbarcontroller has been - // initialized on: - $snaklistviewNode.closest( '.wb-claim-qualifiers' ).off( '.movetoolbar' ); - } - ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'movetoolbarup movetoolbardown', - function( event ) { - var $snakview = $( event.target ), - $snaklistview = $snakview.closest( ':wikibase-snaklistview' ); - - if( !$snaklistview.length ) { - // Unrelated "move" action. - return; - } - - var snaklistview = $snaklistview.data( 'snaklistview' ), - snaklistviewListview = snaklistview.$listview.data( 'listview' ), - snaklistviewListviewLia = snaklistviewListview.listItemAdapter(), - snak = snaklistviewListviewLia.liInstance( $snakview ).snak(), - snakList = snaklistview.value(), - $listview = $snaklistview.closest( ':wikibase-listview' ), - listview = $listview.data( 'listview' ), - action = ( event.type === 'movetoolbarup' ) ? 'moveUp' : 'moveDown'; - - if( action === 'moveUp' && snakList.indexOf( snak ) !== 0 ) { - // Snak is not in top of the snaklistview group the snaks featuring the same - // property. Therefore, the snak is to be moved within the snaklistview. - snaklistview.moveUp( snak ); - } else if( action === 'moveDown' && snakList.indexOf( snak ) !== snakList.length - 1 ) { - // Move down snakview within a snaklistview. - snaklistview.moveDown( snak ); - } else { - // When issuing "move up" on a snak on top of a snak list, the whole snaklistview - // has to be move; Same for "move down" on a snak at the bottom of a snak list. - listview[action]( $snaklistview ); - } - } - ); - - toolbarController.registerEventHandler( - event.data.toolbar.type, - event.data.toolbar.id, - 'movetoolbarup movetoolbardown listviewitemadded listviewitemremoved', - function( event ) { - // Disable "move up" button of the topmost snakview of the topmost snaklistview and the - // "move down" button of the bottommost snakview of the bottommost snaklistview. All - // other buttons shall be enabled. - var $target = $( event.target ), - $claimview = $target.closest( ':wikibase-claimview' ), - claimview = $claimview.data( 'claimview' ), - listview; - - if( event.type.indexOf( 'listview' ) !== 0 ) { - var $snaklistview = $target.closest( ':wikibase-snaklistview' ), - $listview = $snaklistview.closest( ':wikibase-listview' ); - listview = $listview.data( 'listview' ); - } else if( !$target.parent().hasClass( 'wb-claim-qualifiers' ) ) { - // Do not react on snaklistview's listview event. - return; - } else { - listview = $target.data( 'listview' ); - } - - if( !listview ) { - // Unrelated "move" action. - return; - } - - var listviewItems = listview.items(); - - listviewItems.each( function( i, snaklistviewNode ) { - var snaklistview = $( snaklistviewNode ).data( 'snaklistview' ); - - if( !snaklistview || !snaklistview.value() || !snaklistview.isInEditMode() ) { - // Pending snaklistview: Remove the preceding "move down" button if it exists: - return; - } - - var snaklistviewItems = snaklistview._listview.items(); - - snaklistviewItems.each( function( j, snakviewNode ) { - var $snakview = $( snakviewNode ), - movetoolbar = $snakview.data( 'movetoolbar' ); - - // Pending snakviews do not feature a movetoolbar. - if( movetoolbar ) { - var btnUp = movetoolbar.getButton( 'up' ), - btnDown = movetoolbar.getButton( 'down' ), - isOverallFirst = ( i === 0 && j === 0 ), - isLastInSnaklistview = ( j === snaklistviewItems.length - 1 ), - isOverallLast = ( i === listviewItems.length - 1 && isLastInSnaklistview ), - hasNextListItem = listviewItems.eq( i + 1 ).length > 0, - nextSnaklist = ( hasNextListItem ) - ? listviewItems.eq( i + 1 ).data( 'snaklistview' ).value() - : null, - nextListItemIsPending = hasNextListItem && ( - nextSnaklist === null - || claimview._initialQualifiers.indexOf( nextSnaklist.toArray()[0] ) === -1 - ), - isBeforePending = isLastInSnaklistview && nextListItemIsPending; - - btnUp[ ( isOverallFirst ) ? 'disable' : 'enable' ](); - btnDown[ ( isOverallLast || isBeforePending ) ? 'disable' : 'enable' ](); - } - } ); - } ); - - // Stop repeatedly triggering the event on the moved DOM node: - event.stopImmediatePropagation(); - } - ); - } - } - } -} ); - -// We have to override this here because $.widget sets it no matter what's in -// the prototype -$.wikibase.claimview.prototype.widgetBaseClass = 'wb-claimview'; - -}( mediaWiki, wikibase, jQuery ) ); diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js b/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js index f0a5616..537d00e 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js @@ -607,7 +607,7 @@ // Register toolbars: $.wikibase.toolbarcontroller.definition( 'addtoolbar', { id: 'referenceview-snakview', - selector: '.wb-statement-references .wb-referenceview', + selector: '.wikibase-statementview-references .wb-referenceview', events: { referenceviewstartediting: function( event, toolbarController ) { var $referenceview = $( event.target ), @@ -671,7 +671,7 @@ $.wikibase.toolbarcontroller.definition( 'removetoolbar', { id: 'referenceview-snakview-remove', - selector: '.wb-statement-references .wb-referenceview', + selector: '.wikibase-statementview-references .wb-referenceview', events: { 'snakviewstartediting snakviewchange referenceviewitemremoved': function( event, toolbarController ) { var $target = $( event.target ), @@ -794,7 +794,7 @@ $.wikibase.toolbarcontroller.definition( 'movetoolbar', { id: 'referenceview-snakview', - selector: '.wb-statement-references .wb-referenceview', + selector: '.wikibase-statementview-references .wb-referenceview', events: { 'snakviewstartediting': function( event, toolbarController ) { var $snakview = $( event.target ), diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js index e509325..3635718 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js @@ -41,23 +41,28 @@ */ $.widget( 'wikibase.statementview', PARENT, { options: { - template: 'wb-statement', + template: 'wikibase-statementview', templateParams: [ - function() { // Rank selector - return $( '<div>' ); + function() { // GUID + return ( this._statement && this._statement.getClaim().getGuid() ) || 'new'; }, - function() { - return $( '<div/>' ).addClass( 'wb-claimview' ); - }, // .wb-claimview - '', // TODO: This toolbar placeholder should be removed from the template. + function() { // Rank selector + return $( '<div/>' ); + }, + function() { // Main snak + return $( '<div/>' ); + }, + '', // Qualifiers + '', // Toolbar placeholder '', // References heading '' // List of references ], templateShortCuts: { - '$rankSelector': '.wb-statement-rank', - '$claimview': '.wb-claimview', - '$refsHeading': '.wb-statement-references-heading', - '$references': '.wb-statement-references' + $rankSelector: '.wikibase-statementview-rankselector', + $mainSnak: '.wikibase-statementview-mainsnak > :first-child', + $qualifiers: '.wikibase-statementview-qualifiers', + $refsHeading: '.wikibase-statementview-references-heading', + $references: '.wikibase-statementview-references' }, value: null, claimsChanger: null, @@ -98,9 +103,21 @@ _statement: null, /** - * @type {jQuery.wikibase.claimview} + * Reference to the `listview` widget managing the qualifier `snaklistview`s. Basically, just a + * short-cut for `this.$qualifiers.data( 'listview' )`. + * @type {$.wikibase.listview} */ - _claimview: null, + _qualifiers: null, + + /** + * Caches the `SnakList` of the qualifiers the `statementview` has been initialized with. The + * qualifiers are split into groups featuring the same property. Removing one of those groups + * results in losing the reference to those qualifiers. Therefore, `_initialQualifiers` is used + * to rebuild the list of qualifiers when cancelling and is used to query whether the qualifiers + * represent the initial state. + * @type {wb.datamodel.SnakList} + */ + _initialQualifiers: null, /** * @type {wikibase.entityChangers.ReferencesChanger} @@ -122,165 +139,28 @@ PARENT.prototype._create.call( this ); - var self = this, - statement = this._statement = this.option( 'value' ), - refs = statement ? statement.getReferences() : []; + this._statement = this.options.value; + this._initialIndex = this.options.index; - this._initialIndex = this.option( 'index' ); + this._createRankSelector( this._statement ? this._statement.getRank() : null ); + this._createMainSnak( this._statement + ? this._statement.getClaim().getMainSnak() + : this.option( 'predefined' ).mainSnak || null + ); - this._createRankSelector( statement ? statement.getRank() : null ); + this._initialQualifiers = this._statement + ? this._statement.getClaim().getQualifiers() + : new wb.datamodel.SnakList(); + + // TODO: Allow adding qualifiers when adding a new claim. + if( this._statement && this._initialQualifiers.length ) { + this._createQualifiersListview( this._initialQualifiers ); + } this._referencesChanger = this.options.entityChangersFactory.getReferencesChanger(); - this._createClaimview( statement ); + this._createReferences( this._statement ); - this._attachEditModeEventHandlers(); - - function indexOf( element, array ) { - var index = $.inArray( element, array ); - return ( index !== -1 ) ? index : null; - } - - if( statement ) { - var $listview = this.$references.children(); - if( !$listview.length ) { - $listview = $( '<div/>' ).prependTo( this.$references ); - } - - $listview.listview( { - listItemAdapter: new $.wikibase.listview.ListItemAdapter( { - listItemWidget: $.wikibase.referenceview, - newItemOptionsFn: function( value ) { - var index = indexOf( value, self.value().getReferences().toArray() ); - if( index === null ) { - // The empty list view item for this is already appended to the list view - index = self._referencesListview.items().length - 1; - } - return { - value: value || null, - statementGuid: self.value().getClaim().getGuid(), - index: index, - dataTypeStore: self.option( 'dataTypeStore' ), - entityStore: self.option( 'entityStore' ), - valueViewBuilder: self.option( 'valueViewBuilder' ), - referencesChanger: self._referencesChanger - }; - } - } ), - value: refs.toArray() - } ); - - this._referencesListview = $listview.data( 'listview' ); - - this._referenceviewLia = this._referencesListview.listItemAdapter(); - - $listview - .on( 'listviewitemadded listviewitemremoved', function( event, value, $li ) { - if( event.target === $listview.get( 0 ) ) { - self.drawReferencesCounter(); - self._updateReferenceIndices(); - } - } ) - .on( 'referenceviewafterstopediting', function( event, dropValue ) { - if( dropValue ) { - // Re-order claims according to their initial indices: - var $referenceviews = self._referencesListview.items(); - - for( var i = 0; i < $referenceviews.length; i++ ) { - var referenceview = self._referenceviewLia.liInstance( $referenceviews.eq( i ) ); - self._referencesListview.move( $referenceviews.eq( i ), referenceview.getInitialIndex() ); - } - } - } ) - .on( 'listviewenternewitem', function( event, $newLi ) { - // Enter first item into the referenceview. - self._referenceviewLia.liInstance( $newLi ).enterNewItem(); - - var lia = self._referenceviewLia, - liInstance = lia.liInstance( $newLi ); - - if ( !liInstance.value() ) { - $newLi - .on( lia.prefixedEvent( 'afterstopediting' ), function( event, dropValue ) { - if( dropValue ) { - liInstance.destroy(); - $newLi.remove(); - self.drawReferencesCounter(); - } else { - var newReferenceWithHash = liInstance.value(); - - // Destroy new reference input form and add reference to list - liInstance.destroy(); - $newLi.remove(); - - // Display new reference with final GUID - self._addReference( newReferenceWithHash ); - } - } ); - } - } ); - - // Collapse references if there is at least one. - if ( this._referencesListview.items().length > 0 ) { - this.$references.css( 'display', 'none' ); - } - - // toggle for references section: - var $toggler = $( '<a/>' ).toggler( { $subject: this.$references } ); - - if( this.$refsHeading.text() ) { - $toggler.find( '.ui-toggler-label' ).text( this.$refsHeading.text() ); - this.$refsHeading.html( $toggler ); - } else { - this.$refsHeading.html( $toggler ); - this.drawReferencesCounter(); - } - - this._updateReferenceIndices(); - } - }, - - /** - * @param {wikibase.datamodel.Statement} statement - * @return {jQuery.wikibase.claimview} - */ - _createClaimview: function( statement ) { - var self = this; - - this.$claimview.claimview( { - dataTypeStore: this.option( 'dataTypeStore' ), - entityStore: this.option( 'entityStore' ), - helpMessage: this.option( 'helpMessage' ), - predefined: this.option( 'predefined' ), - locked: this.option( 'locked' ), - value: statement && statement.getClaim(), - valueViewBuilder: this.option( 'valueViewBuilder' ) - } ); - - this._claimview = this.$claimview.data( 'claimview' ); - - this.$claimview - .on( this._claimview.widgetEventPrefix + 'change.' + this.widgetName, function() { - self._trigger( 'change' ); - } ) - .on( - this._claimview.widgetEventPrefix + 'afterstopediting.' + this.widgetName, - function( event, dropValue ) { - self.stopEditing( dropValue ); - } - ) - .on( [ - this._claimview.widgetEventPrefix + 'startediting.' + this.widgetName, - this._claimview.widgetEventPrefix + 'afterstartediting.' + this.widgetName, - this._claimview.widgetEventPrefix + 'stopediting.' + this.widgetName, - this._claimview.widgetEventPrefix + 'afterstopediting.' + this.widgetName, - this._claimview.widgetEventPrefix + 'change.' + this.widgetName, - this._claimview.widgetEventPrefix + 'toggleerror.' + this.widgetName - ].join( ' ' ), - function( event ) { - // Encapsulate claimview. - event.stopPropagation(); - } - ); + this._updateHelpMessage(); }, /** @@ -325,41 +205,281 @@ }, /** - * Attaches event listeners that shall trigger stopping the claimview's edit mode. + * @param {wikibase.datamodel.Snak|null} snak + * @private */ - _attachEditModeEventHandlers: function() { + _createMainSnak: function( snak ) { var self = this; - this._detachEditModeEventHandlers(); - - function defaultHandling( event, dropValue ) { - event.stopImmediatePropagation(); - event.preventDefault(); - self._detachEditModeEventHandlers(); - self._attachEditModeEventHandlers(); - self.stopEditing( dropValue ); - } - - this._claimview.$mainSnak.one( 'snakviewstopediting.' + this.widgetName, function( event, dropValue ) { - defaultHandling( event, dropValue ); + this.$mainSnak + .on( + [ + 'snakviewchange.' + this.widgetName, + 'snakviewafterstartediting.' + this.widgetName + ].join( ' ' ), + function( event, status ) { + event.stopPropagation(); + self._trigger( 'change' ); + } + ) + .on( 'snakviewstopediting.' + this.widgetName, function( event ) { + event.stopPropagation(); } ); - if( this._claimview.$qualifiers ) { - this._claimview.$qualifiers - .one( 'snaklistviewstopediting.' + this.widgetName, function( event, dropValue ) { - defaultHandling( event, dropValue ); + this.$mainSnak.snakview( { + value: snak, + locked: this.option( 'locked' ).mainSnak, + autoStartEditing: false, + dataTypeStore: this.option( 'dataTypeStore' ), + entityStore: this.options.entityStore, + valueViewBuilder: this.option( 'valueViewBuilder' ) + } ); + }, + + /** + * Creates the `listview` widget containing the qualifier `snaklistview` widgets. + * @private + * + * @param {wb.datamodel.SnakList|null} [qualifiers=null] + */ + _createQualifiersListview: function( qualifiers ) { + var self = this, + groupedQualifierSnaks = null; + + // Group qualifiers by property id: + if( qualifiers && qualifiers.length ) { + var propertyIds = qualifiers.getPropertyOrder(); + + groupedQualifierSnaks = []; + + for( var i = 0; i < propertyIds.length; i++ ) { + groupedQualifierSnaks.push( qualifiers.getFilteredSnakList( propertyIds[i] ) ); + } + } + + // Using the property id, qualifier snaks are split into groups of snaklistviews. These + // snaklistviews are managed in a listview: + var $qualifiers = this.$qualifiers.children(); + if( !$qualifiers.length ) { + $qualifiers = $( '<div/>' ).prependTo( this.$qualifiers ); + } + $qualifiers.listview( { + listItemAdapter: new $.wikibase.listview.ListItemAdapter( { + listItemWidget: $.wikibase.snaklistview, + newItemOptionsFn: function( value ) { + return { + value: value || null, + singleProperty: true, + dataTypeStore: self.option( 'dataTypeStore' ), + entityStore: self.option( 'entityStore' ), + valueViewBuilder: self.option( 'valueViewBuilder' ) + }; + } + } ), + value: groupedQualifierSnaks + } ) + .on( 'snaklistviewstopediting.' + this.widgetName, function( event, dropValue ) { + event.stopPropagation(); + } ) + .on( 'snaklistviewchange.' + this.widgetName + + ' listviewafteritemmove.' + this.widgetName, + function( event ) { + event.stopPropagation(); + self._trigger( 'change' ); + } + ) + .on( 'listviewitemremoved.' + this.widgetName, function( event, value, $itemNode ) { + if( event.target === self._qualifiers.element.get( 0 ) ) { + self._trigger( 'change' ); + return; + } + + // Check if last snaklistview of a qualifier listview item has been removed and + // remove the listview item if so: + var $snaklistview = $( event.target ).closest( ':wikibase-snaklistview' ), + snaklistview = $snaklistview.data( 'snaklistview' ); + + if( !snaklistview.value() ) { + self._qualifiers.removeItem( snaklistview.element ); + } + } ); + + this._qualifiers = $qualifiers.data( 'listview' ); + }, + + /** + * @param {wikibase.datamodel.Statement} [statement] + * @private + */ + _createReferences: function( statement ) { + if( !statement ) { + return; + } + + var self = this, + references = statement.getReferences(); + + function indexOf( element, array ) { + var index = $.inArray( element, array ); + return ( index !== -1 ) ? index : null; + } + + var $listview = this.$references.children(); + if( !$listview.length ) { + $listview = $( '<div/>' ).prependTo( this.$references ); + } + + $listview.listview( { + listItemAdapter: new $.wikibase.listview.ListItemAdapter( { + listItemWidget: $.wikibase.referenceview, + newItemOptionsFn: function( value ) { + var index = indexOf( value, self.value().getReferences().toArray() ); + if( index === null ) { + // The empty list view item for this is already appended to the list view + index = self._referencesListview.items().length - 1; + } + return { + value: value || null, + statementGuid: self.value().getClaim().getGuid(), + index: index, + dataTypeStore: self.option( 'dataTypeStore' ), + entityStore: self.option( 'entityStore' ), + valueViewBuilder: self.option( 'valueViewBuilder' ), + referencesChanger: self._referencesChanger + }; + } + } ), + value: references.toArray() + } ); + + this._referencesListview = $listview.data( 'listview' ); + + this._referenceviewLia = this._referencesListview.listItemAdapter(); + + $listview + .on( 'listviewitemadded listviewitemremoved', function( event, value, $li ) { + if( event.target === $listview.get( 0 ) ) { + self.drawReferencesCounter(); + self._updateReferenceIndices(); + } + } ) + .on( 'referenceviewafterstopediting', function( event, dropValue ) { + if( dropValue ) { + // Re-order claims according to their initial indices: + var $referenceviews = self._referencesListview.items(); + + for( var i = 0; i < $referenceviews.length; i++ ) { + var referenceview = self._referenceviewLia.liInstance( $referenceviews.eq( i ) ); + self._referencesListview.move( $referenceviews.eq( i ), referenceview.getInitialIndex() ); + } + } + } ) + .on( 'listviewenternewitem', function( event, $newLi ) { + // Enter first item into the referenceview. + self._referenceviewLia.liInstance( $newLi ).enterNewItem(); + + var lia = self._referenceviewLia, + liInstance = lia.liInstance( $newLi ); + + if ( !liInstance.value() ) { + $newLi + .on( lia.prefixedEvent( 'afterstopediting' ), function( event, dropValue ) { + if( dropValue ) { + liInstance.destroy(); + $newLi.remove(); + self.drawReferencesCounter(); + } else { + var newReferenceWithHash = liInstance.value(); + + // Destroy new reference input form and add reference to list + liInstance.destroy(); + $newLi.remove(); + + // Display new reference with final GUID + self._addReference( newReferenceWithHash ); + } + } ); + } + } ); + + // Collapse references if there is at least one. + if ( this._referencesListview.items().length > 0 ) { + this.$references.css( 'display', 'none' ); + } + + // toggle for references section: + var $toggler = $( '<a/>' ).toggler( { $subject: this.$references } ); + + if( this.$refsHeading.text() ) { + $toggler.find( '.ui-toggler-label' ).text( this.$refsHeading.text() ); + this.$refsHeading.html( $toggler ); + } else { + this.$refsHeading.html( $toggler ); + this.drawReferencesCounter(); + } + + this._updateReferenceIndices(); + }, + + /** + * Updates the `helpMessage` option according to whether the `main Snak`'s `Property` is + * predefined. + * @private + */ + _updateHelpMessage: function() { + if( !this._statement && !this.options.predefined.mainSnak ) { + return; + } + + var property = this._statement + ? this._statement.getClaim().getMainSnak().getPropertyId() + : this.options.predefined.mainSnak.property; + + var deferred = $.Deferred(), + helpMessage = this.options.helpMessage; + + this.options.helpMessage = deferred.promise(); + + if( property ) { + this.options.entityStore.get( property ).done( function( fetchedProperty ) { + if( fetchedProperty ) { + helpMessage = mw.msg( + 'wikibase-claimview-snak-tooltip', + wb.utilities.ui.buildPrettyEntityLabelText( fetchedProperty.getContent() ) + ); + } + deferred.resolve( helpMessage ); } ); + } else { + deferred.resolve( helpMessage ); } }, /** - * Detaches event listeners that shall trigger stopping the claimview's edit mode. + * @inheritdoc */ - _detachEditModeEventHandlers: function() { - this._claimview.$mainSnak.off( 'snakviewstopediting' ); + destroy: function() { + this._rankSelector.destroy(); + this.$rankSelector.off( '.' + this.widgetName ); - if ( this._qualifiers && this._qualifiers.value().length ) { - this._qualifiers.element.off( 'snaklistviewstopediting' ); + this.$mainSnak.snakview( 'destroy' ); + this.$mainSnak.off( '.' + this.widgetName ); + + this._destroyQualifiersListView(); + + PARENT.prototype.destroy.call( this ); + }, + + /** + * @private + */ + _destroyQualifiersListView: function() { + if( this._qualifiers ) { + this._qualifiers.destroy(); + this.$qualifiers + .off( '.' + this.widgetName ) + .empty(); + this._qualifiers = null; } }, @@ -367,25 +487,57 @@ * @return {boolean} */ isInitialValue: function() { - if( this.option( 'index' ) !== this._initialIndex || !this._claimview.isInitialValue() ) { + if( this.option( 'index' ) !== this._initialIndex ) { return false; - } else if( this._statement && this._rankSelector ) { - return this._statement.getRank() === this._rankSelector.rank(); } - return true; + + if( this._statement ) { + if( this._statement.getRank() !== this._rankSelector.rank() ) { + return false; + } + + var snaklistviews = ( this._qualifiers ) ? this._qualifiers.value() : [], + qualifiers = new wb.datamodel.SnakList(); + + // Generate a SnakList object featuring all current qualifier snaks to be able to + // compare it to the SnakList object the claimview has been initialized with: + if( snaklistviews.length ) { + for( var i = 0; i < snaklistviews.length; i++ ) { + if( snaklistviews[i].value() ) { + qualifiers.merge( snaklistviews[i].value() ); + } + } + } + + if( !qualifiers.equals( this._initialQualifiers ) ) { + return false; + } + } + + return this.$mainSnak.data( 'snakview' ).isInitialSnak(); }, /** - * Instantiates a statement with the statementview's current value. + * Instantiates a `Statement` with the `statementview`'s current value. * * @param {string} guid * @return {wikibase.datamodel.Statement} */ _instantiateStatement: function( guid ) { - var claim = this._claimview._instantiateClaim( guid ); + var qualifiers = new wb.datamodel.SnakList(), + snaklistviews = this._qualifiers ? this._qualifiers.value() : []; + + // Combine qualifiers grouped by property to a single SnakList: + for( var i = 0; i < snaklistviews.length; i++ ) { + qualifiers.merge( snaklistviews[i].value() ); + } return new wb.datamodel.Statement( - claim, + new wb.datamodel.Claim( + this.$mainSnak.data( 'snakview' ).snak(), + qualifiers, + guid + ), new wb.datamodel.ReferenceList( this.getReferences() ), this._rankSelector.rank() ); @@ -462,22 +614,6 @@ }, /** - * @see jQuery.Widget.destroy - */ - destroy: function() { - this._rankSelector.destroy(); - this.$rankSelector.off( '.' + this.widgetName ); - - if( this._claimview ) { - this._claimview.destroy(); - this._claimview = null; - } - this.$claimview.off( '.' + this.widgetName ); - - PARENT.prototype.destroy.call( this ); - }, - - /** * Returns the current Statement represented by the view. If null is returned, than this is a * fresh view where a new Statement is being constructed. * @@ -532,21 +668,20 @@ natively: function( e, dropValue ) { var self = this; - this._detachEditModeEventHandlers(); - this.disable(); this._rankSelector.disable(); function stopEditing() { + if( self.$mainSnak.data( 'snakview' ) ) { + self.$mainSnak.data( 'snakview' ).stopEditing( dropValue ); + } + + self._stopEditingQualifiers( dropValue ); + self._isInEditMode = false; - // If the claimview has it's initial value, it refuses to leave edit mode. - // Set dropValue = true in this case, so that it really leaves edit mode. - self._claimview.stopEditing( self._claimview.isInitialValue() || dropValue ); self.enable(); self.element.removeClass( 'wb-edit' ); - - self._attachEditModeEventHandlers(); // transform toolbar and snak view after save complete self._trigger( 'afterstopediting', null, [dropValue] ); @@ -560,17 +695,56 @@ .done( stopEditing ) .fail( function( error ) { self.enable(); - - // Claimview might have gotten the stopEditing before statementview - self._claimview.startEditing(); - - self._attachEditModeEventHandlers(); - self.setError( error ); } ); } } } ), + + /** + * Stops qualifiers `listview` edit mode. + * + * @param {boolean} dropValue + */ + _stopEditingQualifiers: function( dropValue ) { + var snaklistviews, + i; + + if( this._qualifiers ) { + snaklistviews = this._qualifiers.value(); + + if( !dropValue ) { + // When saving the qualifier snaks, reset the initial qualifiers to the new ones. + this._initialQualifiers = new wb.datamodel.SnakList(); + } + + if( snaklistviews.length ) { + for( i = 0; i < snaklistviews.length; i++ ) { + snaklistviews[i].stopEditing( dropValue ); + + if( dropValue && !snaklistviews[i].value() ) { + // Remove snaklistview from qualifier listview if no snakviews are left in + // that snaklistview: + this._qualifiers.removeItem( snaklistviews[i].element ); + } else if ( !dropValue ) { + // Gather all the current snaks in a single SnakList to set to reset the + // initial qualifiers: + this._initialQualifiers.merge( snaklistviews[i].value() ); + } + } + } + } + + // Destroy and (if qualifiers still exist) re-create the qualifier listview in order to + // re-group the qualifiers by their property. This will also send out the event to erase + // the "add qualifier" toolbar. + this._destroyQualifiersListView(); + + if( this._initialQualifiers.length > 0 ) { + // Refill the qualifier listview with the initial (or new initial) qualifiers: + this._createQualifiersListview( this._initialQualifiers ); + } + }, /** * TODO: would be nice to have all API related stuff out of here to allow concentrating on @@ -623,7 +797,24 @@ natively: function( e ) { var self = this; - this._claimview.element.one( 'claimviewafterstartediting', function() { + this.$mainSnak.one( 'snakviewafterstartediting', function() { + if( !self._qualifiers && self._statement ) { + self._createQualifiersListview(); + } + + // Start edit mode of all qualifiers: + if( self._qualifiers ) { + var snaklistviews = self._qualifiers.value(); + if( snaklistviews.length ) { + for( var i = 0; i < snaklistviews.length; i++ ) { + snaklistviews[i].startEditing(); + } + } + // If there are no snaklistviews, there is no way for the "add qualifier" + // toolbar to be + self._qualifiers.element.trigger( 'qualifiersstartediting' ); + } + self.element.addClass( 'wb-edit' ); self._isInEditMode = true; @@ -637,7 +828,7 @@ self._trigger( 'afterstartediting' ); } ); - this._claimview.startEditing(); + this.$mainSnak.data( 'snakview' ).startEditing(); } } ), @@ -681,8 +872,16 @@ * @return {boolean} */ isValid: function() { - if( !this._claimview.isValid() ) { - return false; + if( this._qualifiers ) { + var snaklistviews = this._qualifiers.value(); + + if( snaklistviews.length ) { + for( var i = 0; i < snaklistviews.length; i++ ) { + if( !snaklistviews[i].isValid() ) { + return false; + } + } + } } try { @@ -695,17 +894,422 @@ }, /** - * @see jQuery.ui.TemplatedWidget.focus + * @inheritdoc + */ + _setOption: function( key, value ) { + if( key === 'value' ) { + throw new Error( 'Can not set value after initialization' ); + } + + var response = PARENT.prototype._setOption.apply( this, arguments ); + + if( key === 'disabled' ) { + this.$mainSnak.data( 'snakview' ).option( key, value ); + if( this._qualifiers ) { + this._qualifiers.option( key, value ); + } + } else if( key === 'index' && value !== undefined ) { + this._trigger( 'change' ); + } + + return response; + }, + + /** + * @inheritdoc */ focus: function() { - this._claimview.focus(); + this.$mainSnak.data( 'snakview' ).focus(); } } ); // Register toolbars: $.wikibase.toolbarcontroller.definition( 'addtoolbar', { + id: 'claim-qualifiers-snak', + selector: '.wikibase-statementview-qualifiers', + events: { + 'listviewcreate snaklistviewstartediting': function( event, toolbarController ) { + var $target = $( event.target ), + $qualifiers = $target.closest( '.wikibase-statementview-qualifiers' ), + listview = $target.closest( ':wikibase-listview' ).data( 'listview' ), + listviewInited = event.type === 'listviewcreate' && listview.items().length === 0; + + if( + ( listviewInited || event.type === 'snaklistviewstartediting' ) + && !$qualifiers.data( 'addtoolbar' ) + ) { + $qualifiers + .addtoolbar( { + $container: $( '<div/>' ).appendTo( $qualifiers ), + label: mw.msg( 'wikibase-addqualifier' ) + } ) + .off( '.addtoolbar' ) + .on( 'addtoolbaradd.addtoolbar', function( e ) { + listview.enterNewItem(); + listview.value()[listview.value().length - 1].enterNewItem(); + } ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'listviewdestroy snaklistviewafterstopediting', + function( event, toolbarcontroller ) { + var $target = $( event.target ), + $qualifiers = $target.closest( '.wikibase-statementview-qualifiers' ); + + if( $target.parent().get( 0 ) !== $qualifiers.get( 0 ) ) { + // Not the qualifiers main listview. + return; + } + + toolbarcontroller.destroyToolbar( $qualifiers.data( 'addtoolbar' ) ); + } + ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'snaklistviewchange', + function( event ) { + var $target = $( event.target ), + $qualifiers = $target.closest( '.wikibase-statementview-qualifiers' ), + addToolbar = $qualifiers.data( 'addtoolbar' ), + $listview = $target.closest( ':wikibase-listview' ), + snaklistviews = $listview.data( 'listview' ).value(); + + if( addToolbar ) { + addToolbar.enable(); + for( var i = 0; i < snaklistviews.length; i++ ) { + if( !snaklistviews[i].isValid() ) { + addToolbar.disable(); + break; + } + } + } + } + ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + // FIXME: When there are qualifiers, no state change events will be thrown. + 'listviewdisable', + function( event ) { + var $qualifiers = $( event.target ) + .closest( '.wikibase-statementview-qualifiers' ), + addToolbar = $qualifiers.data( 'addtoolbar' ), + $statementview = $qualifiers.closest( ':wikibase-statementview' ), + statementview = $statementview.data( 'statementview' ); + + // Toolbar might be removed from the DOM already after having stopped edit + // mode. + if( addToolbar ) { + addToolbar[statementview.option( 'disabled' ) ? 'disable' : 'enable'](); + } + } + ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'listviewitemadded listviewitemremoved', + function( event ) { + // Enable "add" link when all qualifiers have been removed: + var $listviewNode = $( event.target ), + listview = $listviewNode.data( 'listview' ), + $snaklistviewNode = $listviewNode.closest( '.wb-snaklistview' ), + snaklistview = $snaklistviewNode.data( 'snaklistview' ), + addToolbar = $snaklistviewNode.data( 'addtoolbar' ); + + // Toolbar is not within the DOM when (re-)constructing the list in + // non-edit-mode. + if( !addToolbar ) { + return; + } + + // Disable "add" toolbar when the last qualifier has been removed: + if( !snaklistview.isValid() && listview.items().length ) { + addToolbar.disable(); + } else { + addToolbar.enable(); + } + } + ); + + } + } + } +} ); + +$.wikibase.toolbarcontroller.definition( 'removetoolbar', { + id: 'claim-qualifiers-snak', + selector: '.wikibase-statementview-qualifiers', + events: { + 'snakviewstartediting': function( event, toolbarController ) { + var $snakview = $( event.target ), + $snaklistview = $snakview.closest( '.wb-snaklistview' ), + snaklistview = $snaklistview.data( 'snaklistview' ); + + if( !snaklistview ) { + return; + } + + var qualifierPorpertyGroupListview = snaklistview._listview; + + // Create toolbar for each snakview widget: + $snakview + .removetoolbar( { + $container: $( '<div/>' ).appendTo( $snakview ) + } ) + .on( 'removetoolbarremove.removetoolbar', function( event ) { + if( event.target === $snakview.get( 0 ) ) { + qualifierPorpertyGroupListview.removeItem( $snakview ); + } + } ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'snaklistviewafterstopediting', + function( event, toolbarcontroller ) { + // Destroy the snakview toolbars: + var $snaklistviewNode = $( event.target ), + listview = $snaklistviewNode.data( 'snaklistview' )._listview, + lia = listview.listItemAdapter(); + + $.each( listview.items(), function( i, item ) { + var snakview = lia.liInstance( $( item ) ); + toolbarcontroller.destroyToolbar( + snakview.element.data( 'removetoolbar' ) + ); + } ); + } + ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'snaklistviewdisable', + function( event ) { + var $snaklistviewNode = $( event.target ), + listview = $snaklistviewNode.data( 'snaklistview' )._listview, + lia = listview.listItemAdapter(), + $statementview = $snaklistviewNode.closest( ':wikibase-statementview' ), + statementview = $statementview.data( 'statementview' ); + + $.each( listview.items(), function( i, node ) { + var $snakview = $( node ), + snakview = lia.liInstance( $snakview ), + removeToolbar = $snakview.data( 'removetoolbar' ); + + // Item might be about to be removed not being a list item instance. + if( !snakview || !removeToolbar ) { + return; + } + + $snakview.data( 'removetoolbar' )[statementview.option( 'disabled' ) + ? 'disable' + : 'enable' + ](); + } ); + } + ); + + } + } +} ); + +$.wikibase.toolbarcontroller.definition( 'movetoolbar', { + id: 'claim-qualifiers-snak', + selector: '.wikibase-statementview-qualifiers', + events: { + 'snakviewstartediting': function( event, toolbarController ) { + var $snakview = $( event.target ), + $snaklistview = $snakview.closest( ':wikibase-snaklistview' ), + snaklistview = $snaklistview.data( 'snaklistview' ); + + if( !snaklistview ) { + return; + } + + var $listview = $snaklistview.closest( ':wikibase-listview' ); + + if( !$listview.parent().hasClass( 'wikibase-statementview-qualifiers' ) ) { + return; + } + + var listview = $listview.data( 'listview' ); + + if( $snaklistview.data( 'snaklistview' ).value() !== null ) { + // Create toolbar for each snakview widget: + $snakview.movetoolbar( { + $container: $( '<div/>' ).appendTo( $snakview ) + } ); + + var $topMostSnakview = listview.items().first().data( 'snaklistview' ) + ._listview.items().first(); + var $bottomMostSnakview = listview.items().last().data( 'snaklistview' ) + ._listview.items().last(); + + if ( $topMostSnakview.get( 0 ) === $snakview.get( 0 ) ) { + $snakview.data( 'movetoolbar' ).getButton( 'up' ).disable(); + } + + if( $bottomMostSnakview.get( 0 ) === $snakview.get( 0 ) ) { + $snakview.data( 'movetoolbar' ).getButton( 'down' ).disable(); + } + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'snaklistviewafterstopediting', + function( event, toolbarcontroller ) { + // Destroy the snakview toolbars: + var $snaklistviewNode = $( event.target ), + listview = $snaklistviewNode.data( 'snaklistview' )._listview, + lia = listview.listItemAdapter(); + + $.each( listview.items(), function( i, item ) { + var snakview = lia.liInstance( $( item ) ); + toolbarcontroller.destroyToolbar( snakview.element.data( 'movetoolbar' ) ); + } ); + + // Remove obsolete event handlers attached to the node the + // toolbarcontroller has been initialized on: + $snaklistviewNode + .closest( '.wikibase-statementview-qualifiers' ) + .off( '.movetoolbar' ); + } + ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'movetoolbarup movetoolbardown', + function( event ) { + var $snakview = $( event.target ), + $snaklistview = $snakview.closest( ':wikibase-snaklistview' ); + + if( !$snaklistview.length ) { + // Unrelated "move" action. + return; + } + + var snaklistview = $snaklistview.data( 'snaklistview' ), + snaklistviewListview = snaklistview.$listview.data( 'listview' ), + snaklistviewListviewLia = snaklistviewListview.listItemAdapter(), + snak = snaklistviewListviewLia.liInstance( $snakview ).snak(), + snakList = snaklistview.value(), + $listview = $snaklistview.closest( ':wikibase-listview' ), + listview = $listview.data( 'listview' ), + action = ( event.type === 'movetoolbarup' ) ? 'moveUp' : 'moveDown'; + + if( action === 'moveUp' && snakList.indexOf( snak ) !== 0 ) { + // Snak is not in top of the snaklistview group the snaks featuring the same + // property. Therefore, the snak is to be moved within the snaklistview. + snaklistview.moveUp( snak ); + } else if( + action === 'moveDown' + && snakList.indexOf( snak ) !== snakList.length - 1 + ) { + // Move down snakview within a snaklistview. + snaklistview.moveDown( snak ); + } else { + // When issuing "move up" on a snak on top of a snak list, the whole + // snaklistview has to be move; Same for "move down" on a snak at the + // bottom of a snak list. + listview[action]( $snaklistview ); + } + } + ); + + toolbarController.registerEventHandler( + event.data.toolbar.type, + event.data.toolbar.id, + 'movetoolbarup movetoolbardown listviewitemadded listviewitemremoved', + function( event ) { + // Disable "move up" button of the topmost snakview of the topmost + // snaklistview and the "move down" button of the bottommost snakview of the + // bottommost snaklistview. All other buttons shall be enabled. + var $target = $( event.target ), + $statementview = $target.closest( ':wikibase-statementview' ), + statementview = $statementview.data( 'statementview' ), + listview; + + if( event.type.indexOf( 'listview' ) !== 0 ) { + var $snaklistview = $target.closest( ':wikibase-snaklistview' ), + $listview = $snaklistview.closest( ':wikibase-listview' ); + listview = $listview.data( 'listview' ); + } else if( + !$target.parent().hasClass( 'wikibase-statementview-qualifiers' ) + ) { + // Do not react on snaklistview's listview event. + return; + } else { + listview = $target.data( 'listview' ); + } + + if( !listview ) { + // Unrelated "move" action. + return; + } + + var listviewItems = listview.items(); + + listviewItems.each( function( i, snaklistviewNode ) { + var snaklistview = $( snaklistviewNode ).data( 'snaklistview' ); + + if( + !snaklistview + || !snaklistview.value() + || !snaklistview.isInEditMode() + ) { + // Pending snaklistview: Remove the preceding "move down" button if + // it exists: + return; + } + + var snaklistviewItems = snaklistview._listview.items(); + + snaklistviewItems.each( function( j, snakviewNode ) { + var $snakview = $( snakviewNode ), + movetoolbar = $snakview.data( 'movetoolbar' ); + + // Pending snakviews do not feature a movetoolbar. + if( movetoolbar ) { + var btnUp = movetoolbar.getButton( 'up' ), + btnDown = movetoolbar.getButton( 'down' ), + isOverallFirst = ( i === 0 && j === 0 ), + isLastInSnaklistview = ( j === snaklistviewItems.length - 1 ), + isOverallLast = ( i === listviewItems.length - 1 && isLastInSnaklistview ), + hasNextListItem = listviewItems.eq( i + 1 ).length > 0, + nextSnaklist = ( hasNextListItem ) + ? listviewItems.eq( i + 1 ).data( 'snaklistview' ).value() + : null, + nextListItemIsPending = hasNextListItem && ( + nextSnaklist === null + || statementview._initialQualifiers.indexOf( nextSnaklist.toArray()[0] ) === -1 + ), + isBeforePending = isLastInSnaklistview && nextListItemIsPending; + + btnUp[ ( isOverallFirst ) ? 'disable' : 'enable' ](); + btnDown[ ( isOverallLast || isBeforePending ) ? 'disable' : 'enable' ](); + } + } ); + } ); + + // Stop repeatedly triggering the event on the moved DOM node: + event.stopImmediatePropagation(); + } + ); + } + } + } +} ); + +$.wikibase.toolbarcontroller.definition( 'addtoolbar', { id: 'references', - selector: '.wb-statement-references', + selector: '.wikibase-statementview-references', events: { listviewcreate: function( event, toolbarController ) { var $listview = $( event.target ), @@ -713,7 +1317,7 @@ lia = listview.listItemAdapter(), $node = $listview.parent(); - if( !$node.hasClass( 'wb-statement-references' ) ) { + if( !$node.hasClass( 'wikibase-statementview-references' ) ) { return; } @@ -746,7 +1350,7 @@ var $listview = $( event.target ), $node = $listview.parent(); - if( !$node.hasClass( '.wb-statement-references' ) ) { + if( !$node.hasClass( '.wikibase-statementview-references' ) ) { return; } @@ -949,9 +1553,5 @@ } } } ); - -// We have to override this here because $.widget sets it no matter what's in -// the prototype -$.wikibase.statementview.prototype.widgetBaseClass = 'wb-statementview'; }( mediaWiki, wikibase, jQuery ) ); diff --git a/lib/resources/jquery.wikibase/resources.php b/lib/resources/jquery.wikibase/resources.php index f193584..5aec454 100644 --- a/lib/resources/jquery.wikibase/resources.php +++ b/lib/resources/jquery.wikibase/resources.php @@ -86,7 +86,6 @@ 'dependencies' => array( 'jquery.ui.TemplatedWidget', 'jquery.ui.widget', - 'jquery.wikibase.claimview', 'jquery.wikibase.listview', 'jquery.wikibase.statementview', 'jquery.wikibase.toolbarcontroller', @@ -97,23 +96,6 @@ ), 'messages' => array( 'wikibase-entity-property', - ), - ), - - 'jquery.wikibase.claimview' => $moduleTemplate + array( - 'scripts' => array( - 'jquery.wikibase.claimview.js', - ), - 'dependencies' => array( - 'jquery.wikibase.snakview', - 'jquery.wikibase.snaklistview', - 'wikibase.datamodel', - 'jquery.wikibase.toolbarcontroller', - ), - 'messages' => array( - 'wikibase-addqualifier', - 'wikibase-claimview-snak-tooltip', - 'wikibase-claimview-snak-new-tooltip', ), ), @@ -443,20 +425,27 @@ 'jquery.ui.position', 'jquery.ui.toggler', 'util.inherit', - 'jquery.wikibase.claimview', 'jquery.wikibase.listview', 'jquery.wikibase.referenceview', + 'jquery.wikibase.snakview', + 'jquery.wikibase.snaklistview', 'jquery.wikibase.toolbarcontroller', - 'wikibase.datamodel', + 'wikibase.datamodel.Claim', + 'wikibase.datamodel.ReferenceList', + 'wikibase.datamodel.SnakList', + 'wikibase.datamodel.Statement', 'wikibase.utilities', ), 'messages' => array( + 'wikibase-addreference', + 'wikibase-addqualifier', + 'wikibase-claimview-snak-tooltip', + 'wikibase-claimview-snak-new-tooltip', 'wikibase-statementview-rank-preferred', 'wikibase-statementview-rank-normal', 'wikibase-statementview-rank-deprecated', 'wikibase-statementview-referencesheading-pendingcountersubject', 'wikibase-statementview-referencesheading-pendingcountertooltip', - 'wikibase-addreference', ), ), diff --git a/lib/resources/jquery.wikibase/toolbar/jquery.wikibase.edittoolbar.js b/lib/resources/jquery.wikibase/toolbar/jquery.wikibase.edittoolbar.js index 0602b8a..982c2ef 100644 --- a/lib/resources/jquery.wikibase/toolbar/jquery.wikibase.edittoolbar.js +++ b/lib/resources/jquery.wikibase/toolbar/jquery.wikibase.edittoolbar.js @@ -367,7 +367,7 @@ html: ' ' // TODO find nicer way to hack Webkit browsers to display tooltip image (see also css) } ).toolbaritem(); - // Support promises instead of strings, too, since $.wikibase.claimview does not know + // Support promises instead of strings, too, since $.wikibase.statementview does not know // immediately after creation which help message to show. // TODO: This should be replaced by a dynamic getter so that views can arbitrarily // change their help messages anywhere in their lifecycle. diff --git a/lib/resources/wikibase.css b/lib/resources/wikibase.css index b0aa623..ed1d39e 100644 --- a/lib/resources/wikibase.css +++ b/lib/resources/wikibase.css @@ -197,7 +197,7 @@ /********** CLAIMS **********/ -div.wb-claim textarea { +div.wikibase-statementview textarea { margin: 0; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; @@ -236,24 +236,12 @@ } /* A single claim */ -div.wb-claim { +div.wikibase-statementview { width: 100%; } -/* Container for the property (used in JS only). */ -div.wb-claim .wb-claim-property-container { - width: 15em; - top: 0; - position: absolute; - display: none; /* hidden by default (used in JS only) */ -} - -div.wb-claim .wb-claim-property { - padding: 10px; -} - /* Container for the claim contents */ -div.wb-claim-mainsnak { +div.wikibase-statementview-mainsnak { position: relative; margin-left: 15em; margin-right: 18em; @@ -261,7 +249,7 @@ word-wrap: break-word; } -div.wb-claim-mainsnak .wb-snak-property-container { +div.wikibase-statementview-mainsnak .wb-snak-property-container { display: none; } @@ -329,16 +317,13 @@ background-color: #E5C8B5; } -.wb-claimgrouplistview .wb-claimview.wb-edit, -.wb-claimgrouplistview .wb-claimview.wb-edit .wb-claim { +.wb-claimgrouplistview .wikibase-statementview.wb-edit, +.wb-claimgrouplistview .wikibase-statementview.wb-edit .wb-claim { background-color: #D6F3FF; } -.wb-claimgrouplistview .wb-claimview.wb-error, -.wb-claimgrouplistview .wb-claimview.wb-error .wb-claim { +.wb-claimgrouplistview .wikibase-statementview.wb-error, +.wb-claimgrouplistview .wikibase-statementview.wb-error .wb-claim { background-color: #FFDFC9; -} -.wb-claimgrouplistview .wb-claimlistview.wb-new .wb-claimview { - background-color: transparent; } .wb-claimlistview.wb-new { @@ -346,21 +331,17 @@ border: none; } -.wb-claimgrouplistview .wb-claimlistview.wb-new .wb-claim { +.wb-claimgrouplistview .wb-claimlistview.wb-new .wikibase-statementview { border: 1px solid #C9C9C9; width: 100%; margin-bottom: 1em; } -.wb-claimgrouplistview .wb-claimview.wb-new { +.wb-claimgrouplistview .wikibase-statementview.wb-new { padding-bottom: 0; } -.wb-claimgrouplistview .wb-claimlistview.wb-new .wb-claimview.wb-edit { - border: none; -} - -.wb-claimgrouplistview .wb-new .wb-claim-mainsnak { +.wb-claimgrouplistview .wb-new .wikibase-statementview-mainsnak { margin: 0 18em 0 15em; } @@ -424,59 +405,59 @@ /***** QUALIFIERS *****/ -.wb-claim-qualifiers { +.wikibase-statementview-qualifiers { padding-left: 17em; } -.wb-claim-qualifiers .wb-snaklistview:first-child { +.wikibase-statementview-qualifiers .wb-snaklistview:first-child { border-top: 1px dotted #D8D8D8; } -.wb-claim-qualifiers .wb-snaklistview { +.wikibase-statementview-qualifiers .wb-snaklistview { border-bottom: 1px dotted #D8D8D8; } -.wb-edit .wb-claim-qualifiers .wb-snaklistview { +.wb-edit .wikibase-statementview-qualifiers .wb-snaklistview { border-color: #C0DAE5; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-property { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-property { width: 12em; position: absolute; font-size: 90%; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-property input { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-property input { width: 100%; font-size: 100%; top: 0; position: absolute; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container { margin-left: 12em; position: relative; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-value { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-value { margin-left: 16px; margin-right: 18em; word-wrap: break-word; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-value .valueview-value { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-value .valueview-value { font-size: 90%; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-typeselector { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-typeselector { left: 0; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-value .valueview-value textarea { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snak-value-container .wb-snak-value .valueview-value textarea { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snakview { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snakview { position: relative; min-height: 1.8em; padding-top: 4px; @@ -484,12 +465,12 @@ } /* "remove" link at each reference's snak */ -.wb-claim-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snakview > .wikibase-toolbar-container { +.wikibase-statementview-qualifiers .wb-snaklistview .wb-snaklistview-listview .wb-snakview > .wikibase-toolbar-container { top: 5px; } /* "add" link in one reference's snak list */ -.wb-claim-qualifiers > .wikibase-toolbar-container { +.wikibase-statementview-qualifiers > .wikibase-toolbar-container { float: right; margin-bottom: 1em; position: static; @@ -508,7 +489,7 @@ /********** STATEMENTS **********/ /* Container for a single statement */ -.wb-statementview { +.wikibase-statementview { border-bottom: 1px dashed #AAA; float: left; width: 100%; @@ -516,32 +497,32 @@ padding-bottom: 1em; } -.wb-statementview:last-child { +.wikibase-statementview:last-child { border-bottom: 0; } -.wb-statementview .wb-statement-rank { +.wikibase-statementview .wikibase-statementview-rankselector { position: absolute; margin-left: 15.2em; margin-top: 1em; z-index: 1; } -.wb-claimview > .wikibase-toolbar { +.wikibase-statementview > .wikibase-toolbar { display: block; } -.wb-claimview .wikibase-toolbar-container { +.wikibase-statementview .wikibase-toolbar-container { top: 10px; /* even out padding */ } /***** REFERENCES *****/ -.wb-statement-reference-heading { +.wikibase-statementview-reference-heading { padding-top: 0.5em; } -.wb-statement-references-heading, .wb-statement-references { +.wikibase-statementview-references-heading, .wikibase-statementview-references { padding-left: 17em; clear: both; } @@ -660,7 +641,7 @@ } /* "add reference" link */ -.wb-statement-references > .wikibase-toolbar-container { +.wikibase-statementview-references > .wikibase-toolbar-container { float: right; position: static; } diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js deleted file mode 100644 index 68630d7..0000000 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @licence GNU GPL v2+ - * @author Adrian Lang < adrian.l...@wikimedia.de > - */ -( function( $, mw, wb, dv, vf, vv, QUnit ) { - 'use strict'; - - var entityStore = { - get: function() { - return $.Deferred().resolve( new wb.store.FetchedContent( { - title: new mw.Title( 'Property:P1' ), - content: new wb.datamodel.Property( - 'P1', - 'string', - new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( [ - new wb.datamodel.Term( 'en', 'P1' ) - ] ) ) - ) - } ) ); - } - }; - - var valueViewBuilder = new wb.ValueViewBuilder( - new vv.ExpertStore(), - new vf.ValueFormatterStore( vf.NullFormatter ), - 'I am a ParserStore', - 'I am a language code' - ); - - function createClaimview( value ) { - var options = { - // locked, index - value: value || null, - dataTypeStore: { - getDataType: function() {} - }, - entityStore: entityStore, - valueViewBuilder: valueViewBuilder, - claimsChanger: 'I am a ClaimsChanger' - }; - - return $( '<div/>' ) - .addClass( 'test_claimview' ) - .claimview( options ); - } - - QUnit.module( 'jquery.wikibase.claimview' ); - - QUnit.test( 'Initialize and destroy', function( assert ) { - var $node = createClaimview(), - claimview = $node.data( 'claimview' ); - - assert.ok( - claimview !== undefined, - 'Initialized claimview widget.' - ); - - claimview.destroy(); - - assert.ok( - $node.data( 'listview' ) === undefined, - 'Destroyed listview.' - ); - } ); - - QUnit.test( 'Initialize and destroy claimview with value', function( assert ) { - var $node = createClaimview( - new wb.datamodel.Claim( new wb.datamodel.PropertyNoValueSnak( 'P1' ) ) - ), - claimview = $node.data( 'claimview' ); - - assert.ok( - claimview instanceof $.wikibase.claimview, - 'Initialized claimview widget.' - ); - - claimview.destroy(); - - assert.ok( - $node.data( 'listview' ) === undefined, - 'Destroyed listview.' - ); - } ); - - function assertOnMaybePromise( assert, maybePromise, expectedVal ) { - if( maybePromise.done ) { - maybePromise.done( function( val ) { - QUnit.start(); - assert.equal( val, expectedVal ); - } ); - } else { - QUnit.start(); - assert.equal( maybePromise, expectedVal ); - } - } - - QUnit.asyncTest( 'Using the generic tooltip for new claims', 1, function( assert ) { - var $node = createClaimview(), - claimview = $node.data( 'claimview' ); - - assertOnMaybePromise( - assert, - claimview.options.helpMessage, - mw.msg( 'wikibase-claimview-snak-new-tooltip' ) - ); - } ); - - QUnit.asyncTest( 'Using tooltip specific for existing claims', 1, function( assert ) { - var $node = createClaimview( - new wb.datamodel.Claim( new wb.datamodel.PropertyValueSnak( 'p1', new dv.StringValue( 'g' ) ) ) - ), - claimview = $node.data( 'claimview' ); - - assertOnMaybePromise( - assert, - claimview.options.helpMessage, - mw.msg( 'wikibase-claimview-snak-tooltip', 'P1' ) - ); - } ); - -} )( jQuery, mediaWiki, wikibase, dataValues, valueFormatters, jQuery.valueview, QUnit ); diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js index 1928dd4..6bc6650 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js @@ -2,8 +2,38 @@ * @licence GNU GPL v2+ * @author Adrian Lang <adrian.l...@wikimedia.de> */ -( function( $, wb, QUnit, sinon ) { +( function( $, mw, wb, dv, QUnit, sinon ) { 'use strict'; + +QUnit.module( 'jquery.wikibase.statementview', QUnit.newMwEnvironment( { + teardown: function() { + $( '.test_statementview' ).each( function() { + var $statementview = $( this ), + statementview = $statementview.data( 'statementview' ); + + if( statementview ) { + statementview.destroy(); + } + + $statementview.remove(); + } ); + } +} ) ); + +var entityStore = { + get: function() { + return $.Deferred().resolve( new wb.store.FetchedContent( { + title: new mw.Title( 'Property:P1' ), + content: new wb.datamodel.Property( + 'P1', + 'string', + new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( [ + new wb.datamodel.Term( 'en', 'P1' ) + ] ) ) + ) + } ) ); + } +}; /** * @param {Object} [options] @@ -12,9 +42,7 @@ */ var createStatementview = function( options, $node ) { options = $.extend( { - entityStore: { - get: function () { return $.Deferred().resolve().promise(); } - }, + entityStore: entityStore, valueViewBuilder: 'i am a valueview builder', claimsChanger: 'I am a ClaimsChanger', entityChangersFactory: { @@ -32,20 +60,22 @@ .statementview( options ); }; -QUnit.module( 'jquery.wikibase.statementview', QUnit.newMwEnvironment( { - teardown: function() { - $( '.test_statementview' ).each( function() { - var $statementview = $( this ), - statementview = $statementview.data( 'statementview' ); - - if( statementview ) { - statementview.destroy(); - } - - $statementview.remove(); +/** + * @param {Object} assert QUnit.assert + * @param {*} maybePromise + * @param {*} expectedVal + */ +function assertOnMaybePromise( assert, maybePromise, expectedVal ) { + if( maybePromise.done ) { + maybePromise.done( function( val ) { + QUnit.start(); + assert.equal( val, expectedVal ); } ); + } else { + QUnit.start(); + assert.equal( maybePromise, expectedVal ); } -} ) ); +} QUnit.test( 'Create & destroy without value', function( assert ) { var $statementview = createStatementview(), @@ -77,7 +107,7 @@ statementview = $statementview.data( 'statementview' ); assert.ok( - statementview !== 'undefined', + statementview !== undefined, 'Created widget.' ); @@ -131,4 +161,31 @@ sinon.assert.calledWith( referencesChanger.removeReference, 'guid', reference ); } ); -}( jQuery, wikibase, QUnit, sinon ) ); +QUnit.asyncTest( 'Using the generic tooltip for new claims', 1, function( assert ) { + var $statementview = createStatementview(), + statementview = $statementview.data( 'statementview' ); + + assertOnMaybePromise( + assert, + statementview.options.helpMessage, + mw.msg( 'wikibase-claimview-snak-new-tooltip' ) + ); +} ); + +QUnit.asyncTest( 'Using tooltip specific for existing claims', 1, function( assert ) { + var $statementview = createStatementview( { + value: new wb.datamodel.Statement( new wb.datamodel.Claim( + new wb.datamodel.PropertyNoValueSnak( 'P1', new dv.StringValue( 'g' ) ) + ) ) + } ); + + var statementview = $statementview.data( 'statementview' ); + + assertOnMaybePromise( + assert, + statementview.options.helpMessage, + mw.msg( 'wikibase-claimview-snak-tooltip', 'P1' ) + ); +} ); + +}( jQuery, mediaWiki, wikibase, dataValues, QUnit, sinon ) ); diff --git a/lib/tests/qunit/jquery.wikibase/resources.php b/lib/tests/qunit/jquery.wikibase/resources.php index 38e9bc9..4b40aee 100644 --- a/lib/tests/qunit/jquery.wikibase/resources.php +++ b/lib/tests/qunit/jquery.wikibase/resources.php @@ -59,22 +59,6 @@ ), ), - 'jquery.wikibase.claimview.tests' => $moduleBase + array( - 'scripts' => array( - 'jquery.wikibase.claimview.tests.js', - ), - 'dependencies' => array( - 'dataValues.values', - 'jquery.valueview', - 'jquery.wikibase.claimview', - 'mediawiki.Title', - 'valueFormatters', - 'wikibase.datamodel', - 'wikibase.store.FetchedContent', - 'wikibase.ValueViewBuilder', - ), - ), - 'jquery.wikibase.descriptionview.tests' => $moduleBase + array( 'scripts' => array( 'jquery.wikibase.descriptionview.tests.js', @@ -275,9 +259,15 @@ 'jquery.wikibase.statementview.tests.js', ), 'dependencies' => array( + 'dataValues.values', 'jquery.wikibase.statementview', 'test.sinonjs', - 'wikibase.datamodel', + 'wikibase.datamodel.Claim', + 'wikibase.datamodel.PropertyNoValueSnak', + 'wikibase.datamodel.PropertyValueSnak', + 'wikibase.datamodel.Reference', + 'wikibase.datamodel.ReferenceList', + 'wikibase.datamodel.Statement', ), ), diff --git a/repo/includes/View/ClaimHtmlGenerator.php b/repo/includes/View/ClaimHtmlGenerator.php index fb5ef76..080b619 100644 --- a/repo/includes/View/ClaimHtmlGenerator.php +++ b/repo/includes/View/ClaimHtmlGenerator.php @@ -58,12 +58,17 @@ false ); + // TODO: Resolve if-statement after concept of Claim has been removed + // (see https://github.com/wmde/WikibaseDataModel/pull/317) if ( !( $claim instanceof Statement ) ) { - $claimHtml = wfTemplate( 'wb-claim', + $claimHtml = wfTemplate( 'wikibase-statementview', $claim->getGuid(), + '', $mainSnakHtml, $this->getHtmlForQualifiers( $claim->getQualifiers() ), - $editSectionHtml + $editSectionHtml, + '', + '' ); } else { /** @var Statement $claim */ @@ -90,14 +95,11 @@ $claim->getReferences() ); - $claimHtml = wfTemplate( 'wb-statement', + $claimHtml = wfTemplate( 'wikibase-statementview', + $claim->getGuid(), $rankHtml, - wfTemplate( 'wb-claim', - $claim->getGuid(), - $mainSnakHtml, - $this->getHtmlForQualifiers( $claim->getQualifiers() ), - '' - ), + $mainSnakHtml, + $this->getHtmlForQualifiers( $claim->getQualifiers() ), $editSectionHtml, $referencesHeading, $referencesHtml diff --git a/repo/resources/templates.php b/repo/resources/templates.php index 442d5e2..6c7a55e 100644 --- a/repo/resources/templates.php +++ b/repo/resources/templates.php @@ -81,19 +81,6 @@ </div> HTML; - $templates['wb-claim'] = -<<<HTML -<div class="wb-claimview"> - <div class="wb-claim wb-claim-$1"> - <div class="wb-claim-mainsnak" dir="auto"> - $2 <!-- wb-snak (Main Snak) --> - </div> - <div class="wb-claim-qualifiers">$3</div> - </div> - $4 <!-- wikibase-toolbar --> -</div> -HTML; - // TODO: .wb-snakview should not be part of the template; check uses of that class and move them // to .wb-snak $templates['wb-snak'] = @@ -111,16 +98,18 @@ </div> HTML; - // TODO: $4 is used for the non-JS toolbar to attach to. This parameter should be removed. - $templates['wb-statement'] = + $templates['wikibase-statementview'] = <<<HTML -<div class="wb-statement wb-statementview wb-claimview"> - <div class="wb-statement-rank">$1</div> - <!-- wb-claimview --> $2 - <!-- wikibase-toolbar --> $3 - <div class="wb-statement-references-heading">$4</div> - <div class="wb-statement-references"> - <!-- [0,*] wb-referenceview --> $5 +<div class="wikibase-statementview wikibase-statement-$1"> + <div class="wikibase-statementview-rankselector">$2</div> + <div class="wikibase-statementview-mainsnak-container"> + <div class="wikibase-statementview-mainsnak" dir="auto"><!-- wb-snak -->$3</div> + <div class="wikibase-statementview-qualifiers"><!-- wb-listview -->$4</div> + </div> + <!-- wikibase-toolbar -->$5 + <div class="wikibase-statementview-references-container"> + <div class="wikibase-statementview-references-heading">$6</div> + <div class="wikibase-statementview-references"><!-- wb-listview -->$7</div> </div> </div> HTML; -- To view, visit https://gerrit.wikimedia.org/r/178869 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4060c1f9ff56970e69a59b85ca716848f3dcef53 Gerrit-PatchSet: 12 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Henning Snater <henning.sna...@wikimedia.de> Gerrit-Reviewer: Henning Snater <henning.sna...@wikimedia.de> Gerrit-Reviewer: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de> Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits