diff --git a/extension.json b/extension.json index e1a34e09fe..613eaaafab 100644 --- a/extension.json +++ b/extension.json @@ -1149,7 +1149,8 @@ "modules/ve-mw/ui/styles/widgets/ve.ui.MWMediaInfoFieldWidget.css" ], "dependencies": [ - "ext.visualEditor.mwimage.core" + "ext.visualEditor.mwimage.core", + "mediawiki.ForeignStructuredUpload.BookletLayout" ], "messages": [ "visualeditor-dialog-media-alttext-section", @@ -1185,6 +1186,9 @@ "visualeditor-dialog-media-position-right", "visualeditor-dialog-media-position-section", "visualeditor-dialog-media-position-section-help", + "visualeditor-dialog-media-save", + "visualeditor-dialog-media-search-tab-search", + "visualeditor-dialog-media-search-tab-upload", "visualeditor-dialog-media-searchselect", "visualeditor-dialog-media-size-originalsize-error", "visualeditor-dialog-media-size-section", @@ -1198,12 +1202,12 @@ "visualeditor-dialog-media-type-section", "visualeditor-dialog-media-type-section-help", "visualeditor-dialog-media-type-thumb", + "visualeditor-dialog-media-upload", "visualeditor-dialogbutton-media-tooltip", "visualeditor-media-input-placeholder" ], "targets": [ - "desktop", - "mobile" + "desktop" ] }, "ext.visualEditor.mwlink": { diff --git a/modules/ve-mw/i18n/en.json b/modules/ve-mw/i18n/en.json index ca6df88fb6..a252fb32c1 100644 --- a/modules/ve-mw/i18n/en.json +++ b/modules/ve-mw/i18n/en.json @@ -105,6 +105,9 @@ "visualeditor-dialog-media-position-right": "Right", "visualeditor-dialog-media-position-section": "Position", "visualeditor-dialog-media-position-section-help": "You can set where this media item appears on the page. This is sometimes used to break up a long line of images on one side of the page.", + "visualeditor-dialog-media-save": "Save", + "visualeditor-dialog-media-search-tab-search": "Search", + "visualeditor-dialog-media-search-tab-upload": "Upload", "visualeditor-dialog-media-searchselect": "Select", "visualeditor-dialog-media-size-choosecustom": "Set custom size", "visualeditor-dialog-media-size-choosedefault": "Set to default size", @@ -121,6 +124,7 @@ "visualeditor-dialog-media-type-section": "Image type", "visualeditor-dialog-media-type-section-help": "You can set how the media item appears on the page. This should be the thumbnail format to be consistent with other pages in almost all cases.", "visualeditor-dialog-media-type-thumb": "Thumbnail", + "visualeditor-dialog-media-upload": "Upload", "visualeditor-dialog-meta-advancedsettings-label": "Advanced settings", "visualeditor-dialog-meta-advancedsettings-section": "Advanced settings", "visualeditor-dialog-meta-categories-category": "Category", diff --git a/modules/ve-mw/i18n/qqq.json b/modules/ve-mw/i18n/qqq.json index 6897986a68..aacc8a16a1 100644 --- a/modules/ve-mw/i18n/qqq.json +++ b/modules/ve-mw/i18n/qqq.json @@ -114,6 +114,9 @@ "visualeditor-dialog-media-position-right": "Label for the image position option for aligning to the right.\n{{Related|Visualeditor-dialog-media-position}}\n{{Identical|Right}}", "visualeditor-dialog-media-position-section": "Label for the image position sub-section.\n\nSee also:\n* {{msg-mw|Visualeditor-dialog-media-position-center}}\n* {{msg-mw|Visualeditor-dialog-media-position-left}}\n* {{msg-mw|Visualeditor-dialog-media-position-none}}\n* {{msg-mw|Visualeditor-dialog-media-position-right}}\n{{Identical|Position}}", "visualeditor-dialog-media-position-section-help": "Message displayed as contextual help about the control for which display position to use (left, right, etc.) to editors in the media editing dialog.", + "visualeditor-dialog-media-save": "Label for the save button", + "visualeditor-dialog-media-search-tab-search": "Label for search tab on insert new media page", + "visualeditor-dialog-media-search-tab-upload": "Label for upload tab on insert new media page", "visualeditor-dialog-media-searchselect": "Button for choosing media item from the search results in the media dialog.\n{{Identical|Select}}", "visualeditor-dialog-media-size-choosecustom": "Label for setting image size to custom dimensions.\n{{Related|Visualeditor-dialog-media-size}}", "visualeditor-dialog-media-size-choosedefault": "Label for setting image size to wiki default thumbnail dimensions.\n{{Related|Visualeditor-dialog-media-size}}", @@ -130,6 +133,7 @@ "visualeditor-dialog-media-type-section": "Label for the image type sub-section.\n\nFollowed by the following buttons:\n* {{msg-mw|Visualeditor-dialog-media-type-thumb}}\n* {{msg-mw|Visualeditor-dialog-media-type-frame}}\n* {{msg-mw|Visualeditor-dialog-media-type-frameless}}\n* {{msg-mw|Visualeditor-dialog-media-type-border}}", "visualeditor-dialog-media-type-section-help": "Message displayed as contextual help about the controls for display type (thumb, frameless, etc.) to editors in the media editing dialog.", "visualeditor-dialog-media-type-thumb": "Label for the image type option for thumbnail.\n{{Identical|Thumbnail}}", + "visualeditor-dialog-media-upload": "Label for the upload button", "visualeditor-dialog-meta-advancedsettings-label": "Title for the advanced settings dialog section.\n{{Identical|Advanced settings}}", "visualeditor-dialog-meta-advancedsettings-section": "Label for the advanced settings dialog section.\n{{Identical|Advanced settings}}", "visualeditor-dialog-meta-categories-category": "Title of popup for editing category options.\n{{Identical|Category}}", diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js index 2b40057eed..af0e4749b4 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js @@ -70,6 +70,18 @@ ve.ui.MWMediaDialog.static.actions = [ flags: [ 'primary', 'progressive' ], modes: [ 'info' ] }, + { + action: 'upload', + label: OO.ui.deferMsg( 'visualeditor-dialog-media-upload' ), + flags: [ 'primary', 'progressive' ], + modes: [ 'upload-upload' ] + }, + { + action: 'save', + label: OO.ui.deferMsg( 'visualeditor-dialog-media-save' ), + flags: [ 'primary', 'progressive' ], + modes: [ 'upload-info' ] + }, { action: 'cancelchoose', label: OO.ui.deferMsg( 'visualeditor-dialog-media-goback' ), @@ -79,7 +91,7 @@ ve.ui.MWMediaDialog.static.actions = [ { label: OO.ui.deferMsg( 'visualeditor-dialog-action-cancel' ), flags: [ 'safe', 'back' ], - modes: [ 'edit', 'insert', 'select' ] + modes: [ 'edit', 'insert', 'select', 'search', 'upload-upload', 'upload-info' ] }, { action: 'back', @@ -175,6 +187,8 @@ ve.ui.MWMediaDialog.prototype.initialize = function () { scrollable: true } ); + this.mediaUploadBooklet = new mw.ForeignStructuredUpload.BookletLayout( { $overlay: this.$overlay } ); + this.mediaImageInfoPanel = new OO.ui.PanelLayout( { classes: [ 've-ui-mwMediaDialog-panel-imageinfo' ], scrollable: false @@ -195,6 +209,18 @@ ve.ui.MWMediaDialog.prototype.initialize = function () { .setLabel( ve.msg( 'visualeditor-dialog-media-page-advanced' ) ); // Define the media search page + this.searchTabs = new OO.ui.IndexLayout(); + + this.searchTabs.addCards( [ + new OO.ui.CardLayout( 'search', { + label: ve.msg( 'visualeditor-dialog-media-search-tab-search' ) + } ), + new OO.ui.CardLayout( 'upload', { + label: ve.msg( 'visualeditor-dialog-media-search-tab-upload' ), + content: [ this.mediaUploadBooklet ] + } ) + ] ); + this.search = new ve.ui.MWMediaSearchWidget(); // Define fieldsets for image settings @@ -323,9 +349,18 @@ ve.ui.MWMediaDialog.prototype.initialize = function () { this.typeSelect.connect( this, { choose: 'onTypeSelectChoose' } ); this.search.getResults().connect( this, { choose: 'onSearchResultsChoose' } ); this.altTextInput.connect( this, { change: 'onAlternateTextChange' } ); + this.searchTabs.connect( this, { + set: 'onSearchTabsSet' + } ); + this.mediaUploadBooklet.connect( this, { + set: 'onMediaUploadBooketSet', + uploadValid: 'onUploadValid', + infoValid: 'onInfoValid' + } ); // Initialization - this.mediaSearchPanel.$element.append( this.search.$element ); + this.searchTabs.getCard( 'search' ).$element.append( this.search.$element ); + this.mediaSearchPanel.$element.append( this.searchTabs.$element ); this.generalSettingsPage.$element.append( this.filenameFieldset.$element, this.captionFieldset.$element, @@ -347,6 +382,70 @@ ve.ui.MWMediaDialog.prototype.initialize = function () { this.$body.append( this.panels.$element ); }; +/** + * Handle set events from the search tabs + * + * @param {OO.ui.CardLayout} card Current card + */ +ve.ui.MWMediaDialog.prototype.onSearchTabsSet = function ( card ) { + var name = card.getName(); + + this.actions.setMode( name ); + + switch ( name ) { + case 'search': + this.setSize( 'larger' ); + break; + + case 'upload': + this.setSize( 'medium' ); + this.mediaUploadBooklet.initialize(); + this.uploadPageNameSet( 'upload' ); + break; + } +}; + +/** + * Handle panelNameSet events from the upload stack + * + * @param {OO.ui.PageLayout} page Current page + */ +ve.ui.MWMediaDialog.prototype.onMediaUploadBooketSet = function ( page ) { + this.uploadPageNameSet( page.getName() ); +}; + +/** + * The upload booklet's page name has changed + * + * @param {string} pageName Page name + */ +ve.ui.MWMediaDialog.prototype.uploadPageNameSet = function ( pageName ) { + if ( pageName === 'insert' ) { + this.chooseImageInfo( this.mediaUploadBooklet.upload.getImageInfo() ); + } else { + this.actions.setMode( 'upload-' + pageName ); + this.actions.setAbilities( { upload: false, save: false } ); + } +}; + +/** + * Handle uploadValid events + * + * @param {boolean} isValid The panel is complete and valid + */ +ve.ui.MWMediaDialog.prototype.onUploadValid = function ( isValid ) { + this.actions.setAbilities( { upload: isValid } ); +}; + +/** + * Handle infoValid events + * + * @param {boolean} isValid The panel is complete and valid + */ +ve.ui.MWMediaDialog.prototype.onInfoValid = function ( isValid ) { + this.actions.setAbilities( { save: isValid } ); +}; + /** * Build the image info panel from the information in the API. * Use the metadata info if it exists. @@ -358,8 +457,9 @@ ve.ui.MWMediaDialog.prototype.initialize = function () { ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) { var i, newDimensions, field, isPortrait, $info, $section, windowWidth, contentDirection = this.getFragment().getDocument().getDir(), + imageTitleText = imageinfo.title || imageinfo.canonicaltitle, imageTitle = new OO.ui.LabelWidget( { - label: mw.Title.newFromText( imageinfo.title ).getNameText() + label: mw.Title.newFromText( imageTitleText ).getNameText() } ), metadata = imageinfo.extmetadata, // Field configuration (in order) @@ -568,7 +668,7 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) { } ); // Call for a bigger image - this.fetchThumbnail( imageinfo.title, newDimensions ) + this.fetchThumbnail( imageTitleText, newDimensions ) .done( function ( thumburl ) { if ( thumburl ) { $image.prop( 'src', thumburl ); @@ -709,7 +809,15 @@ ve.ui.MWMediaDialog.prototype.getLicenseIcon = function ( license ) { * @param {ve.ui.MWMediaResultWidget} item Chosen item */ ve.ui.MWMediaDialog.prototype.onSearchResultsChoose = function ( item ) { - var info = item.getData(); + this.chooseImageInfo( item.getData ); +}; + +/** + * Choose image info for editing + * + * @param {Object} info Image info + */ +ve.ui.MWMediaDialog.prototype.chooseImageInfo = function ( info ) { this.$infoPanelWrapper.empty(); // Switch panels this.selectedImageInfo = info; @@ -724,13 +832,14 @@ ve.ui.MWMediaDialog.prototype.onSearchResultsChoose = function ( item ) { * @param {ve.ui.MWMediaResultWidget|null} item Selected item */ ve.ui.MWMediaDialog.prototype.confirmSelectedImage = function () { - var title, + var title, imageTitleText, obj = {}, info = this.selectedImageInfo; if ( info ) { + imageTitleText = info.title || info.canonicaltitle; // Run title through mw.Title so the File: prefix is localised - title = mw.Title.newFromText( info.title ).getPrefixedText(); + title = mw.Title.newFromText( imageTitleText ).getPrefixedText(); if ( !this.imageModel ) { // Create a new image model based on default attributes this.imageModel = ve.dm.MWImageModel.static.newFromImageAttributes( @@ -768,7 +877,7 @@ ve.ui.MWMediaDialog.prototype.confirmSelectedImage = function () { } // Cache - obj[ info.title ] = info; + obj[ imageTitleText ] = info; ve.init.platform.imageInfoCache.set( obj ); this.checkChanged(); @@ -1007,6 +1116,7 @@ ve.ui.MWMediaDialog.prototype.switchPanels = function ( panel, stopSearchRequery } // Set the edit panel this.panels.setItem( this.mediaSearchPanel ); + this.searchTabs.setCard( 'search' ); this.actions.setMode( this.imageModel ? 'change' : 'select' ); // Layout pending items this.search.runLayoutQueue(); @@ -1225,6 +1335,10 @@ ve.ui.MWMediaDialog.prototype.getActionProcess = function ( action ) { this.switchPanels( 'search', true ); }; break; + case 'upload': + return new OO.ui.Process( this.mediaUploadBooklet.uploadFile() ); + case 'save': + return new OO.ui.Process( this.mediaUploadBooklet.saveFile() ); case 'apply': case 'insert': handler = function () {