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 () {