Henning Snater has uploaded a new change for review. https://gerrit.wikimedia.org/r/154394
Change subject: Implemented jQuery.wikibase.labelview ...................................................................... Implemented jQuery.wikibase.labelview jQuery.wikibase.labelview replaces EditableLabel and LabelEditTool. PropertyEditTool and corresponding components have become obsolete by this change set and are removed in a subsequent change set. Change-Id: Id36ab9c2dd0a3acb0c19e34c3ce8c8b2e7b954bb --- M lib/WikibaseLib.hooks.php M lib/resources/Resources.php M lib/resources/jquery.wikibase/jquery.wikibase.descriptionview.js A lib/resources/jquery.wikibase/jquery.wikibase.labelview.js A lib/resources/jquery.wikibase/themes/default/jquery.wikibase.labelview.css M lib/resources/templates.php M lib/resources/wikibase.css D lib/resources/wikibase.ui.LabelEditTool.js D lib/resources/wikibase.ui.PropertyEditTool.EditableLabel.js M lib/resources/wikibase.ui.PropertyEditTool.css A lib/tests/qunit/jquery.wikibase/jquery.wikibase.labelview.tests.js D lib/tests/qunit/wikibase.ui.LabelEditTool.tests.js D lib/tests/qunit/wikibase.ui.PropertyEditTool.EditableLabel.tests.js M repo/includes/EntityView.php M repo/resources/Resources.php M repo/resources/wikibase.ui.entityViewInit.js M repo/resources/wikibase.ui.initTermBox.js 17 files changed, 961 insertions(+), 555 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase refs/changes/94/154394/6 diff --git a/lib/WikibaseLib.hooks.php b/lib/WikibaseLib.hooks.php index f7c859a..e19c1d7 100644 --- a/lib/WikibaseLib.hooks.php +++ b/lib/WikibaseLib.hooks.php @@ -83,9 +83,7 @@ 'tests/qunit/wikibase.RepoApi/wikibase.RepoApi.tests.js', 'tests/qunit/wikibase.RepoApi/wikibase.RepoApiError.tests.js', - 'tests/qunit/wikibase.ui.LabelEditTool.tests.js', 'tests/qunit/wikibase.ui.PropertyEditTool.tests.js', - 'tests/qunit/wikibase.ui.PropertyEditTool.EditableLabel.tests.js', 'tests/qunit/wikibase.ui.PropertyEditTool.EditableValue.tests.js', 'tests/qunit/wikibase.ui.PropertyEditTool.EditableValue.Interface.tests.js', @@ -170,6 +168,15 @@ ), ); + $testModules['qunit']['jquery.wikibase.labelview.tests'] = $moduleBase + array( + 'scripts' => array( + 'tests/qunit/jquery.wikibase/jquery.wikibase.labelview.tests.js', + ), + 'dependencies' => array( + 'jquery.wikibase.labelview', + ), + ); + $testModules['qunit']['jquery.wikibase.listview.tests'] = $moduleBase + array( 'scripts' => array( 'tests/qunit/jquery.wikibase/jquery.wikibase.listview.tests.js', diff --git a/lib/resources/Resources.php b/lib/resources/Resources.php index dc36178..0ec5dc9 100644 --- a/lib/resources/Resources.php +++ b/lib/resources/Resources.php @@ -299,8 +299,6 @@ 'wikibase.ui.PropertyEditTool.js', 'wikibase.ui.PropertyEditTool.EditableValue.js', 'wikibase.ui.PropertyEditTool.EditableValue.Interface.js', - 'wikibase.ui.PropertyEditTool.EditableLabel.js', - 'wikibase.ui.LabelEditTool.js', ), 'styles' => array( 'wikibase.ui.PropertyEditTool.css' @@ -502,6 +500,23 @@ ), ), + 'jquery.wikibase.labelview' => $moduleTemplate + array( + 'scripts' => array( + 'jquery.wikibase/jquery.wikibase.labelview.js' + ), + 'styles' => array( + 'jquery.wikibase/themes/default/jquery.wikibase.labelview.css', + ), + 'dependencies' => array( + 'jquery', + 'jquery.ui.TemplatedWidget', + 'jquery.wikibase.edittoolbar', + 'jquery.wikibase.toolbarcontroller', + 'wikibase', + 'wikibase.RepoApiError', + ), + ), + 'jquery.wikibase.sitelinkgroupview' => $moduleTemplate + array( 'scripts' => array( 'jquery.wikibase/jquery.wikibase.sitelinkgroupview.js' diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.descriptionview.js b/lib/resources/jquery.wikibase/jquery.wikibase.descriptionview.js index 0f548ad..d5c41a9 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.descriptionview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.descriptionview.js @@ -98,7 +98,7 @@ } ) .on( 'descriptionviewafterstopediting.' + this.widgetName - + ' eachchange.' + this.widgetName, + + ' eachchange.' + this.widgetName, function( event, dropValue ) { if( event.type !== 'eachchange' diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.labelview.js b/lib/resources/jquery.wikibase/jquery.wikibase.labelview.js new file mode 100644 index 0000000..c6abab9 --- /dev/null +++ b/lib/resources/jquery.wikibase/jquery.wikibase.labelview.js @@ -0,0 +1,460 @@ +/** + * @licence GNU GPL v2+ + * @author H. Snater < mediaw...@snater.com > + */ +( function( $, mw, wb ) { + 'use strict'; + + var PARENT = $.ui.TemplatedWidget; + +/** + * Manages a label. + * @since 0.5 + * @extends jQuery.ui.TemplatedWidget + * + * @option {Object|null} value + * Object representing the widget's value. + * Structure: { language: <{string}>, label: <{string|null}> } + * + * @option {string} [helpMessage] + * Default: mw.msg( 'wikibase-label-input-help-message' ) + * + * @options {string} entityId + * + * @option {wikibase.RepoApi} api + * + * @option {wikibase.store.EntityStore} entityStore + * + * @option {boolean} [showEntityId] + * Default: false + */ +$.widget( 'wikibase.labelview', PARENT, { + /** + * @see jQuery.ui.TemplatedWidget.options + */ + options: { + template: 'wikibase-labelview', + templateParams: [ + '', // additional class + '', // text + '', // entity id + '' // toolbar + ], + templateShortCuts: { + '$text': '.wikibase-labelview-text', + '$entityId': '.wikibase-labelview-entityid' + }, + value: null, + helpMessage: mw.msg( 'wikibase-label-input-help-message' ), + entityId: null, + api: null, + showEntityId: false + }, + + /** + * @type {boolean} + */ + _isInEditMode: false, + + /** + * @see jQuery.ui.TemplatedWidget._create + * + * @throws {Error} if required parameters are not specified properly. + */ + _create: function() { + if( !this.options.entityId || !this.options.api ) { + throw new Error( 'Required parameter(s) missing' ); + } + + this.options.value = this._checkValue( this.options.value ); + + PARENT.prototype._create.call( this ); + + var self = this, + value = this.options.value; + + this.element.attr( 'id', 'wb-firstHeading-' + this.options.entityId ); + + if( value && value.label !== '' && this.$text.text() === '' ) { + this._draw(); + } + + this.element + // TODO: Move that code to a sensible place (see jQuery.wikibase.entityview): + .on( + 'labelviewafterstartediting.' + this.widgetName + + ' eachchange.' + this.widgetName, + function( event ) { + if( !self.value().label ) { + // Since the widget shall not be in view mode when there is no value, triggering + // the event without a proper value is only done when creating the widget. Disabling + // other edit buttons shall be avoided. + // TODO: Move logic to a sensible place. + self.element.addClass( 'wb-empty' ); + return; + } + + self.element.removeClass( 'wb-empty' ); + + $( wb ).trigger( 'startItemPageEditMode', [ + self.element, + { + exclusive: false, + wbCopyrightWarningGravity: 'sw' + } + ] ); + } ) + .on( + 'labelviewafterstopediting.' + this.widgetName + + ' eachchange.' + this.widgetName, + function( event, dropValue ) { + if( + event.type !== 'eachchange' + || !self.options.value.label && !self.value().label + ) { + $( wb ).trigger( 'stopItemPageEditMode', [ + self.element, + { save: dropValue !== true } + ] ); + } + } ); + }, + + /** + * @see jQuery.ui.TemplatedWidget.destroy + */ + destroy: function() { + if( this._isInEditMode ) { + var self = this; + + this.element.one( this.widgetEventPrefix + 'afterstopediting', function( event ) { + PARENT.prototype.destroy.call( self ); + } ); + + this.cancelEditing(); + } else { + PARENT.prototype.destroy.call( this ); + } + }, + + /** + * Main draw routine. + */ + _draw: function() { + if( !this._isInEditMode ) { + this.element.removeClass( 'wb-edit' ); + this.$text.text( this.options.value.label ); + if( this.options.showEntityId ) { + this.$entityId.text( mw.msg( 'parentheses', this.options.entityId ) ); + } + return; + } + + // TODO: Inject correct placeholder via options + var self = this, + languageName = wb.getLanguageNameByCode( this.options.value.language ), + placeholder = mw.msg( 'wikibase-label-edit-placeholder' ); + + if( languageName ) { + placeholder = mw.msg( + 'wikibase-label-edit-placeholder-language-aware', + languageName + ); + } + + var $input = $( '<input/>' ) + .attr( 'placeholder', placeholder ) + .on( 'eachchange.' + this.widgetName, function( event ) { + self._trigger( 'change' ); + } ); + + if( this.options.value.label ) { + $input.val( this.options.value.label ); + } + + this.element.addClass( 'wb-edit' ); + this.$text.empty().append( $input ); + + this.$entityId.empty(); + }, + + /** + * Starts the widget's edit mode. + */ + startEditing: function() { + if( this._isInEditMode ) { + return; + } + + this._isInEditMode = true; + this._draw(); + + this._trigger( 'afterstartediting' ); + }, + + /** + * Stops the widget's edit mode. + * + * @param {boolean} dropValue + */ + stopEditing: function( dropValue ) { + var self = this; + + if( !this._isInEditMode || ( !this.isValid() || this.isInitialValue() ) && !dropValue ) { + return; + } + + if( dropValue ) { + this._afterStopEditing( dropValue ); + return; + } + + this.disable(); + + this._trigger( 'stopediting', null, [dropValue] ); + + // TODO: Performing API interaction should be managed in parent component (probably + // entityview) + this._save() + .done( function( response ) { + wb.getRevisionStore().setLabelRevision( response.entity.lastrevid ); + self.enable(); + self._afterStopEditing( dropValue ); + } ) + .fail( function( errorCode, details ) { + // TODO: API should return an Error object + var error = wb.RepoApiError.newFromApiResponse( errorCode, details, 'save' ); + self.setError( error ); + self.enable(); + } ); + }, + + /** + * @return {jQuery.Promise} + */ + _save: function() { + return this.options.api.setLabel( + this.options.entityId, + wb.getRevisionStore().getLabelRevision(), + this.value().label || '', + this.options.value.language + ); + }, + + /** + * Cancels the widget's edit mode. + */ + cancelEditing: function() { + this.stopEditing( true ); + }, + + /** + * Callback tearing down edit mode. + * + * @param {boolean} dropValue + */ + _afterStopEditing: function( dropValue ) { + if( !dropValue ) { + this.options.value = this.value(); + } else if( !this.options.value.label ) { + this.$text.children( 'input' ).val( '' ); + this._trigger( 'change' ); + } + + this._isInEditMode = false; + this._draw(); + + this._trigger( 'afterstopediting', null, [dropValue] ); + }, + + /** + * @return {boolean} + */ + isValid: function() { + // Function is required by edittoolbar definition. + return true; + }, + + /** + * @return {boolean} + */ + isInitialValue: function() { + var initialValue = this.options.value, + currentValue = this.value(); + + return currentValue.language === initialValue.language + && currentValue.label === initialValue.label; + }, + + /** + * Toggles error state. + * + * @param {Error} 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 jQuery.ui.TemplatedWidget._setOption + */ + _setOption: function( key, value ) { + if( key === 'value' ) { + value = this._checkValue( value ); + } + return PARENT.prototype._setOption.call( this, key, value ); + }, + + /** + * @param {*} value + * @return {Object} + * + * @throws {Error} if value is not defined properly. + */ + _checkValue: function( value ) { + if( !$.isPlainObject( value ) ) { + throw new Error( 'Value needs to be an object' ); + } else if( !value.language ) { + throw new Error( 'Value needs language to be specified' ); + } + + if( !value.label ) { + value.label = null; + } + + return value; + }, + + /** + * Gets/Sets the widget's value. + * + * @param {Object} [value] + * @return {Object|undefined} + */ + value: function( value ) { + if( value !== undefined ) { + this.option( 'value', value ); + return; + } + + if( !this._isInEditMode ) { + return this.option( 'value' ); + } + + var text = $.trim( this.$text.children( 'input' ).val() ); + + return { + language: this.options.value.language, + label: text !== '' ? text : null + }; + }, + + /** + * Puts Keyboard focus on the widget. + */ + focus: function() { + if( this._isInEditMode ) { + this.$text.children( 'input' ).focus(); + } + }, + + /** + * @see jQuery.ui.TemplatedWidget.disable + */ + disable: function() { + if( this._isInEditMode ) { + this.$text.children( 'input' ).prop( 'disabled', true ); + } + + return PARENT.prototype.disable.call( this ); + }, + + /** + * @see jQuery.ui.TemplatedWidget.enable + */ + enable: function() { + if( this._isInEditMode ) { + this.$text.children( 'input' ).prop( 'disabled', false ); + } + + return PARENT.prototype.enable.call( this ); + } + +} ); + +$.wikibase.toolbarcontroller.definition( 'edittoolbar', { + id: 'labelview', + events: { + labelviewcreate: function( event, toolbarcontroller ) { + var $labelview = $( event.target ), + labelview = $labelview.data( 'labelview' ); + + $labelview.edittoolbar( { + $container: $labelview.find( '.wikibase-labelview-container' ), + interactionWidgetName: $.wikibase.labelview.prototype.widgetName, + enableRemove: false + } ); + + $labelview.on( 'keyup', function( event ) { + if( event.keyCode === $.ui.keyCode.ESCAPE ) { + labelview.stopEditing( true ); + } else if( event.keyCode === $.ui.keyCode.ENTER ) { + labelview.stopEditing( false ); + } + } ); + + if( !labelview.value().label ) { + labelview.startEditing(); + } + + $labelview + .off( 'labelviewafterstopediting.edittoolbar' ) + .on( 'labelviewafterstopediting', function( event ) { + var edittoolbar = $( event.target ).data( 'edittoolbar' ); + if( labelview.value().label ) { + edittoolbar.toolbar.editGroup.toNonEditMode(); + } else { + labelview.startEditing(); + } + + edittoolbar.enable(); + edittoolbar.toggleActionMessage( function() { + edittoolbar.toolbar.editGroup.getButton( 'edit' ).focus(); + } ); + } ); + }, + 'labelviewchange labelviewafterstartediting': function( event ) { + var $labelview = $( event.target ), + labelview = $labelview.data( 'labelview' ), + toolbar = $labelview.data( 'edittoolbar' ).toolbar, + $btnSave = toolbar.editGroup.getButton( 'save' ), + btnSave = $btnSave.data( 'toolbarbutton' ), + enable = labelview.isValid() && !labelview.isInitialValue(), + $btnCancel = toolbar.editGroup.getButton( 'cancel' ), + btnCancel = $btnCancel.data( 'toolbarbutton' ), + currentLabel = labelview.value().label, + disableCancel = !currentLabel && labelview.isInitialValue(); + + btnSave[enable ? 'enable' : 'disable'](); + btnCancel[disableCancel ? 'disable' : 'enable'](); + }, + toolbareditgroupedit: function( event, toolbarcontroller ) { + var $labelview = $( event.target ).closest( ':wikibase-edittoolbar' ), + labelview = $labelview.data( 'labelview' ); + + if( !labelview ) { + return; + } + + labelview.focus(); + } + } +} ); + +}( jQuery, mediaWiki, wikibase ) ); diff --git a/lib/resources/jquery.wikibase/themes/default/jquery.wikibase.labelview.css b/lib/resources/jquery.wikibase/themes/default/jquery.wikibase.labelview.css new file mode 100644 index 0000000..2a65104 --- /dev/null +++ b/lib/resources/jquery.wikibase/themes/default/jquery.wikibase.labelview.css @@ -0,0 +1,118 @@ +/** + * @licence GNU GPL v2+ + * @author H. Snater < mediaw...@snater.com > + */ +/* TODO: Re-evaluate all styles and clean-up */ +.wikibase-labelview { + float: left; + position: relative; + width: 100%; +} + +.wb-firstHeading .wikibase-labelview-container.wb-edit .wikibase-labelview-container { + background-color: #D6F3FF; +} +.wb-firstHeading .wikibase-labelview-container.wb-empty .wikibase-labelview-container { + background-color: inherit; +} + +.wb-firstHeading .wikibase-labelview-container { + margin: .3em .3em .13em 0; + padding-right: 19em; +} + +.wb-firstHeading .wikibase-labelview .wikibase-labelview-container { + margin-left: 10px; + word-wrap: break-word; +} + +.wb-firstHeading .wikibase-labelview.wb-edit .wikibase-labelview-container { + margin-left: 7px; +} + +.wb-firstHeading .wikibase-labelview-text { + font-size: 188%; + line-height: 1.2; +} + +.wikibase-labelview .wikibase-labelview-entityid { + color: #A1A1A1; +} + +#content .wb-firstHeading { + font-size: 100%; /* required since Gerrit Ic5ba836364d04b2c3814777b69b5f47fce25292a */ +} + +.wb-firstHeading { + border-bottom: 0; + margin-bottom: 0; /* FIXME: Should be removed if the Typography refresh is stable */ + padding-top: 0; /* FIXME: Should be removed if the Typography refresh is stable */ + clear: both; /* so success bar after new item created won't float heading */ +} + +.wb-firstHeading span { + line-height: 100%; +} + +.wikibase-labelview .wikibase-labelview-entityid { + /* In RTL UI, if the last word of the label is LTR, + * the supplement will get jumbled without isolation */ + unicode-bidi: -moz-isolate; + unicode-bidi: -webkit-isolate; + unicode-bidi: isolate; +} + +.wb-firstHeading .wb-editsection { + /* this nodes font size will affect the toolbar padding which is specified in em; therefore, the + font size should be the same as on every other toolbar container node */ + font-size: 100%; +} + +/* vertical positioning */ +/* the following lines are used to vertically position the toolbar on the baseline of the heading +(label) which has a bigger font size */ +.wb-firstHeading .wb-editsection { + /* FIXME: Should use the LESS variable @content-font-family */ + font-family: sans-serif; + line-height: 188%; + top: .3em; /* even out margin of label container in view mode */ +} +.wb-firstHeading .wikibase-toolbar { + font-size: 100%; + line-height: 1.2; /* adjust to height of value */ + padding-top: 1px; /* even out border of input box */ +} + +.wb-firstHeading .wikibase-toolbar .wikibase-toolbareditgroup { + font-size: 53%; + margin-bottom: 2px; +} +.wb-firstHeading .wikibase-toolbar .wikibase-toolbar, /* inner group (buttons) */ +.wb-firstHeading .wikibase-toolbar .wikibase-toolbarlabel /* tooltip */ { + font-size: 100%; + margin-bottom: 0; /* even out border of label container in view mode */ +} + +.wikibase-labelview input { + width: 100%; + font-family: inherit; + font-size: inherit; + height: 1.2em; +} + +/* The wait message displayed when saving the label has to be customized due to diverging font +sizes and line heights within the heading */ +.wikibase-labelview .wb-actionmsg { + display: inline-block; + font-size: 188%; + line-height: 1.2; + padding-top: 1px; + margin: 0; +} +.wikibase-labelview .wb-actionmsg span { + font-size: 53%; +} + +.wb-firstHeading .wb-editsection > .wikibase-toolbar { + font-size: 188%; +} diff --git a/lib/resources/templates.php b/lib/resources/templates.php index 813b00c..305552f 100644 --- a/lib/resources/templates.php +++ b/lib/resources/templates.php @@ -159,14 +159,27 @@ </div> HTML; - $templates['wb-label'] = + $templates['wikibase-h1'] = // add an h1 for displaying the entity's label; the actual firstHeading is being hidden by // css since the original MediaWiki DOM does not represent a Wikidata entity's structure // where the combination of label and description is the unique "title" of an entity which // should not be semantically disconnected by having elements in between, like siteSub, // contentSub and jump-to-nav <<<HTML -<h1 id="wb-firstHeading-$1" class="wb-firstHeading wb-value-row">$2</h1> +<h1 id="wb-firstHeading-$1" class="wb-firstHeading"> + <!-- wikibase-labelview -->$2 +</h1> +HTML; + + $templates['wikibase-labelview'] = +<<<HTML +<div class="wikibase-labelview $1"> + <div class="wikibase-labelview-container"> + <span class="wikibase-labelview-text">$2</span> + <span class="wikibase-labelview-entityid">$3</span> + <!-- wikibase-toolbar -->$4 + </div> +</div> HTML; $templates['wikibase-descriptionview'] = diff --git a/lib/resources/wikibase.css b/lib/resources/wikibase.css index a6c905b..8367da0 100644 --- a/lib/resources/wikibase.css +++ b/lib/resources/wikibase.css @@ -160,88 +160,6 @@ /********** /BASIC LAYOUT **********/ -/********** LABEL & DESCRIPTION **********/ - -.wb-ui-labeledittool .wb-value-container { - padding-right: 19em; /* width of toolbar + white space border */ -} - -/********** LABEL **********/ - -#content .wb-firstHeading { - font-size: 100%; /* required since Gerrit Ic5ba836364d04b2c3814777b69b5f47fce25292a */ -} - -.wb-firstHeading { - border-bottom: 0; - margin-bottom: 0; /* FIXME: Should be removed if the Typography refresh is stable */ - padding-top: 0; /* FIXME: Should be removed if the Typography refresh is stable */ - clear: both; /* so success bar after new item created won't float heading */ -} - -.wb-firstHeading span { - line-height: 100%; -} - -/* the label edit tool styles have to be further customized due to the differing font sizes of the -label and its toolbar */ - -/* preventing layout jittering toggling between view and edit mode */ -.wb-firstHeading .wb-value { - font-size: 188%; - line-height: 1.2; /* adjust line height to input box height in edit mode */ - padding: 1px 0; /* even out border of input box in edit mode */ -} - -.wb-firstHeading .wb-value-supplement { - line-height: 188%; - /* In RTL UI, if the last word of the label is LTR, - * the supplement will get jumbled without isolation */ - unicode-bidi: -moz-isolate; - unicode-bidi: -webkit-isolate; - unicode-bidi: isolate; -} - -.wb-firstHeading .wb-value-container { - display: block; - margin: .3em .3em .13em 10px; /* h1 natively has 0.17em bottom padding to avoid clipping */ -} - -.wb-firstHeading .wb-editsection { - /* this nodes font size will affect the toolbar padding which is specified in em; therefore, the - font size should be the same as on every other toolbar container node */ - font-size: 100%; -} - -/* vertical positioning */ -/* the following lines are used to vertically position the toolbar on the baseline of the heading -(label) which has a bigger font size */ -.wb-firstHeading .wb-editsection { - /* FIXME: Should use the LESS variable @content-font-family */ - font-family: sans-serif; - line-height: 188%; - top: .3em; /* even out margin of label container in view mode */ -} -.wb-firstHeading .wikibase-toolbar { - font-size: 188%; - line-height: 1.2; /* adjust to height of value */ - padding-top: 1px; /* even out border of input box */ -} -.wb-firstHeading .wikibase-toolbar .wikibase-toolbareditgroup { - font-size: 53%; - margin-bottom: 2px; -} -.wb-firstHeading .wikibase-toolbar .wikibase-toolbar, /* inner group (buttons) */ -.wb-firstHeading .wikibase-toolbar .wikibase-toolbarlabel /* tooltip */ { - font-size: 100%; - margin-bottom: 0; /* even out border of label container in view mode */ -} - -/********** /LABEL **********/ - -/********** /LABEL & DESCRIPTION **********/ - - /********** TERMS **********/ .wb-terms .wb-value { @@ -332,6 +250,7 @@ padding-right: 0; } +.wb-terms .wikibase-labelview, .wb-terms .wikibase-descriptionview { display: block; float: none; @@ -340,6 +259,7 @@ width: auto; } +.wb-terms .wikibase-labelview.wb-edit, .wb-terms .wikibase-descriptionview.wb-edit { padding: 9px 8px 9px 7px; } diff --git a/lib/resources/wikibase.ui.LabelEditTool.js b/lib/resources/wikibase.ui.LabelEditTool.js deleted file mode 100644 index 97a7aba..0000000 --- a/lib/resources/wikibase.ui.LabelEditTool.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @licence GNU GPL v2+ - * @author Daniel Werner < daniel.werner at wikimedia.de > - */ -( function( mw, wb, util, $ ) { -'use strict'; -var PARENT = wb.ui.PropertyEditTool; - -/** - * Module for 'Wikibase' extensions user interface functionality for editing the heading representing an items label. - * @constructor - * @see wb.ui.PropertyEditTool - * @since 0.1 - */ -wb.ui.LabelEditTool = util.inherit( PARENT, { - /** - * @see wb.ui.SECONDARY_UI_CLASSES - */ - SECONDARY_UI_CLASSES: PARENT.prototype.SECONDARY_UI_CLASSES + ' wb-ui-labeledittool', - - /** - * @see wb.ui.PropertyEditTool._getValueElems() - */ - _getValueElems: function() { - return this._subject.children( 'h1.wb-firstHeading span' ); - }, - - /** - * @see wb.ui.PropertyEditTool._init() - */ - _init: function( subject, options ) { - // setting default options - options = $.extend( {}, PARENT.prototype._options, { - /** - * @see wikibase.ui.PropertyEditTool.allowsMultipleValues - */ - allowsMultipleValues: false - }, options ); - PARENT.prototype._init.call( this, subject, options ); - }, - - /** - * @see wb.ui.PropertyEditTool.getPropertyName() - * - * @return string 'label' - */ - getPropertyName: function() { - return 'label'; - }, - - /** - * @see wb.ui.PropertyEditTool.getEditableValuePrototype - */ - getEditableValuePrototype: function() { - return PARENT.EditableLabel; - } - -} ); - -} )( mediaWiki, wikibase, util, jQuery ); diff --git a/lib/resources/wikibase.ui.PropertyEditTool.EditableLabel.js b/lib/resources/wikibase.ui.PropertyEditTool.EditableLabel.js deleted file mode 100644 index 886c3cc..0000000 --- a/lib/resources/wikibase.ui.PropertyEditTool.EditableLabel.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @licence GNU GPL v2+ - * @author Daniel Werner - * @author Tobias Gritschacher - */ -( function( mw, wb, util, $ ) { -'use strict'; - -var PARENT = wb.ui.PropertyEditTool.EditableValue; - -/** - * Serves the input interface for the label of an item, extends EditableValue. - * @constructor - * @extends wb.ui.PropertyEditTool.EditableValue - * @since 0.1 - */ -var SELF = wb.ui.PropertyEditTool.EditableLabel = util.inherit( PARENT, { - /** - * @see wikibase.ui.PropertyEditTool.EditableValue.API_VALUE_KEY - */ - API_VALUE_KEY: 'labels', - - /** - * @see wb.ui.PropertyEditTool.EditableValue._options - */ - _options: $.extend( {}, PARENT.prototype._options, { - inputHelpMessageKey: 'wikibase-label-input-help-message' - } ), - - /** - * see wb.ui.PropertyEditTool.EditableValue.startEditing - */ - startEditing: function() { - var self = this; - return PARENT.prototype.startEditing.call( this ).done( function() { - if( !self._interfaces[0].isEmpty() ) { - self._subject.children( '.wb-value-supplement' ).hide(); - } - }) ; - }, - - /** - * @see wb.ui.PropertyEditTool.EditableValue.stopEditing - */ - stopEditing: function( save ) { - var self = this; - return PARENT.prototype.stopEditing.call( this, save ).done( function() { - self._subject.children( '.wb-value-supplement' ).show(); - } ); - }, - - /** - * @see wikibase.ui.PropertyEditTool.EditableValue._setRevisionIdFromApiResponse - */ - _setRevisionIdFromApiResponse: function( response ) { - wb.getRevisionStore().setLabelRevision( response.lastrevid ); - return true; - }, - - /** - * Calling the corresponding method in the wikibase.RepoApi - * - * @return {jQuery.Promise} - */ - queryApi: function() { - return this._api.setLabel( - mw.config.get( 'wbEntityId' ), - wb.getRevisionStore().getLabelRevision(), - this.getValue().toString(), - this.getValueLanguageContext() - ); - } -} ); - -/** - * @see wb.ui.PropertyEditTool.EditableValue.newFromDom - */ -SELF.newFromDom = function( subject, options, toolbar ) { - var ev = wb.ui.PropertyEditTool.EditableValue, - $subject = $( subject ), - $interfaceParent = $subject.find( '.wb-value' ).first(), - languageName, placeHolderMsg, simpleInterface; - - options = options || {}; - options.valueLanguageContext = - options.valueLanguageContext || ev.getValueLanguageContextFromDom( $interfaceParent ); - - languageName = wb.getLanguageNameByCode( options.valueLanguageContext ); - - if ( languageName ) { - placeHolderMsg = mw.msg( - 'wikibase-label-edit-placeholder-language-aware', - languageName - ); - } else { - placeHolderMsg = mw.msg( 'wikibase-label-edit-placeholder' ); - } - - simpleInterface = new ev.Interface( $interfaceParent, { - 'inputPlaceholder': placeHolderMsg, - 'autoExpand': false - } ); - - // TODO: get rid of this - simpleInterface.normalize = function( value ) { - value = ev.Interface.prototype.normalize.call( this, value ); - // make sure we don't ever allow two+ sequential spaces in an item's label: - value = value.replace( /\s+/g, ' ' ); - return value; - }; - - return new SELF( $subject, options, simpleInterface, toolbar ); -}; - -}( mediaWiki, wikibase, util, jQuery ) ); diff --git a/lib/resources/wikibase.ui.PropertyEditTool.css b/lib/resources/wikibase.ui.PropertyEditTool.css index d335f53..8a447f0 100644 --- a/lib/resources/wikibase.ui.PropertyEditTool.css +++ b/lib/resources/wikibase.ui.PropertyEditTool.css @@ -41,43 +41,6 @@ /********** /BASIC LAYOUT **********/ -/***** LABEL *****/ - -.wb-ui-labeledittool .wb-ui-propertyedittool-editablevalue-ineditmode .wb-value { - padding: 0; /* even out border of input box in edit mode */ -} - -.wb-ui-labeledittool .wb-ui-propertyedittool-editablevalue-ineditmode { - margin-left: 7px; /* h1 natively has 0.17em bottom padding to avoid clipping */ -} - -.wb-ui-labeledittool .wb-ui-propertyedittool-editablevalue-ineditmode .wb-ui-propertyedittool-editablevalue-toolbarparent { - top: .3em; -} - -.wb-ui-labeledittool input { - width: 100%; - font-family: inherit; - font-size: inherit; - height: 1.2em; -} - -/* The wait message displayed when saving the label has to be customized due to differging font -sizes and line heights within the heading */ -.wb-ui-labeledittool .wb-ui-propertyedittool-editablevalue-waitmsg { - display: inline-block; - font-size: 188%; - line-height: 1.2; - padding-top: 1px; - margin: 0; -} -.wb-ui-labeledittool .wb-ui-propertyedittool-editablevalue-waitmsg span { - font-size: 53%; -} - -/***** /LABEL *****/ - - /********** TAGADATA **********/ ul.tagadata { diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.labelview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.labelview.tests.js new file mode 100644 index 0000000..d731969 --- /dev/null +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.labelview.tests.js @@ -0,0 +1,191 @@ +/** + * @licence GNU GPL v2+ + * @author H. Snater < mediaw...@snater.com > + */ + +( function( $, jQuery, QUnit ) { +'use strict'; + +/** + * @param {Object} [options] + * @param {jQuery} [$node] + * @return {jQuery} + */ +var createLabelview = function( options, $node ) { + options = $.extend( { + entityId: 'i am an entity id', + api: 'i am an api', + value: { + language: 'en', + label: 'test label' + } + }, options || {} ); + + $node = $node || $( '<div/>' ).appendTo( 'body' ); + + var $labelview = $node + .addClass( 'test_labelview' ) + .labelview( options ); + + $labelview.data( 'labelview' )._save = function() { + return $.Deferred().resolve( { + entity: { + lastrevid: 'i am a revision id' + } + } ).promise(); + }; + + return $labelview; +}; + +QUnit.module( 'jquery.wikibase.labelview', QUnit.newMwEnvironment( { + teardown: function() { + $( '.test_labelview' ).each( function() { + var $labelview = $( this ), + labelview = $labelview.data( 'labelview' ); + + if( labelview ) { + labelview.destroy(); + } + + $labelview.remove(); + } ); + } +} ) ); + +QUnit.test( 'Create & destroy', function( assert ) { + assert.throws( + function() { + createLabelview( { value: null } ); + }, + 'Throwing error when trying to initialize widget without a value.' + ); + + var $labelview = createLabelview(), + labelview = $labelview.data( 'labelview' ); + + assert.ok( + labelview !== 'undefined', + 'Created widget.' + ); + + labelview.destroy(); + + assert.ok( + $labelview.data( 'labelview' ) === undefined, + 'Destroyed widget.' + ); +} ); + +QUnit.test( 'startEditing() & stopEditing()', 5, function( assert ) { + var $labelview = createLabelview(), + labelview = $labelview.data( 'labelview' ); + + $labelview + .on( 'labelviewafterstartediting', function( event ) { + assert.ok( + true, + 'Started edit mode.' + ); + } ) + .on( 'labelviewafterstopediting', function( event, dropValue ) { + assert.ok( + true, + 'Stopped edit mode.' + ); + } ); + + labelview.startEditing(); + + assert.ok( + labelview.$text.find( 'input' ).length === 1, + 'Generated input element.' + ); + + labelview.startEditing(); // should not trigger event + labelview.stopEditing( true ); + labelview.stopEditing( true ); // should not trigger event + labelview.stopEditing(); // should not trigger event + labelview.startEditing(); + + labelview.$text.find( 'input' ).val( '' ); + + labelview.stopEditing(); +} ); + +QUnit.test( 'isInitialValue()', function( assert ) { + var $labelview = createLabelview(), + labelview = $labelview.data( 'labelview' ); + + labelview.startEditing(); + + assert.ok( + labelview.isInitialValue(), + 'Verified isInitialValue() returning true.' + ); + + labelview.$text.find( 'input' ).val( 'changed' ); + + assert.ok( + !labelview.isInitialValue(), + 'Verified isInitialValue() returning false after changing value.' + ); + + labelview.$text.find( 'input' ).val( 'test label' ); + + assert.ok( + labelview.isInitialValue(), + 'Verified isInitialValue() returning true after resetting to initial value.' + ); +} ); + +QUnit.test( 'setError()', function( assert ) { + var $labelview = createLabelview(), + labelview = $labelview.data( 'labelview' ); + + $labelview + .on( 'labelviewtoggleerror', function( event, error ) { + assert.ok( + true, + 'Triggered "toggleerror" event.' + ); + } ); + + labelview.setError(); +} ); + +QUnit.test( 'value()', function( assert ) { + var $labelview = createLabelview(), + labelview = $labelview.data( 'labelview' ); + + assert.throws( + function() { + labelview.value( null ); + }, + 'Trying to set no value fails.' + ); + + labelview.value( { + language: 'de', + label: 'changed label' + } ); + + assert.ok( + labelview.value().language === 'de' + && labelview.value().label === 'changed label', + 'Set new value.' + ); + + labelview.value( { + language: 'en', + label: null + } ); + + assert.ok( + labelview.value().language === 'en' + && labelview.value().label === null, + 'Set another value.' + ); +} ); + +}( jQuery, wikibase, QUnit ) ); diff --git a/lib/tests/qunit/wikibase.ui.LabelEditTool.tests.js b/lib/tests/qunit/wikibase.ui.LabelEditTool.tests.js deleted file mode 100644 index 5d08347..0000000 --- a/lib/tests/qunit/wikibase.ui.LabelEditTool.tests.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * QUnit tests heading edit tool - * @see https://www.mediawiki.org/wiki/Extension:Wikibase - * - * @since 0.1 - * - * @licence GNU GPL v2+ - * @author H. Snater <mediaw...@snater.com> - */ - -( function( mw, wb, $, QUnit, undefined ) { - 'use strict'; - - QUnit.module( 'wikibase.ui.LabelEditTool', QUnit.newWbEnvironment( { - setup: function() { - this.h1 = $( '<h1/>', { 'class': 'wb-firstHeading' } ); - this.span = $( '<span/>' ).append( $( '<span/>', { - 'class': 'wb-value', - text: 'Text' - } ) ).appendTo( this.h1 ); - this.subject = new wb.ui.LabelEditTool( this.h1, { api: {} } ); - }, - teardown: function() {} - } ) ); - - QUnit.test( 'basic check', function( assert ) { - - assert.ok( - this.subject instanceof wb.ui.LabelEditTool, - 'instantiated HeadingEditTool' - ); - - assert.equal( - this.subject._getValueElems()[0], - this.span[0], - 'checked getting value element' - ); - - assert.equal( - this.subject.getPropertyName(), - 'label', - 'property name is label' - ); - - assert.equal( - this.subject.getEditableValuePrototype(), - wb.ui.PropertyEditTool.EditableLabel, - 'retrieved prototype' - ); - - assert.equal( - this.subject.getOption( 'allowsMultipleValues' ), - false, - 'does not allow multiple values' - ); - - this.subject.destroy(); - - assert.equal( - this.h1.children().length + this.h1.children().first().children().length, - 1, - 'cleaned DOM' - ); - - assert.equal( - this.h1.children()[0], - this.span[0], - 'span child remains' - ); - - } ); - -}( mediaWiki, wikibase, jQuery, QUnit ) ); diff --git a/lib/tests/qunit/wikibase.ui.PropertyEditTool.EditableLabel.tests.js b/lib/tests/qunit/wikibase.ui.PropertyEditTool.EditableLabel.tests.js deleted file mode 100644 index 55ce8b4..0000000 --- a/lib/tests/qunit/wikibase.ui.PropertyEditTool.EditableLabel.tests.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * QUnit tests for editable label component - * @see https://www.mediawiki.org/wiki/Extension:Wikibase - * - * @since 0.1 - * - * @licence GNU GPL v2+ - * @author H. Snater <mediaw...@snater.com> - * @author Marius Hoch < h...@online.de > - */ - -( function( mw, wb, $, QUnit, undefined ) { - 'use strict'; - - function setup( options ) { - options = $.extend( { api: {} }, options || {} ); - - var $node = $( '<div><div class="wb-value"/></div>' ); - $( '<div/>', { id: 'parent' } ).append( $node ); - - var propertyEditTool = new wb.ui.PropertyEditTool( $node ), - subject = wb.ui.PropertyEditTool.EditableLabel.newFromDom( $node, options ), - toolbar = propertyEditTool._buildSingleValueToolbar(); - - subject.setToolbar( toolbar ); - - return subject; - } - - QUnit.module( 'wikibase.ui.PropertyEditTool.EditableLabel', QUnit.newWbEnvironment( { - setup: function() { - this.subject = setup(); - }, - teardown: function() {} - } ) ); - - QUnit.test( 'basic', function( assert ) { - - assert.ok( - this.subject instanceof wb.ui.PropertyEditTool.EditableLabel, - 'instantiated editable label' - ); - - assert.equal( - this.subject._interfaces.length, - 1, - 'initialized single interface' - ); - - assert.ok( - this.subject.getInputHelpMessage() !== '', - 'help message not empty' - ); - - this.subject.destroy(); - - assert.equal( - this.subject._toolbar, - null, - 'destroyed toolbar' - ); - - assert.equal( - this.subject._instances, - null, - 'destroyed instances' - ); - - } ); - - QUnit.test( 'placeholder', function( assert ) { - var oldGetLanguageNameByCode = wb.getLanguageNameByCode; - - wb.getLanguageNameByCode = function( code ) { - if ( code === 'de' ) { - return 'Deutsch'; - } else { - return ''; - } - }; - - var withLanguage = setup( { valueLanguageContext: 'de' } ), - withoutLanguage = setup( { valueLanguageContext: 'ru' } ); - - assert.equal( - withLanguage._interfaces[0]._options.inputPlaceholder, - mw.msg( - 'wikibase-label-edit-placeholder-language-aware', - 'Deutsch' - ) - ); - - assert.equal( - withoutLanguage._interfaces[0]._options.inputPlaceholder, - mw.msg( 'wikibase-label-edit-placeholder' ) - ); - - wb.getLanguageNameByCode = oldGetLanguageNameByCode; - } ); - -}( mediaWiki, wikibase, jQuery, QUnit ) ); diff --git a/repo/includes/EntityView.php b/repo/includes/EntityView.php index 8ea7402..700f5df 100644 --- a/repo/includes/EntityView.php +++ b/repo/includes/EntityView.php @@ -401,22 +401,17 @@ $label = $entity->getLabel( $languageCode ); $entityId = $entity->getId(); $idString = 'new'; - $supplement = ''; - if ( $entityId !== null ) { - $idString = $entityId->getSerialization(); - $supplement .= wfTemplate( 'wb-property-value-supplement', wfMessage( 'parentheses', $idString ) ); - if ( $editable ) { - $supplement .= $this->getHtmlForEditSection( 'SetLabel', array( $idString, $languageCode ) ); - } - } - - $html = wfTemplate( 'wb-label', + $html = wfTemplate( 'wikibase-h1', $idString, - wfTemplate( 'wb-property', + wfTemplate( 'wikibase-labelview', $label === false ? 'wb-value-empty' : '', - htmlspecialchars( $label === false ? wfMessage( 'wikibase-label-empty' )->text() : $label ), - $supplement + htmlspecialchars( $label === false + ? wfMessage( 'wikibase-label-empty' )->text() + : $label + ), + wfMessage( 'parentheses', $entityId->getSerialization() )->text(), + $this->getHtmlForEditSection( 'SetLabel', array( $idString, $languageCode ) ) ) ); diff --git a/repo/resources/Resources.php b/repo/resources/Resources.php index 5fe5b10..d09d6a3 100644 --- a/repo/resources/Resources.php +++ b/repo/resources/Resources.php @@ -30,6 +30,7 @@ 'jquery.wikibase.aliasesview', 'jquery.wikibase.descriptionview', 'jquery.wikibase.entityview', + 'jquery.wikibase.labelview', 'jquery.wikibase.toolbarcontroller', 'jquery.wikibase.wbtooltip', 'jquery.cookie', diff --git a/repo/resources/wikibase.ui.entityViewInit.js b/repo/resources/wikibase.ui.entityViewInit.js index 81dec62..1a1a2b2 100644 --- a/repo/resources/wikibase.ui.entityViewInit.js +++ b/repo/resources/wikibase.ui.entityViewInit.js @@ -30,29 +30,6 @@ var repoApi = new wb.RepoApi(); - // add an edit tool for the main label. This will be integrated into the heading nicely: - var $firstHeading = $( '.wb-firstHeading' ); - if ( $firstHeading.length ) { // Special pages do not have a custom wb heading - var labelEditTool = new wb.ui.LabelEditTool( $firstHeading[0], { api: repoApi } ), - editableLabel = labelEditTool.getValues( true )[0], // [0] will always be set - fn = function( event, origin ) { - // Limit the global stopItemPageEditMode event to that element - if ( event.type !== 'stopItemPageEditMode' || origin === editableLabel ) { - var title = editableLabel.isEmpty() - ? mw.config.get( 'wgTitle' ) - : editableLabel.getValue()[0]; - - // update 'title' tag - $( 'title' ).text( mw.msg( 'pagetitle', title ) ); - } - }; - - editableLabel.getSubject().on( 'eachchange', fn ); - // Can't use afterStopEditing because it does not fire on cancel - // but this is needed to reset the title - $( wb ).on( 'stopItemPageEditMode', fn ); - } - registerEditRestrictionHandlers(); if( mw.config.get( 'wbEntity' ) !== null ) { @@ -242,6 +219,36 @@ wb.compileEntityStoreFromMwConfig( entityStore ); // TODO: Integrate into entityview + $( '.wikibase-labelview' ) + .toolbarcontroller( { + edittoolbar: ['labelview'] + } ) + .labelview( { + value: { + language: mw.config.get( 'wgUserLanguage' ), + label: $( '.wikibase-labelview' ).hasClass( 'wb-empty' ) + ? null + // FIXME: entity object should not contain fallback strings + : entity.getLabel( mw.config.get( 'wgUserLanguage' ) ) + }, + helpMessage: mw.msg( + 'wikibase-description-input-help-message', + wb.getLanguageNameByCode( mw.config.get( 'wgUserLanguage' ) ) + ), + entityId: entity.getId(), + api: repoApi, + showEntityId: true + } ) + .on( 'labelviewchange', function( event ) { + var $labelview = $( event.target ), + labelview = $labelview.data( 'labelview' ), + label = labelview.value().label; + + $( 'title' ).text( + mw.msg( 'pagetitle', label && label !== '' ? label : mw.config.get( 'wgTitle' ) ) + ); + } ); + $( '.wikibase-descriptionview' ) .toolbarcontroller( { edittoolbar: ['descriptionview'] @@ -317,7 +324,8 @@ // it to a sensible place. $( wb ) .on( 'startItemPageEditMode', function( event, target, options ) { - $( ':wikibase-descriptionview, :wikibase-aliasesview, :wikibase-sitelinklistview' ) + $( ':wikibase-labelview, :wikibase-descriptionview, :wikibase-aliasesview, ' + + ':wikibase-sitelinklistview' ) .not( target ) .find( ':wikibase-toolbar' ) .each( function() { @@ -328,6 +336,16 @@ $( ':wikibase-aliasesview' ).find( ':wikibase-toolbar' ).each( function() { $( this ).data( 'toolbar' ).enable(); } ); + $( ':wikibase-labelview' ).each( function() { + var $labelview = $( this ), + labelview = $labelview.data( 'labelview' ); + + if( labelview.value().label ) { + $labelview.find( ':wikibase-toolbar' ).each( function() { + $( this ).data( 'toolbar' ).enable(); + } ); + } + } ); $( ':wikibase-descriptionview' ).each( function() { var $descriptionview = $( this ), descriptionview = $descriptionview.data( 'descriptionview' ); diff --git a/repo/resources/wikibase.ui.initTermBox.js b/repo/resources/wikibase.ui.initTermBox.js index 57438e3..25db8d6 100644 --- a/repo/resources/wikibase.ui.initTermBox.js +++ b/repo/resources/wikibase.ui.initTermBox.js @@ -16,8 +16,7 @@ */ wb.ui.initTermBox = function( entity, api ) { mw.hook( 'wikibase.domready' ).add( function() { - var termsValueTools = [], - $termBoxRows = $( 'tr.wb-terms-label, tr.wb-terms-description' ), + var $termBoxRows = $( 'tr.wb-terms-label, tr.wb-terms-description' ), userSpecifiedLanguages = mw.config.get( 'wbUserSpecifiedLanguages' ), hasSpecifiedLanguages = userSpecifiedLanguages && userSpecifiedLanguages.length, isUlsDefined = mw.uls !== undefined @@ -25,7 +24,7 @@ && $.uls.data !== undefined; $( '.wb-terms' ).toolbarcontroller( { - edittoolbar: ['terms-descriptionview'] + edittoolbar: ['terms-labelview', 'terms-descriptionview'] } ); // Skip if having no extra languages is what the user wants @@ -50,39 +49,37 @@ } $termBoxRows.each( function() { - var $termsRow = $( this ); - - if( $termsRow.hasClass( 'wb-terms-label' ) ) { - var editTool = wb.ui.PropertyEditTool.EditableLabel, - $toolbar = mw.template( 'wikibase-toolbar', '', '' ).toolbar(), - toolbar = $toolbar.data( 'toolbar' ), - $editGroup = mw.template( 'wikibase-toolbareditgroup', '', '' ) - .toolbareditgroup(); - - toolbar.addElement( $editGroup ); - - // TODO: EditableLabel should not assume that this is set - toolbar.$editGroup = $editGroup; - - termsValueTools.push( editTool.newFromDom( $termsRow, { - api: api - }, toolbar ) ); - - return true; - } - - var languageCode; + var $termsRow = $( this ), + languageCode; // TODO: Find more sane way to figure out language code. $.each( $termsRow.attr( 'class' ).split( ' ' ), function( i, cssClass ) { if( cssClass.indexOf( 'wb-terms-' ) === 0 + && cssClass.indexOf( 'wb-terms-label' ) === -1 && cssClass.indexOf( 'wb-terms-description' ) === -1 ) { languageCode = cssClass.replace( /wb-terms-/, '' ); return false; } } ); + + if( $termsRow.hasClass( 'wb-terms-label' ) ) { + $termsRow.children( 'td' ).eq( 1 ).labelview( { + value: { + language: languageCode, + label: entity.getLabel( languageCode ) + }, + helpMessage: mw.msg( + 'wikibase-label-input-help-message', + wb.getLanguageNameByCode( languageCode ) + ), + entityId: entity.getId(), + api: api + } ); + + return true; + } $termsRow.children( 'td' ).first().descriptionview( { value: { @@ -101,29 +98,25 @@ $( wb ) .on( 'startItemPageEditMode', function( event, origin ) { - // Disable language terms table's editable value or mark it as the active one if it - // is the one being edited by the user and therefore the origin of the event - $.each( termsValueTools, function( i, termValueTool ) { - if( - !( origin instanceof wb.ui.PropertyEditTool.EditableValue ) - || origin.getSubject() !== termValueTool.getSubject() - ) { - termValueTool.disable(); - } else if( origin && origin.getSubject() === termValueTool.getSubject() ) { - $( 'table.wb-terms' ).addClass( 'wb-edit' ); - } - } ); - - $termBoxRows.find( ':wikibase-descriptionview' ) + $termBoxRows.find( ':wikibase-labelview, :wikibase-descriptionview' ) .not( origin ) .each( function() { $( this ).data( 'edittoolbar' ).toolbar.disable(); } ); } ) .on( 'stopItemPageEditMode', function( event, origin ) { - $( 'table.wb-terms' ).removeClass( 'wb-edit' ); - $.each( termsValueTools, function( i, termValueTool ) { - termValueTool.enable(); + $termBoxRows.find( ':wikibase-labelview' ).each( function() { + var labelview = $( this ).data( 'labelview' ); + + if( labelview.value().label ) { + var toolbar = $( this ).data( 'edittoolbar' ).toolbar, + btnEdit = toolbar.editGroup.getButton( 'edit' ).data( 'toolbarbutton' ); + + $( this ).data( 'edittoolbar' ).toolbar.enable(); + + // FIXME: Get rid of StatableObject making things complicated + btnEdit.setState( btnEdit.STATE.ENABLED ); + } } ); $termBoxRows.find( ':wikibase-descriptionview' ).each( function() { @@ -212,7 +205,68 @@ return mw.template( 'wb-terms-table', $tbody ); } -// TODO: Merge with native descriptionview toolbar definiton +// TODO: Merge with native labelview/descriptionview toolbar definiton +$.wikibase.toolbarcontroller.definition( 'edittoolbar', { + id: 'terms-labelview', + selector: '.wb-terms-label', + events: { + labelviewcreate: function( event, toolbarcontroller ) { + var $labelview = $( event.target ), + labelview = $labelview.data( 'labelview' ); + + $labelview.edittoolbar( { + $container: $labelview.next(), + interactionWidgetName: $.wikibase.labelview.prototype.widgetName, + enableRemove: false + } ); + + $labelview.on( 'keyup', function( event ) { + if( event.keyCode === $.ui.keyCode.ESCAPE ) { + labelview.stopEditing( true ); + } else if( event.keyCode === $.ui.keyCode.ENTER ) { + labelview.stopEditing( false ); + } + } ); + + if( !labelview.value().label ) { + labelview.startEditing(); + } + }, + 'labelviewchange labelviewafterstartediting': function( event ) { + var $labelview = $( event.target ), + labelview = $labelview.data( 'labelview' ), + toolbar = $labelview.data( 'edittoolbar' ).toolbar, + $btnSave = toolbar.editGroup.getButton( 'save' ), + btnSave = $btnSave.data( 'toolbarbutton' ), + enable = labelview.isValid() && !labelview.isInitialValue(), + $btnCancel = toolbar.editGroup.getButton( 'cancel' ), + btnCancel = $btnCancel.data( 'toolbarbutton' ), + currentLabel = labelview.value().label, + disableCancel = !currentLabel && labelview.isInitialValue(); + + btnSave[enable ? 'enable' : 'disable'](); + btnCancel[disableCancel ? 'disable' : 'enable'](); + }, + labelviewafterstopediting: function( event, dropValue ) { + var $labelview = $( event.target ), + labelview = $labelview.data( 'labelview' ); + + if( !labelview.value().label ) { + labelview.startEditing(); + } + }, + toolbareditgroupedit: function( event, toolbarcontroller ) { + var $labelview = $( event.target ).closest( ':wikibase-edittoolbar' ), + labelview = $labelview.data( 'labelview' ); + + if( !labelview ) { + return; + } + + labelview.focus(); + } + } +} ); $.wikibase.toolbarcontroller.definition( 'edittoolbar', { id: 'terms-descriptionview', selector: '.wb-terms-description', -- To view, visit https://gerrit.wikimedia.org/r/154394 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id36ab9c2dd0a3acb0c19e34c3ce8c8b2e7b954bb Gerrit-PatchSet: 6 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Henning Snater <henning.sna...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits