2013-10-11 18:42:46 +00:00
|
|
|
/*!
|
2015-07-29 13:41:30 +00:00
|
|
|
* VisualEditor MediaWiki Initialization MobileArticleTarget class.
|
2013-10-11 18:42:46 +00:00
|
|
|
*
|
2020-01-08 17:13:04 +00:00
|
|
|
* @copyright 2011-2020 VisualEditor Team and others; see AUTHORS.txt
|
2013-10-11 18:42:46 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
2020-06-02 20:30:00 +00:00
|
|
|
/**
|
|
|
|
* @class VisualEditorOverlay
|
|
|
|
* TODO: Use @-external when we switch to JSDoc
|
|
|
|
*/
|
|
|
|
|
2013-10-11 18:42:46 +00:00
|
|
|
/**
|
2015-08-04 13:37:13 +00:00
|
|
|
* MediaWiki mobile article target.
|
2013-10-11 18:42:46 +00:00
|
|
|
*
|
|
|
|
* @class
|
2015-12-10 16:07:50 +00:00
|
|
|
* @extends ve.init.mw.ArticleTarget
|
2013-10-11 18:42:46 +00:00
|
|
|
*
|
|
|
|
* @constructor
|
2019-03-21 20:47:25 +00:00
|
|
|
* @param {VisualEditorOverlay} overlay Mobile frontend overlay
|
2014-02-06 23:26:52 +00:00
|
|
|
* @param {Object} [config] Configuration options
|
2021-09-11 08:05:31 +00:00
|
|
|
* @cfg {Object} [toolbarConfig]
|
2020-07-07 18:50:49 +00:00
|
|
|
* @cfg {string|null} [section] Number of the section target should scroll to
|
2013-10-11 18:42:46 +00:00
|
|
|
*/
|
2019-03-21 20:47:25 +00:00
|
|
|
ve.init.mw.MobileArticleTarget = function VeInitMwMobileArticleTarget( overlay, config ) {
|
|
|
|
this.overlay = overlay;
|
|
|
|
this.$overlay = overlay.$el;
|
|
|
|
this.$overlaySurface = overlay.$el.find( '.surface' );
|
|
|
|
|
2014-02-06 23:26:52 +00:00
|
|
|
config = config || {};
|
2021-11-15 17:25:51 +00:00
|
|
|
config.toolbarConfig = ve.extendObject( {
|
2015-08-15 17:00:37 +00:00
|
|
|
actions: false
|
|
|
|
}, config.toolbarConfig );
|
2013-10-11 18:42:46 +00:00
|
|
|
|
|
|
|
// Parent constructor
|
2017-09-11 14:59:38 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.super.call( this, config );
|
2013-12-06 20:01:03 +00:00
|
|
|
|
2020-07-07 18:50:49 +00:00
|
|
|
if ( config.section !== undefined ) {
|
|
|
|
this.section = config.section;
|
|
|
|
}
|
2015-07-30 09:32:40 +00:00
|
|
|
|
|
|
|
// Initialization
|
2019-07-22 19:12:35 +00:00
|
|
|
this.$element.addClass( 've-init-mw-mobileArticleTarget ve-init-mobileTarget' );
|
2013-10-11 18:42:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
2015-12-10 16:07:50 +00:00
|
|
|
OO.inheritClass( ve.init.mw.MobileArticleTarget, ve.init.mw.ArticleTarget );
|
2013-10-11 18:42:46 +00:00
|
|
|
|
|
|
|
/* Static Properties */
|
2014-11-24 17:43:16 +00:00
|
|
|
|
2015-07-29 13:41:30 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.static.toolbarGroups = [
|
2015-08-06 14:22:15 +00:00
|
|
|
// History
|
2018-05-18 13:59:15 +00:00
|
|
|
{
|
|
|
|
name: 'history',
|
2019-02-01 18:24:20 +00:00
|
|
|
include: [ 'undo' ]
|
|
|
|
},
|
2014-05-02 20:08:16 +00:00
|
|
|
// Style
|
2015-07-29 16:11:06 +00:00
|
|
|
{
|
2018-05-18 13:59:15 +00:00
|
|
|
name: 'style',
|
2015-07-29 16:11:06 +00:00
|
|
|
classes: [ 've-test-toolbar-style' ],
|
|
|
|
type: 'list',
|
|
|
|
icon: 'textStyle',
|
|
|
|
title: OO.ui.deferMsg( 'visualeditor-toolbar-style-tooltip' ),
|
2020-03-13 21:03:50 +00:00
|
|
|
label: OO.ui.deferMsg( 'visualeditor-toolbar-style-tooltip' ),
|
|
|
|
invisibleLabel: true,
|
2015-07-29 16:11:06 +00:00
|
|
|
include: [ { group: 'textStyle' }, 'language', 'clear' ],
|
|
|
|
forceExpand: [ 'bold', 'italic', 'clear' ],
|
|
|
|
promote: [ 'bold', 'italic' ],
|
|
|
|
demote: [ 'strikethrough', 'code', 'underline', 'language', 'clear' ]
|
|
|
|
},
|
2014-05-02 20:08:16 +00:00
|
|
|
// Link
|
2018-05-18 13:59:15 +00:00
|
|
|
{
|
|
|
|
name: 'link',
|
|
|
|
include: [ 'link' ]
|
|
|
|
},
|
2018-05-24 15:33:00 +00:00
|
|
|
// Placeholder for reference tools (e.g. Cite and/or Citoid)
|
|
|
|
{
|
|
|
|
name: 'reference'
|
2018-05-18 13:59:15 +00:00
|
|
|
}
|
2013-10-11 18:42:46 +00:00
|
|
|
];
|
|
|
|
|
2016-04-21 11:28:00 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.static.trackingName = 'mobile';
|
2013-12-10 01:39:46 +00:00
|
|
|
|
2015-09-03 01:24:48 +00:00
|
|
|
// FIXME Some of these users will be on tablets, check for this
|
|
|
|
ve.init.mw.MobileArticleTarget.static.platformType = 'phone';
|
|
|
|
|
2013-12-06 20:01:03 +00:00
|
|
|
/* Methods */
|
|
|
|
|
2019-03-29 00:31:51 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.deactivateSurfaceForToolbar = function () {
|
|
|
|
// Parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.deactivateSurfaceForToolbar.call( this );
|
|
|
|
|
|
|
|
if ( this.wasSurfaceActive && ve.init.platform.constructor.static.isIos() ) {
|
2022-01-24 23:36:32 +00:00
|
|
|
this.prevScrollPosition = this.$scrollContainer.scrollTop();
|
2019-03-29 00:31:51 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.activateSurfaceForToolbar = function () {
|
|
|
|
// Parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.activateSurfaceForToolbar.call( this );
|
|
|
|
|
|
|
|
if ( this.wasSurfaceActive && ve.init.platform.constructor.static.isIos() ) {
|
|
|
|
// Setting the cursor can cause unwanted scrolling on iOS, so manually
|
|
|
|
// restore the scroll offset from before the toolbar was opened (T218650).
|
2022-01-24 23:36:32 +00:00
|
|
|
this.$scrollContainer.scrollTop( this.prevScrollPosition );
|
2019-03-29 00:31:51 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-05-27 19:12:04 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.clearSurfaces = function () {
|
|
|
|
if ( ve.init.platform.constructor.static.isIos() && this.viewportZoomHandler ) {
|
|
|
|
this.viewportZoomHandler.detach();
|
|
|
|
this.viewportZoomHandler = null;
|
|
|
|
}
|
|
|
|
// Parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.clearSurfaces.call( this );
|
|
|
|
};
|
|
|
|
|
2019-03-21 20:47:25 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.onContainerScroll = function () {
|
2019-12-20 15:28:22 +00:00
|
|
|
var target = this,
|
|
|
|
// Editor may not have loaded yet, in which case `this.surface` is undefined
|
|
|
|
surfaceView = this.surface && this.surface.getView(),
|
|
|
|
isActiveWithKeyboard = surfaceView && surfaceView.isFocused() && !surfaceView.isDeactivated();
|
2019-03-21 22:10:56 +00:00
|
|
|
|
|
|
|
// On iOS Safari, when the keyboard is open, the layout viewport reported by the browser is not
|
|
|
|
// updated to match the real viewport reduced by the keyboard (diagram: T218414#5027607). On all
|
|
|
|
// modern non-iOS browsers the layout viewport is updated to match real viewport.
|
|
|
|
//
|
|
|
|
// This allows the fixed toolbar to be scrolled out of view, ignoring `position: fixed` (because
|
|
|
|
// it refers to the layout viewport).
|
|
|
|
//
|
|
|
|
// When this happens, bring it back in by scrolling down a bit and back up until the top of the
|
|
|
|
// fake viewport is aligned with the top of the real viewport.
|
|
|
|
|
|
|
|
clearTimeout( this.onContainerScrollTimer );
|
|
|
|
if ( !isActiveWithKeyboard ) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-20 15:28:22 +00:00
|
|
|
|
2019-03-21 22:10:56 +00:00
|
|
|
// Wait until after the scroll, because 'scroll' events are not emitted for every frame the
|
|
|
|
// browser paints, so the toolbar would lag behind in a very unseemly manner. Additionally,
|
|
|
|
// getBoundingClientRect returns incorrect values during scrolling, so make sure to calculate
|
|
|
|
// it only after the scrolling ends (https://openradar.appspot.com/radar?id=6668472289329152).
|
2021-10-13 12:57:45 +00:00
|
|
|
var animateToolbarIntoView;
|
2020-08-20 22:36:24 +00:00
|
|
|
this.onContainerScrollTimer = setTimeout( animateToolbarIntoView = function () {
|
|
|
|
if ( target.toolbarAnimating ) {
|
|
|
|
// We can't do this while the 'transform' transition is happening, because
|
|
|
|
// getBoundingClientRect() returns values that reflect that (and are negative).
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-13 12:57:45 +00:00
|
|
|
var $header = target.overlay.$el.find( '.overlay-header-container' );
|
|
|
|
|
2019-03-21 22:10:56 +00:00
|
|
|
// Check if toolbar is offscreen. In a better world, this would reject all negative values
|
|
|
|
// (pos >= 0), but getBoundingClientRect often returns funny small fractional values after
|
|
|
|
// this function has done its job (which triggers another 'scroll' event) and before the
|
|
|
|
// user scrolled again. If we allowed it to run, it would trigger a hilarious loop! Toolbar
|
|
|
|
// being 1px offscreen is not a big deal anyway.
|
2021-10-13 12:57:45 +00:00
|
|
|
var pos = $header[ 0 ].getBoundingClientRect().top;
|
2019-03-21 22:10:56 +00:00
|
|
|
if ( pos >= -1 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't know how much we have to scroll because we don't know how large the real
|
2019-10-30 20:49:00 +00:00
|
|
|
// viewport is. This value is bigger than the screen height of all iOS devices.
|
2021-10-13 12:57:45 +00:00
|
|
|
var viewportHeight = 2000;
|
2019-10-30 20:49:00 +00:00
|
|
|
// OK so this one is really weird. Normally on iOS, the scroll position is set on <body>.
|
|
|
|
// But on our sites, when using iOS 13, it's on <html> instead - maybe due to some funny
|
|
|
|
// CSS we set on html and body? Anyway, this seems to work...
|
2021-10-13 12:57:45 +00:00
|
|
|
var scrollY = document.body.scrollTop || document.documentElement.scrollTop;
|
|
|
|
var scrollX = document.body.scrollLeft || document.documentElement.scrollLeft;
|
2019-03-21 22:10:56 +00:00
|
|
|
|
2020-08-20 22:36:24 +00:00
|
|
|
// Prevent the scrolling we're about to do from triggering this event handler again.
|
|
|
|
target.toolbarAnimating = true;
|
|
|
|
|
2021-10-13 12:57:45 +00:00
|
|
|
var $overlaySurface = target.$overlaySurface;
|
2019-03-21 22:10:56 +00:00
|
|
|
// Scroll down and translate the surface by the same amount, otherwise the content at new
|
|
|
|
// scroll position visibly flashes.
|
|
|
|
$overlaySurface.css( 'transform', 'translateY( ' + viewportHeight + 'px )' );
|
2019-10-30 20:49:00 +00:00
|
|
|
window.scroll( scrollX, scrollY + viewportHeight );
|
2019-03-21 22:10:56 +00:00
|
|
|
|
|
|
|
// Prepate to animate toolbar sliding into view
|
|
|
|
$header.removeClass( 'toolbar-shown toolbar-shown-done' );
|
2021-10-13 12:57:45 +00:00
|
|
|
var headerHeight = $header[ 0 ].offsetHeight;
|
|
|
|
var headerTranslateY = Math.max( -headerHeight, pos );
|
2019-03-21 22:10:56 +00:00
|
|
|
$header.css( 'transform', 'translateY( ' + headerTranslateY + 'px )' );
|
|
|
|
|
|
|
|
// The scroll back up must be after a delay, otherwise no scrolling happens and the
|
2019-10-30 20:49:00 +00:00
|
|
|
// viewports are not aligned.
|
|
|
|
setTimeout( function () {
|
2019-03-21 22:10:56 +00:00
|
|
|
// Scroll back up
|
|
|
|
$overlaySurface.css( 'transform', '' );
|
2019-10-30 20:49:00 +00:00
|
|
|
window.scroll( scrollX, scrollY );
|
2019-03-21 22:10:56 +00:00
|
|
|
|
2019-03-29 01:16:40 +00:00
|
|
|
// Animate toolbar sliding into view
|
|
|
|
$header.addClass( 'toolbar-shown' ).css( 'transform', '' );
|
|
|
|
setTimeout( function () {
|
|
|
|
$header.addClass( 'toolbar-shown-done' );
|
2020-08-20 22:36:24 +00:00
|
|
|
// Wait until the animation is done before allowing this event handler to trigger again
|
|
|
|
target.toolbarAnimating = false;
|
|
|
|
// Re-check after the animation is done, in case the user scrolls in the meantime.
|
|
|
|
animateToolbarIntoView();
|
|
|
|
// The animation takes 250ms but we need to wait longer for some reason…
|
|
|
|
// 'transitionend' event also doesn't seem to work reliably.
|
|
|
|
}, 300 );
|
2019-10-30 20:49:00 +00:00
|
|
|
// If the delays below are made any smaller, the weirdest graphical glitches happen,
|
|
|
|
// so don't mess with them
|
|
|
|
}, 50 );
|
2019-03-21 22:10:56 +00:00
|
|
|
}, 250 );
|
2019-03-21 20:47:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle surface scroll events
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.onSurfaceScroll = function () {
|
2019-09-09 15:01:34 +00:00
|
|
|
if ( ve.init.platform.constructor.static.isIos() && this.getSurface() ) {
|
2019-03-21 20:47:25 +00:00
|
|
|
// iOS has a bug where if you change the scroll offset of a
|
|
|
|
// contentEditable or textarea with a cursor visible, it disappears.
|
|
|
|
// This function works around it by removing and reapplying the selection.
|
2021-10-13 12:57:45 +00:00
|
|
|
var nativeSelection = this.getSurface().getView().nativeSelection;
|
2019-03-21 20:47:25 +00:00
|
|
|
if ( nativeSelection.rangeCount && document.activeElement.contentEditable === 'true' ) {
|
2021-10-13 12:57:45 +00:00
|
|
|
var range = nativeSelection.getRangeAt( 0 );
|
2019-03-21 20:47:25 +00:00
|
|
|
nativeSelection.removeAllRanges();
|
|
|
|
nativeSelection.addRange( range );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.createSurface = function ( dmDoc, config ) {
|
|
|
|
if ( this.overlay.isNewPage ) {
|
|
|
|
config = ve.extendObject( {
|
|
|
|
placeholder: this.overlay.options.placeholder
|
|
|
|
}, config );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parent method
|
2021-10-13 12:57:45 +00:00
|
|
|
var surface = ve.init.mw.MobileArticleTarget
|
2019-03-21 20:47:25 +00:00
|
|
|
.super.prototype.createSurface.call( this, dmDoc, config );
|
|
|
|
|
|
|
|
surface.connect( this, { scroll: 'onSurfaceScroll' } );
|
|
|
|
|
|
|
|
return surface;
|
|
|
|
};
|
|
|
|
|
2021-05-17 21:39:22 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.getSurfaceClasses = function () {
|
|
|
|
var classes = ve.init.mw.MobileArticleTarget.super.prototype.getSurfaceClasses.call( this );
|
|
|
|
return classes.concat( [ 'content' ] );
|
|
|
|
};
|
|
|
|
|
2019-03-21 20:47:25 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.setSurface = function ( surface ) {
|
|
|
|
var changed = surface !== this.surface;
|
|
|
|
|
|
|
|
// Parent method
|
|
|
|
// FIXME This actually skips ve.init.mw.Target.prototype.setSurface. Why?
|
|
|
|
ve.init.mw.Target.super.prototype.setSurface.apply( this, arguments );
|
|
|
|
|
|
|
|
if ( changed ) {
|
|
|
|
this.$overlaySurface.append( surface.$element );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-12-06 20:01:03 +00:00
|
|
|
/**
|
2015-08-04 13:37:13 +00:00
|
|
|
* @inheritdoc
|
2013-12-06 20:01:03 +00:00
|
|
|
*/
|
2015-12-11 14:57:49 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.surfaceReady = function () {
|
2019-03-21 20:47:25 +00:00
|
|
|
if ( this.teardownPromise ) {
|
|
|
|
// Loading was cancelled, the overlay is already closed at this point. Do nothing.
|
|
|
|
// Otherwise e.g. scrolling from #goToHeading would kick in and mess things up.
|
|
|
|
return;
|
|
|
|
}
|
2015-08-19 18:05:01 +00:00
|
|
|
|
2019-09-05 18:25:33 +00:00
|
|
|
// Deactivate the surface so any initial selection set in surfaceReady
|
|
|
|
// listeners doesn't cause the keyboard to be shown.
|
2019-09-09 17:53:22 +00:00
|
|
|
this.getSurface().getView().deactivate( false );
|
2019-09-05 18:25:33 +00:00
|
|
|
|
2015-07-01 11:11:36 +00:00
|
|
|
// Parent method
|
2015-12-11 14:57:49 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.surfaceReady.apply( this, arguments );
|
2015-07-01 11:11:36 +00:00
|
|
|
|
2019-09-05 18:25:33 +00:00
|
|
|
// If no selection has been set yet, set it to the start of the document.
|
2021-11-27 00:38:54 +00:00
|
|
|
if ( this.getSurface().getModel().getSelection().isNull() ) {
|
|
|
|
this.getSurface().getView().selectFirstSelectableContentOffset();
|
2019-09-05 18:25:33 +00:00
|
|
|
}
|
2015-08-06 14:22:15 +00:00
|
|
|
|
2015-04-09 03:48:46 +00:00
|
|
|
this.events.trackActivationComplete();
|
2019-03-21 20:47:25 +00:00
|
|
|
|
2019-05-27 19:12:04 +00:00
|
|
|
if ( ve.init.platform.constructor.static.isIos() ) {
|
|
|
|
if ( this.viewportZoomHandler ) {
|
|
|
|
this.viewportZoomHandler.detach();
|
|
|
|
}
|
|
|
|
this.viewportZoomHandler = new ve.init.mw.ViewportZoomHandler();
|
|
|
|
this.viewportZoomHandler.attach( this.getSurface() );
|
|
|
|
}
|
2019-03-21 20:47:25 +00:00
|
|
|
};
|
|
|
|
|
2021-12-21 18:41:36 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.afterSurfaceReady = function () {
|
|
|
|
this.adjustContentPadding();
|
|
|
|
|
|
|
|
// Parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.afterSurfaceReady.apply( this, arguments );
|
|
|
|
};
|
|
|
|
|
2019-03-21 20:47:25 +00:00
|
|
|
/**
|
|
|
|
* Match the content padding to the toolbar height
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.adjustContentPadding = function () {
|
2019-05-14 19:52:21 +00:00
|
|
|
var surface = this.getSurface(),
|
|
|
|
surfaceView = surface.getView(),
|
2019-07-23 21:50:16 +00:00
|
|
|
toolbarHeight = this.getToolbar().$element[ 0 ].clientHeight;
|
2019-05-14 19:52:21 +00:00
|
|
|
|
|
|
|
surface.setPadding( {
|
2019-07-23 21:50:16 +00:00
|
|
|
top: toolbarHeight
|
2019-05-14 19:52:21 +00:00
|
|
|
} );
|
2019-03-28 19:17:20 +00:00
|
|
|
surfaceView.$attachedRootNode.css( 'padding-top', toolbarHeight );
|
2019-04-01 22:45:11 +00:00
|
|
|
surface.$placeholder.css( 'padding-top', toolbarHeight );
|
2019-03-28 14:40:44 +00:00
|
|
|
surfaceView.emit( 'position' );
|
2019-04-08 11:17:28 +00:00
|
|
|
surface.scrollSelectionIntoView();
|
2013-12-06 20:01:03 +00:00
|
|
|
};
|
2014-02-06 23:33:21 +00:00
|
|
|
|
2015-07-01 11:11:36 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2018-03-19 14:49:23 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.getSaveButtonLabel = function ( startProcess ) {
|
|
|
|
var suffix = startProcess ? '-start' : '';
|
|
|
|
// The following messages can be used here:
|
|
|
|
// * visualeditor-savedialog-label-publish-short
|
|
|
|
// * visualeditor-savedialog-label-publish-short-start
|
|
|
|
// * visualeditor-savedialog-label-save-short
|
|
|
|
// * visualeditor-savedialog-label-save-short-start
|
2016-08-29 17:46:18 +00:00
|
|
|
if ( mw.config.get( 'wgEditSubmitButtonLabelPublish' ) ) {
|
2018-03-19 14:49:23 +00:00
|
|
|
return OO.ui.deferMsg( 'visualeditor-savedialog-label-publish-short' + suffix );
|
2016-06-30 14:04:51 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 14:49:23 +00:00
|
|
|
return OO.ui.deferMsg( 'visualeditor-savedialog-label-save-short' + suffix );
|
2015-07-01 11:11:36 +00:00
|
|
|
};
|
|
|
|
|
2019-04-03 15:43:09 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2020-03-07 17:02:30 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.switchToFallbackWikitextEditor = function ( modified ) {
|
2019-04-03 15:43:09 +00:00
|
|
|
var dataPromise;
|
|
|
|
if ( modified ) {
|
|
|
|
dataPromise = this.getWikitextDataPromiseForDoc( modified ).then( function ( response ) {
|
|
|
|
var content = ve.getProp( response, 'visualeditoredit', 'content' );
|
|
|
|
return { text: content };
|
2019-03-23 03:36:10 +00:00
|
|
|
} );
|
|
|
|
}
|
2019-04-03 15:43:09 +00:00
|
|
|
this.overlay.switchToSourceEditor( dataPromise );
|
2022-04-26 15:31:12 +00:00
|
|
|
return dataPromise;
|
2019-03-23 03:36:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.save = function () {
|
|
|
|
// Parent method
|
2021-04-22 13:35:53 +00:00
|
|
|
var promise = ve.init.mw.MobileArticleTarget.super.prototype.save.apply( this, arguments );
|
2019-03-23 03:36:10 +00:00
|
|
|
|
|
|
|
this.overlay.log( {
|
|
|
|
action: 'saveAttempt'
|
|
|
|
} );
|
2021-04-22 13:35:53 +00:00
|
|
|
|
|
|
|
return promise;
|
2019-03-23 03:36:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.showSaveDialog = function () {
|
|
|
|
// Parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.showSaveDialog.apply( this, arguments );
|
|
|
|
|
|
|
|
this.overlay.log( {
|
|
|
|
action: 'saveIntent'
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2022-02-17 22:06:14 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2022-02-17 22:07:39 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.replacePageContent = function (
|
2022-06-07 17:47:28 +00:00
|
|
|
html, categoriesHtml, displayTitle, lastModified, contentSub
|
2022-02-17 22:07:39 +00:00
|
|
|
) {
|
|
|
|
var $content = $( $.parseHTML( html ) );
|
|
|
|
|
|
|
|
if ( lastModified ) {
|
|
|
|
// TODO: Update the last-modified-bar with the correct info
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
$( '.last-modified-bar' ).remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
var $editableContent = $( '#mw-content-text' );
|
|
|
|
$editableContent.find( '.mw-parser-output' ).replaceWith( $content );
|
|
|
|
mw.hook( 'wikipage.content' ).fire( $editableContent );
|
|
|
|
if ( displayTitle ) {
|
|
|
|
// eslint-disable-next-line no-jquery/no-html, no-jquery/no-global-selector
|
|
|
|
$( '#firstHeading' ).html( displayTitle );
|
|
|
|
}
|
|
|
|
|
2022-05-17 23:40:08 +00:00
|
|
|
// Categories are only shown in AMC
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
if ( $( '#catlinks' ).length ) {
|
|
|
|
var $categories = $( $.parseHTML( categoriesHtml ) );
|
|
|
|
mw.hook( 'wikipage.categories' ).fire( $categories );
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
$( '#catlinks' ).replaceWith( $categories );
|
|
|
|
}
|
|
|
|
|
2022-06-07 17:47:28 +00:00
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector, no-jquery/no-html
|
|
|
|
$( '.minerva__subtitle' ).html( contentSub );
|
|
|
|
|
2022-02-17 22:07:39 +00:00
|
|
|
this.setRealRedirectInterface();
|
|
|
|
};
|
2022-02-17 22:06:14 +00:00
|
|
|
|
2019-03-23 03:36:10 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2019-11-04 14:54:53 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.saveComplete = function ( data ) {
|
2022-02-17 22:07:39 +00:00
|
|
|
// Set 'saved' flag before teardown (which is called in parent method) to avoid prompts
|
|
|
|
// This is set in this.overlay.onSaveComplete, but we can't call that until we have
|
|
|
|
// computed the fragment.
|
2022-02-24 20:39:41 +00:00
|
|
|
this.overlay.saved = true;
|
|
|
|
|
2019-03-23 03:36:10 +00:00
|
|
|
// Parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.saveComplete.apply( this, arguments );
|
|
|
|
|
2022-02-17 22:07:39 +00:00
|
|
|
var fragment = this.getSectionFragmentFromPage();
|
|
|
|
|
2019-03-23 03:36:10 +00:00
|
|
|
this.overlay.sectionId = fragment;
|
2019-11-04 14:54:53 +00:00
|
|
|
this.overlay.onSaveComplete( data.newrevid );
|
2019-03-23 03:36:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2019-11-04 14:54:53 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.saveFail = function ( doc, saveData, wasRetry, code, data ) {
|
2019-03-23 03:36:10 +00:00
|
|
|
// parent method
|
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.saveFail.apply( this, arguments );
|
|
|
|
|
2019-10-21 18:25:56 +00:00
|
|
|
this.overlay.onSaveFailure( data );
|
2019-03-23 03:36:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.tryTeardown = function () {
|
2020-09-21 14:21:24 +00:00
|
|
|
this.overlay.onExitClick( $.Event() );
|
2019-03-23 03:36:10 +00:00
|
|
|
};
|
|
|
|
|
2022-05-13 21:36:50 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.teardown = function () {
|
|
|
|
var target = this;
|
|
|
|
// Parent method
|
|
|
|
return ve.init.mw.MobileArticleTarget.super.prototype.teardown.call( this ).then( function () {
|
|
|
|
if ( !target.isViewPage ) {
|
|
|
|
location.href = target.viewUri.clone().extend( {
|
|
|
|
redirect: mw.config.get( 'wgIsRedirect' ) ? 'no' : undefined
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2014-02-06 23:33:21 +00:00
|
|
|
/**
|
2014-02-07 22:04:35 +00:00
|
|
|
* @inheritdoc
|
2014-02-06 23:33:21 +00:00
|
|
|
*/
|
2015-07-29 13:41:30 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.setupToolbar = function ( surface ) {
|
2019-10-09 13:55:40 +00:00
|
|
|
var originalToolbarGroups = this.toolbarGroups;
|
2019-08-02 07:21:14 +00:00
|
|
|
|
|
|
|
// We don't want any of these tools to show up in subordinate widgets, so we
|
|
|
|
// temporarily add them here. We need to do it _here_ rather than in their
|
|
|
|
// own static variable to make sure that other tools which meddle with
|
|
|
|
// toolbarGroups (Cite, mostly) have a chance to do so.
|
2019-10-09 13:55:40 +00:00
|
|
|
this.toolbarGroups = [].concat(
|
2019-08-02 07:21:14 +00:00
|
|
|
[
|
|
|
|
// Back
|
|
|
|
{
|
|
|
|
name: 'back',
|
|
|
|
include: [ 'back' ]
|
|
|
|
}
|
|
|
|
],
|
2019-10-09 13:55:40 +00:00
|
|
|
this.toolbarGroups,
|
2019-08-02 07:21:14 +00:00
|
|
|
[
|
|
|
|
{
|
|
|
|
name: 'editMode',
|
|
|
|
type: 'list',
|
|
|
|
icon: 'edit',
|
|
|
|
title: OO.ui.deferMsg( 'visualeditor-mweditmode-tooltip' ),
|
2020-03-13 21:03:50 +00:00
|
|
|
label: OO.ui.deferMsg( 'visualeditor-mweditmode-tooltip' ),
|
|
|
|
invisibleLabel: true,
|
2019-08-02 07:21:14 +00:00
|
|
|
include: [ 'editModeVisual', 'editModeSource' ]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'save',
|
|
|
|
type: 'bar',
|
|
|
|
include: [ 'showMobileSave' ]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
);
|
2019-04-15 22:39:56 +00:00
|
|
|
|
2014-02-07 22:04:35 +00:00
|
|
|
// Parent method
|
2015-07-01 11:11:36 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.super.prototype.setupToolbar.call( this, surface );
|
2014-02-07 22:04:35 +00:00
|
|
|
|
2019-10-09 13:55:40 +00:00
|
|
|
this.toolbarGroups = originalToolbarGroups;
|
2019-04-15 22:39:56 +00:00
|
|
|
|
|
|
|
this.toolbar.$group.addClass( 've-init-mw-mobileArticleTarget-editTools' );
|
2015-07-30 11:08:56 +00:00
|
|
|
this.toolbar.$element.addClass( 've-init-mw-mobileArticleTarget-toolbar' );
|
2022-05-21 02:33:05 +00:00
|
|
|
this.toolbar.$popups.addClass( 've-init-mw-mobileArticleTarget-toolbar-popups' );
|
2015-02-19 18:22:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2015-07-29 13:41:30 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.attachToolbar = function () {
|
2015-02-19 18:22:20 +00:00
|
|
|
// Move the toolbar to the overlay header
|
2019-03-21 20:47:25 +00:00
|
|
|
this.overlay.$el.find( '.overlay-header > .toolbar' ).append( this.toolbar.$element );
|
2015-08-10 12:31:46 +00:00
|
|
|
this.toolbar.initialize();
|
2014-02-06 23:33:21 +00:00
|
|
|
};
|
2014-07-23 22:30:38 +00:00
|
|
|
|
2015-07-30 11:08:56 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2019-04-15 22:39:56 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.setupToolbarSaveButton = function () {
|
2019-08-02 07:21:14 +00:00
|
|
|
this.toolbarSaveButton = this.toolbar.getToolGroupByName( 'save' ).items[ 0 ];
|
2015-07-30 11:08:56 +00:00
|
|
|
};
|
|
|
|
|
2014-07-23 22:30:38 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2015-07-29 13:41:30 +00:00
|
|
|
ve.init.mw.MobileArticleTarget.prototype.goToHeading = function ( headingNode ) {
|
2014-08-22 00:37:12 +00:00
|
|
|
this.scrollToHeading( headingNode );
|
|
|
|
};
|
2014-07-28 21:54:12 +00:00
|
|
|
|
2015-08-06 14:22:15 +00:00
|
|
|
/**
|
|
|
|
* Done with the editing toolbar
|
|
|
|
*/
|
|
|
|
ve.init.mw.MobileArticleTarget.prototype.done = function () {
|
2019-04-10 21:51:08 +00:00
|
|
|
this.getSurface().getModel().setNullSelection();
|
2015-08-06 14:22:15 +00:00
|
|
|
this.getSurface().getView().blur();
|
|
|
|
};
|
|
|
|
|
2016-04-21 11:28:00 +00:00
|
|
|
/* Registration */
|
|
|
|
|
|
|
|
ve.init.mw.targetFactory.register( ve.init.mw.MobileArticleTarget );
|
|
|
|
|
2015-08-06 14:22:15 +00:00
|
|
|
/**
|
2019-08-02 07:21:14 +00:00
|
|
|
* Mobile save tool
|
2015-08-06 14:22:15 +00:00
|
|
|
*/
|
2019-08-02 07:21:14 +00:00
|
|
|
ve.ui.MWMobileSaveTool = function VeUiMWMobileSaveTool() {
|
|
|
|
// Parent Constructor
|
|
|
|
ve.ui.MWMobileSaveTool.super.apply( this, arguments );
|
2015-08-06 14:22:15 +00:00
|
|
|
};
|
2019-08-02 07:21:14 +00:00
|
|
|
OO.inheritClass( ve.ui.MWMobileSaveTool, ve.ui.MWSaveTool );
|
|
|
|
ve.ui.MWMobileSaveTool.static.name = 'showMobileSave';
|
|
|
|
ve.ui.MWMobileSaveTool.static.icon = 'next';
|
|
|
|
ve.ui.MWMobileSaveTool.static.displayBothIconAndLabel = false;
|
|
|
|
|
|
|
|
ve.ui.toolFactory.register( ve.ui.MWMobileSaveTool );
|