diff --git a/extension.json b/extension.json index 59a0e507..99c52bc1 100644 --- a/extension.json +++ b/extension.json @@ -323,20 +323,23 @@ "wikieditor-realtimepreview-error", "wikieditor-realtimepreview-reload", "wikieditor-realtimepreview-reload-title", - "accesskey-wikieditor-realtimepreview" + "accesskey-wikieditor-realtimepreview", + "wikieditor-realtimepreview-manual" ], "packageFiles": [ "realtimepreview/init.js", "realtimepreview/RealtimePreview.js", "realtimepreview/ResizingDragBar.js", "realtimepreview/TwoPaneLayout.js", - "realtimepreview/ErrorLayout.js" + "realtimepreview/ErrorLayout.js", + "realtimepreview/ManualWidget.js" ], "styles": [ "realtimepreview/RealtimePreview.less", "realtimepreview/ResizingDragBar.less", "realtimepreview/TwoPaneLayout.less", - "realtimepreview/ErrorLayout.less" + "realtimepreview/ErrorLayout.less", + "realtimepreview/ManualWidget.less" ] } }, diff --git a/i18n/en.json b/i18n/en.json index 9d7cfb2e..c2ba39b3 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -204,5 +204,6 @@ "wikieditor-realtimepreview-beta-label": "Realtime Preview", "wikieditor-realtimepreview-beta-desc": "See how wikitext changes will appear to readers inside the [[mw:Special:MyLanguage/Extension:WikiEditor|2010 editor]].", "wikieditor-realtimepreview-reload-title": "Reload the realtime preview pane", - "accesskey-wikieditor-realtimepreview": ")" + "accesskey-wikieditor-realtimepreview": ")", + "wikieditor-realtimepreview-manual": "Please reload now to manually preview your edits." } diff --git a/i18n/qqq.json b/i18n/qqq.json index 9b964f9d..a423c6e1 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -231,9 +231,10 @@ "tag-wikieditor-description": "Long description of the wikieditor tag ({{msg-mw|Tag-wikieditor}}).\n\nShown on [[Special:Tags]].\n\nSee also:\n* {{msg-mw|Tag-wikieditor}}", "wikieditor-realtimepreview-preview": "Label for the toolbar button to enable/disable realtime preview.", "wikieditor-realtimepreview-error": "Header text for realtime preview errors.", - "wikieditor-realtimepreview-reload": "Button text for the 'reload' button on realtime preview errors.", + "wikieditor-realtimepreview-reload": "Button text for the realtime preview 'reload' buttons (the hover button, the manual-reload button, and the button shown in error messages).", "wikieditor-realtimepreview-beta-label": "Used in [[Special:Preferences]].\n\nUsed as label for checkbox to enable Realtime Preview as a Beta Feature.\n\nThe description for this checkbox is: {{msg-mw|wikieditor-realtimepreview-beta-desc}}.", "wikieditor-realtimepreview-beta-desc": "Used in [[Special:Preferences]].\n\nUsed as description for the checkbox to enable Realtime Preview as a Beta Feature.\n\nThe label for this checkbox is {{msg-mw|wikieditor-realtimepreview-beta-label}}.", "wikieditor-realtimepreview-reload-title": "Tooltip text for the manual reload button.", - "accesskey-wikieditor-realtimepreview": "{{doc-accesskey}}\nAccesskey for the manual reload button." + "accesskey-wikieditor-realtimepreview": "{{doc-accesskey}}\nAccesskey for the manual reload button.", + "wikieditor-realtimepreview-manual": "Message displayed when realtime preview is in 'manual' mode." } diff --git a/modules/realtimepreview/ManualWidget.js b/modules/realtimepreview/ManualWidget.js new file mode 100644 index 00000000..2d3b5481 --- /dev/null +++ b/modules/realtimepreview/ManualWidget.js @@ -0,0 +1,43 @@ +/* global RealtimePreview */ +/** + * @class + * @constructor + * @param {RealtimePreview} realtimePreview + * @param {OO.ui.ButtonWidget} reloadHoverButton + */ +function ManualWidget( realtimePreview, reloadHoverButton ) { + var config = { + classes: [ 'ext-WikiEditor-ManualWidget' ], + framed: true + }; + ManualWidget.super.call( this, config ); + + this.reloadHoverButton = reloadHoverButton; + + // UI elements. + var reloadIcon = new OO.ui.IconWidget( { icon: 'reload' } ); + var $reloadLabel = $( '' ) + .text( mw.msg( 'wikieditor-realtimepreview-manual' ) ); + this.reloadButton = new OO.ui.ButtonWidget( { + label: mw.msg( 'wikieditor-realtimepreview-reload' ), + framed: false, + flags: [ 'progressive' ] + } ); + this.reloadButton.connect( realtimePreview, { + click: realtimePreview.doRealtimePreview.bind( realtimePreview ) + } ); + this.$element.append( reloadIcon.$element, $reloadLabel, this.reloadButton.$element ); +} + +OO.inheritClass( ManualWidget, OO.ui.Widget ); + +ManualWidget.prototype.toggle = function ( show ) { + ManualWidget.parent.prototype.toggle.call( this, show ); + if ( show ) { + this.reloadHoverButton.$element.remove(); + // Use the same access key as the hover reload button, because this won't ever be displayed at the same time as that. + this.reloadButton.setAccessKey( mw.msg( 'accesskey-wikieditor-realtimepreview' ) ); + } +}; + +module.exports = ManualWidget; diff --git a/modules/realtimepreview/ManualWidget.less b/modules/realtimepreview/ManualWidget.less new file mode 100644 index 00000000..45b9a5b1 --- /dev/null +++ b/modules/realtimepreview/ManualWidget.less @@ -0,0 +1,21 @@ +@import 'mediawiki.ui/variables'; + +.ext-WikiEditor-ManualWidget { + background-color: @colorGray14; + display: flex; + align-items: center; + justify-content: space-between; + border-color: @colorGray12; + border-width: 1px 0; + border-style: solid; + padding: 6px 24px; + + & > .oo-ui-iconWidget { + margin-right: 1em; + } + + .oo-ui-buttonWidget { + margin-left: auto; + font-weight: bolder; + } +} diff --git a/modules/realtimepreview/RealtimePreview.js b/modules/realtimepreview/RealtimePreview.js index c0f972dc..4bf16cca 100644 --- a/modules/realtimepreview/RealtimePreview.js +++ b/modules/realtimepreview/RealtimePreview.js @@ -1,6 +1,7 @@ var ResizingDragBar = require( './ResizingDragBar.js' ); var TwoPaneLayout = require( './TwoPaneLayout.js' ); var ErrorLayout = require( './ErrorLayout.js' ); +var ManualWidget = require( './ManualWidget.js' ); /** * @class @@ -21,13 +22,19 @@ function RealtimePreview() { .append( $previewContent ); // Loading bar. - this.$loadingBar = $( '
' ).addClass( 'ext-WikiEditor-realtimepreview-loadingbar' ); + this.$loadingBar = $( '
' ).addClass( 'ext-WikiEditor-realtimepreview-loadingbar' ).append( '
' ); this.$loadingBar.hide(); // Error layout. this.errorLayout = new ErrorLayout(); this.errorLayout.getReloadButton().connect( this, { - click: this.doRealtimePreview.bind( this ) + click: function () { + // Re-show the manual message after the error message is closed. + if ( this.inManualMode ) { + this.manualWidget.toggle( true ); + } + this.doRealtimePreview(); + }.bind( this ) } ); // Manual reload button (visible on hover). @@ -47,7 +54,11 @@ function RealtimePreview() { }.bind( this ) } ); - this.twoPaneLayout.getPane2().append( reloadButton.$element, this.$loadingBar, this.$previewNode, this.errorLayout.$element ); + // Manual mode widget. + this.manualWidget = new ManualWidget( this, reloadButton ); + this.inManualMode = false; + + this.twoPaneLayout.getPane2().append( this.manualWidget.$element, reloadButton.$element, this.$loadingBar, this.$previewNode, this.errorLayout.$element ); this.eventNames = 'change.realtimepreview input.realtimepreview cut.realtimepreview paste.realtimepreview'; // Used to ensure we wait for a response before making new requests. this.isPreviewing = false; @@ -146,6 +157,9 @@ RealtimePreview.prototype.toggle = function () { .off( this.eventNames ) .on( this.eventNames, this.getEventHandler() ); + // Hide or show the manual-reload message bar. + this.manualWidget.toggle( this.inManualMode ); + // Let other things happen after enabling. mw.hook( 'ext.WikiEditor.realtimepreview.enable' ).fire( this ); } @@ -162,7 +176,12 @@ RealtimePreview.prototype.toggle = function () { */ RealtimePreview.prototype.getEventHandler = function () { return mw.util.debounce( - this.doRealtimePreview.bind( this ), + function () { + // Only do preview if we're not in manual mode (as set in this.checkResponseTimes()). + if ( !this.inManualMode ) { + this.doRealtimePreview(); + } + }.bind( this ), this.configData.realtimeDebounce ); }; @@ -173,6 +192,7 @@ RealtimePreview.prototype.getEventHandler = function () { */ RealtimePreview.prototype.showError = function ( $msg ) { this.$previewNode.hide(); + this.manualWidget.toggle( false ); // There is no need for a default message because mw.Api.getErrorMessage() will // always provide something (even for no network connection, server-side fatal errors, etc.). this.errorLayout.setMessage( $msg ); @@ -184,6 +204,11 @@ RealtimePreview.prototype.showError = function ( $msg ) { * @param {number} time */ RealtimePreview.prototype.checkResponseTimes = function ( time ) { + // Don't track response times if we're already in manual mode. + if ( this.inManualMode ) { + return; + } + this.responseTimes.push( Date.now() - time ); if ( this.responseTimes.length < 3 ) { return; @@ -194,10 +219,10 @@ RealtimePreview.prototype.checkResponseTimes = function ( time ) { }, 0 ); if ( ( totalResponseTime / this.responseTimes.length ) > this.configData.realtimeDisableDuration ) { - // TODO: switch to the 'manual preview' workflow once designs/behaviour is finalized. - this.showError( - $( '
' ).text( '[PLACEHOLDER] Realtime preview is too slow' ) - ); + this.inManualMode = true; + // The error message might already be displayed if e.g. server timeout is greater than the disable-duration here. + this.errorLayout.toggle( false ); + this.manualWidget.toggle( true ); } this.responseTimes.shift(); @@ -218,6 +243,7 @@ RealtimePreview.prototype.doRealtimePreview = function () { this.$loadingBar.show(); var loadingSelectors = this.pagePreview.getLoadingSelectors(); loadingSelectors.push( '.ext-WikiEditor-realtimepreview-preview' ); + loadingSelectors.push( '.ext-WikiEditor-ManualWidget' ); this.errorLayout.toggle( false ); var time = Date.now(); diff --git a/modules/realtimepreview/RealtimePreview.less b/modules/realtimepreview/RealtimePreview.less index d300d829..14aadb16 100644 --- a/modules/realtimepreview/RealtimePreview.less +++ b/modules/realtimepreview/RealtimePreview.less @@ -24,7 +24,7 @@ @loadingbar-width: 20%; -.ext-WikiEditor-realtimepreview-loadingbar { +.ext-WikiEditor-realtimepreview-loadingbar div { position: absolute; z-index: 5; display: block; @@ -53,8 +53,8 @@ .ext-WikiEditor-twopanes-pane2 .ext-WikiEditor-reloadButton { display: none; position: absolute; - top: 12px; - right: 12px; + top: 8px; + right: 15px; z-index: 5; } diff --git a/modules/realtimepreview/TwoPaneLayout.less b/modules/realtimepreview/TwoPaneLayout.less index 5ddbdb34..a6c0c976 100644 --- a/modules/realtimepreview/TwoPaneLayout.less +++ b/modules/realtimepreview/TwoPaneLayout.less @@ -19,6 +19,8 @@ flex: 1 1 0; overflow: hidden; padding: 0; + display: flex; + flex-direction: column; .ext-WikiEditor-realtimepreview-preview { overflow: auto;