Jdlrobson has uploaded a new change for review.
https://gerrit.wikimedia.org/r/54069
Change subject: Rewrite createOverlay to use an Overlay View that is stackable
......................................................................
Rewrite createOverlay to use an Overlay View that is stackable
This refactors overlays so that you can have more than one
open at a time. When closed they are removed from the stack
until you escape back to the page content.
PhotoUploaderPreview now creates an instance of Overlay
- this is probably not perfect but it keeps this patchset as
simplistic as possible.
Change-Id: I26dc25cf47a2a964e7353a05a0fb4400388b79bf
---
M MobileFrontend.php
M includes/MobileFrontend.hooks.php
M javascripts/common/mf-navigation.js
M javascripts/modules/mf-languages.js
M javascripts/modules/mf-photo.js
M less/common/mf-navigation.less
M less/modules/mf-tables.less
M less/specials/userlogin.less
M stylesheets/common/mf-navigation.css
M stylesheets/modules/mf-tables.css
M stylesheets/specials/userlogin.css
A templates/overlay.html
A tests/js/common/mf-navigation.js
M tests/js/fixtures-templates.js
14 files changed, 213 insertions(+), 114 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend
refs/changes/69/54069/1
diff --git a/MobileFrontend.php b/MobileFrontend.php
index fa74116..0d956aa 100644
--- a/MobileFrontend.php
+++ b/MobileFrontend.php
@@ -215,6 +215,7 @@
'templates' => array(
'photoCopyrightDialog',
'leadPhoto',
+ 'overlay',
'photoUploader',
'photoUploadPreview',
'ctaDrawer'
diff --git a/includes/MobileFrontend.hooks.php
b/includes/MobileFrontend.hooks.php
index 8eb85ee..3533bb5 100644
--- a/includes/MobileFrontend.hooks.php
+++ b/includes/MobileFrontend.hooks.php
@@ -190,6 +190,7 @@
'javascripts/modules/mf-toggle-dynamic.js',
'javascripts/actions/mf-edit.js',
'tests/js/test_mf-edit.js',
'javascripts/common/mf-navigation.js',
+ 'tests/js/common/mf-navigation.js',
'javascripts/common/mf-notification.js',
'javascripts/modules/mf-photo.js',
'tests/js/test_mf-photo.js',
'javascripts/modules/mf-references.js',
'tests/js/test_references.js',
diff --git a/javascripts/common/mf-navigation.js
b/javascripts/common/mf-navigation.js
index 8a524f9..f0ce27a 100644
--- a/javascripts/common/mf-navigation.js
+++ b/javascripts/common/mf-navigation.js
@@ -5,6 +5,7 @@
u = M.utils, mfePrefix = M.prefix,
lastScrollTopPosition = 0,
inBeta = mw.config.get( 'wgMFMode' ) === 'beta',
+ Overlay,
Drawer, CtaDrawer;
Drawer = View.extend( {
@@ -55,41 +56,90 @@
template: M.template.get( 'ctaDrawer' )
} );
- function getOverlay() {
- return document.getElementById( 'mw-mf-overlay' );
+ /**
+ * Returns any overlays that have been added to the DOM
+ *
+ * @return {jQuery.object} All open overlays
+ */
+ function getOverlays() {
+ return $( '.mw-mf-overlay' );
}
- function closeOverlay( ) {
- $( 'html' ).removeClass( 'overlay' );
- window.scrollTo( document.body.scrollLeft,
lastScrollTopPosition );
- M.history.replaceHash( '#' );
+ /**
+ * Hides all overlays except last added overlay
+ */
+ function showTopOverlay() {
+ $( '.mw-mf-overlay' ).hide().last().show();
+ }
+
+ /**
+ * Attempts to escape back to article from overlay mode
+ *
+ * @return {Boolean} Whether attempt succeeded
+ */
+ function escapeOverlayMode() {
+ // Make sure all open overlays are closed before returning to
article
+ if ( getOverlays().length === 0 ) {
+ $( 'html' ).removeClass( 'overlay' );
+ window.scrollTo( document.body.scrollLeft,
lastScrollTopPosition );
+ M.history.replaceHash( '#' );
+ return true;
+ } else {
+ showTopOverlay();
+ return false;
+ }
}
function showOverlay() {
+ showTopOverlay();
lastScrollTopPosition = document.body.scrollTop;
- $( 'html' ).addClass( 'overlay' );
- window.scrollTo( 0, 0 ); // scroll right to top
- $( 'html' ).removeClass( 'navigationEnabled' );
+ $( 'html' ).addClass( 'overlay' ).
+ removeClass( 'navigationEnabled' );
+
+ // skip the URL bar if possible
+ window.scrollTo( 0, 1 );
}
- // FIXME: redo using view
+ Overlay = View.extend( {
+ defaults: {
+ heading: '',
+ content: '',
+ closeMsg: mw.msg( 'mobile-frontend-overlay-escape' )
+ },
+ template: M.template.get( 'overlay' ),
+ initialize: function() {
+ var self = this;
+ this.$( '.close' ).click( function( ev ) {
+ ev.preventDefault();
+ self.close();
+ } );
+ },
+ show: function() {
+ showOverlay();
+ },
+ close: function() {
+ this.$el.remove();
+ escapeOverlayMode();
+ }
+ } );
+
+ /**
+ * Convenience function for creating an overlay
+ *
+ * @param {String|jQuery.Object} heading: Text or html to appear in
header of overlay
+ * @param {String|jQuery.Object} contents: Html to appear in body of
overlay
+ * @return {Overlay} View representing overlay
+ */
function createOverlay( heading, contents, options ) {
options = options || {};
- var overlay = document.getElementById( mfePrefix + 'overlay' );
+ options.heading = typeof heading === 'string' ? '<h2>' +
heading + '</h2>' :
+ $( '<div>' ).append( heading ).html();
+ options.content = $( '<div>' ).append( contents ).html();
+ // FIXME: Set this as a default
+ options.el = $( '<div class="mw-mf-overlay">' ).appendTo(
document.body )[ 0 ];
+ var overlay = new Overlay( options );
M.history.pushState( options.hash || '#mw-mf-overlay' );
- showOverlay();
- $( overlay ).empty();
- $( '<div class="header">' ).appendTo( '#' + mfePrefix +
'overlay' );
- $( '<button id="close"></button>' ).text( mw.msg(
'mobile-frontend-overlay-escape' ) ).
- addClass( 'escapeOverlay' ).
- click( closeOverlay ).appendTo( '#' + mfePrefix +
'overlay .header' );
- if( typeof heading === 'string' ) {
- heading = $( '<h2 />' ).text( heading );
- }
- $( heading ).appendTo( '#' + mfePrefix + 'overlay .header' );
- $( overlay ).append( contents );
- $( overlay ).find( '.close' ).click( closeOverlay );
-
+ overlay.show();
return overlay;
}
@@ -137,7 +187,7 @@
M.on( 'history-change', function( curPage ) {
if ( curPage.hash === '#' || curPage.hash === '' ||
curPage.hash === '#_' ) {
- closeOverlay();
+ escapeOverlayMode();
closeNavigation();
} else if ( curPage.hash === '#mw-mf-page-left' ) {
toggleNavigation();
@@ -182,10 +232,9 @@
return {
CtaDrawer: CtaDrawer,
- closeOverlay: closeOverlay,
+ Overlay: Overlay,
createOverlay: createOverlay,
getPageMenu: getPageMenu,
- getOverlay: getOverlay,
showOverlay: showOverlay
};
}( jQuery ));
diff --git a/javascripts/modules/mf-languages.js
b/javascripts/modules/mf-languages.js
index a804d4a..7b85dbd 100644
--- a/javascripts/modules/mf-languages.js
+++ b/javascripts/modules/mf-languages.js
@@ -57,11 +57,11 @@
text( mw.msg( 'mobile-frontend-language-footer' )
).appendTo( $footer );
overlay = createOverlay( $search, $wrapper, { hash:
'#mw-mf-overlay-language' } );
- $lists = $( overlay ).find( 'ul' );
+ $lists = overlay.$( 'ul' );
$lists.find( 'a' ).on( 'click', function() {
M.emit( 'language-select', $( this ).attr( 'lang' ) );
} );
- $( overlay ).find( '.search' ).on( 'keyup', function() {
+ overlay.$( '.search' ).on( 'keyup', function() {
var matches = filterLists( $lists,
this.value.toLowerCase() );
if ( matches > 0 ) {
$footer.hide();
diff --git a/javascripts/modules/mf-photo.js b/javascripts/modules/mf-photo.js
index 3dbcd96..3d34cb0 100644
--- a/javascripts/modules/mf-photo.js
+++ b/javascripts/modules/mf-photo.js
@@ -182,13 +182,17 @@
initialize: function() {
var self = this,
- $description = this.$( 'textarea' ),
- $submitButton = this.$( 'button.submit' );
+ $overlay, $description, $submitButton;
+
+ this.overlay = nav.createOverlay( '', this.$el );
+ $overlay = this.overlay.$el;
+
+ $description = $overlay.find( 'textarea' );
+ $submitButton = $overlay.find( 'button.submit' );
this.$description = $description;
// make license links open in separate tabs
- this.$( '.license a' ).attr( 'target', '_blank' );
-
+ $overlay.find( '.license a' ).attr( 'target', '_blank'
);
// use input event too, Firefox doesn't fire keyup on
many devices:
// https://bugzilla.mozilla.org/show_bug.cgi?id=737658
$description.on( 'keyup input', function() {
@@ -202,7 +206,7 @@
$submitButton.on( 'click', function() {
self.emit( 'submit' );
} );
- this.$( 'button.cancel' ).on( 'click', function() {
+ $overlay.find( 'button.cancel' ).on( 'click',
function() {
self.emit( 'cancel' );
} );
},
@@ -214,6 +218,7 @@
setImageUrl: function( url ) {
var msg = mw.msg( 'mobile-frontend-image-ownership',
mw.config.get( 'wgUserName' ) ),
+ $overlay = this.overlay.$el,
data = {
bulletPoints: [
{ text: mw.msg(
'mobile-frontend-image-ownership-bullet-one' ) },
@@ -224,14 +229,14 @@
leadText: msg
};
this.imageUrl = url;
- this.$( '.loading' ).removeClass( 'loading' ).text( msg
);
+ $overlay.find( '.loading' ).removeClass( 'loading'
).text( msg );
$( '<a class="help">' ).
text( mw.msg(
'mobile-frontend-image-ownership-help' ) ).
click( function() {
nav.createOverlay( '', $(
M.template.get( 'photoCopyrightDialog' ).render( data ) ) );
} ).
- appendTo( this.$( 'p' ) );
- $( '<img>' ).attr( 'src', url ).prependTo( this.$(
'.photoPreview' ) );
+ appendTo( $overlay.find( 'p' ) );
+ $( '<img>' ).attr( 'src', url ).prependTo(
$overlay.find( '.photoPreview' ) );
}
} );
@@ -362,15 +367,14 @@
preview.
on( 'cancel', function() {
self.log( { action:
'previewCancel' } );
- nav.closeOverlay();
+ preview.overlay.close();
} ).
on( 'submit', function() {
self.log( { action:
'previewSubmit' } );
self._submit();
} );
- // FIXME: replace if we make overlay an
object (and inherit from it?)
- nav.createOverlay( null, preview.$el );
+ preview.overlay.show();
// skip the URL bar if possible
window.scrollTo( 0, 1 );
@@ -391,7 +395,7 @@
progressPopup = new PhotoUploadProgress();
this.emit( 'start' );
- nav.closeOverlay();
+ this.preview.overlay.close();
popup.show( progressPopup.$el, 'locked noButton
loading' );
progressPopup.on( 'cancel', function() {
api.abort();
diff --git a/less/common/mf-navigation.less b/less/common/mf-navigation.less
index 0709356..6fb2056 100644
--- a/less/common/mf-navigation.less
+++ b/less/common/mf-navigation.less
@@ -56,7 +56,8 @@
min-height: 100%;
}
-#mw-mf-header, #mw-mf-overlay .header {
+#mw-mf-header,
+.mw-mf-overlay .header {
color: black;
.vertical-gradient( @searchBoxColor, @searchBoxColorTo );
border-bottom: 1px solid #e2e2e2;
@@ -215,23 +216,15 @@
overflow: hidden;
}
-#mw-mf-overlay {
- display: none;
-}
-
-#mw-mf-overlay li {
- text-align: left;
-}
-
-#mw-mf-overlay .mw-mf-overlay-footer a {
- display: inline;
-}
-
.escapeOverlay {
display: none;
}
html.overlay {
+ .mw-mf-overlay {
+ display: block;
+ }
+
#mw-mf-viewport {
display: none;
}
@@ -256,11 +249,17 @@
}
}
-.overlay #mw-mf-overlay {
- display: block;
-}
+.mw-mf-overlay {
+ display: none;
-#mw-mf-overlay {
+ .mw-mf-overlay-header {
+ background-color: #F1F1F1;
+ }
+
+ li {
+ text-align: left;
+ }
+
div.content {
padding-bottom: 20px;
}
@@ -285,6 +284,23 @@
button {
margin: 0 5px;
+ }
+ }
+
+ .mw-mf-overlay-footer,
+ .mw-mf-overlay-header {
+ padding: 4px 8px 4px @searchBarPaddingLeft;
+
+ margin: 0;
+ font-size: 0.8em;
+ color: #666;
+ border-bottom: solid 1px #eee;
+ }
+
+ .mw-mf-overlay-footer {
+ a {
+ display: inline;
+ color: #002BB8;
}
}
}
@@ -400,26 +416,6 @@
#mw-mf-page-left,
#mw-mf-page-center {
min-height: 100%;
-}
-
-#mw-mf-overlay {
- .mw-mf-overlay-footer,
- .mw-mf-overlay-header {
- padding: 4px 8px 4px @searchBarPaddingLeft;
-
- margin: 0;
- font-size: 0.8em;
- color: #666;
- border-bottom: solid 1px #eee;
- }
-}
-
-#mw-mf-overlay .mw-mf-overlay-footer a {
- color: #002BB8;
-}
-
-#mw-mf-overlay .mw-mf-overlay-header {
- background-color: #F1F1F1;
}
.supportsPositionFixed #mw-mf-page-center {
diff --git a/less/modules/mf-tables.less b/less/modules/mf-tables.less
index 88fd456..c084f8c 100644
--- a/less/modules/mf-tables.less
+++ b/less/modules/mf-tables.less
@@ -1,6 +1,6 @@
@import "../mf-mixins.less";
-#mw-mf-overlay {
+.mw-mf-overlay {
.tableContent > table {
.boxshadow( -4px, 10px, 10px, -1px, #aaa );
}
diff --git a/less/specials/userlogin.less b/less/specials/userlogin.less
index 18a44f5..43fbb77 100644
--- a/less/specials/userlogin.less
+++ b/less/specials/userlogin.less
@@ -7,7 +7,7 @@
background-color: @overlayContentBackground;
}
- #mw-mf-overlay {
+ .mw-mf-overlay {
.header {
h1 {
padding-left: @overlayHeadingIndent;
diff --git a/stylesheets/common/mf-navigation.css
b/stylesheets/common/mf-navigation.css
index 96b6d0c..8dba013 100644
--- a/stylesheets/common/mf-navigation.css
+++ b/stylesheets/common/mf-navigation.css
@@ -163,7 +163,7 @@
min-height: 100%;
}
#mw-mf-header,
-#mw-mf-overlay .header {
+.mw-mf-overlay .header {
color: black;
background-color: #f3f3f3;
background-image: -moz-linear-gradient(top, #fafafa 0, #f3f3f3 100%);
@@ -174,7 +174,7 @@
border-bottom: 1px solid #e2e2e2;
}
#mw-mf-header h1,
-#mw-mf-overlay .header h1 {
+.mw-mf-overlay .header h1 {
color: #000000;
line-height: 46px;
margin: 0;
@@ -294,17 +294,11 @@
height: 100%;
overflow: hidden;
}
-#mw-mf-overlay {
- display: none;
-}
-#mw-mf-overlay li {
- text-align: left;
-}
-#mw-mf-overlay .mw-mf-overlay-footer a {
- display: inline;
-}
.escapeOverlay {
display: none;
+}
+html.overlay .mw-mf-overlay {
+ display: block;
}
html.overlay #mw-mf-viewport {
display: none;
@@ -349,20 +343,26 @@
html.overlay ul.content li.preferred {
font-weight: bold;
}
-.overlay #mw-mf-overlay {
- display: block;
+.mw-mf-overlay {
+ display: none;
}
-#mw-mf-overlay div.content {
+.mw-mf-overlay .mw-mf-overlay-header {
+ background-color: #F1F1F1;
+}
+.mw-mf-overlay li {
+ text-align: left;
+}
+.mw-mf-overlay div.content {
padding-bottom: 20px;
}
-#mw-mf-overlay .content {
+.mw-mf-overlay .content {
margin-top: 14pt;
}
-#mw-mf-overlay .content .close {
+.mw-mf-overlay .content .close {
display: block;
margin: auto;
}
-#mw-mf-overlay .buttonBar {
+.mw-mf-overlay .buttonBar {
position: fixed;
bottom: 0;
width: 100%;
@@ -371,8 +371,20 @@
background: #f3f3f3;
text-align: center;
}
-#mw-mf-overlay .buttonBar button {
+.mw-mf-overlay .buttonBar button {
margin: 0 5px;
+}
+.mw-mf-overlay .mw-mf-overlay-footer,
+.mw-mf-overlay .mw-mf-overlay-header {
+ padding: 4px 8px 4px 40px;
+ margin: 0;
+ font-size: 0.8em;
+ color: #666;
+ border-bottom: solid 1px #eee;
+}
+.mw-mf-overlay .mw-mf-overlay-footer a {
+ display: inline;
+ color: #002BB8;
}
.alert {
padding: 0.5em 1em;
@@ -473,20 +485,6 @@
#mw-mf-page-left,
#mw-mf-page-center {
min-height: 100%;
-}
-#mw-mf-overlay .mw-mf-overlay-footer,
-#mw-mf-overlay .mw-mf-overlay-header {
- padding: 4px 8px 4px 40px;
- margin: 0;
- font-size: 0.8em;
- color: #666;
- border-bottom: solid 1px #eee;
-}
-#mw-mf-overlay .mw-mf-overlay-footer a {
- color: #002BB8;
-}
-#mw-mf-overlay .mw-mf-overlay-header {
- background-color: #F1F1F1;
}
.supportsPositionFixed #mw-mf-page-center {
min-height: none !important;
diff --git a/stylesheets/modules/mf-tables.css
b/stylesheets/modules/mf-tables.css
index 81d1b8d..246f21d 100644
--- a/stylesheets/modules/mf-tables.css
+++ b/stylesheets/modules/mf-tables.css
@@ -1,4 +1,4 @@
-#mw-mf-overlay .tableContent > table {
+.mw-mf-overlay .tableContent > table {
box-shadow: -4px 10px 10px -1px #aaaaaa;
}
#content table.expando {
diff --git a/stylesheets/specials/userlogin.css
b/stylesheets/specials/userlogin.css
index fa29e01..c6db02a 100644
--- a/stylesheets/specials/userlogin.css
+++ b/stylesheets/specials/userlogin.css
@@ -1,7 +1,7 @@
.specialPage.overlay body {
background-color: #ffffff;
}
-.specialPage.overlay #mw-mf-overlay .header h1 {
+.specialPage.overlay .mw-mf-overlay .header h1 {
padding-left: 0.4em;
}
#mw-mf-login .watermark,
diff --git a/templates/overlay.html b/templates/overlay.html
new file mode 100644
index 0000000..093bb5e
--- /dev/null
+++ b/templates/overlay.html
@@ -0,0 +1,5 @@
+<div class="header">
+ <button class="close escapeOverlay">{{closeMsg}}</button>
+ {{{heading}}}
+</div>
+{{{content}}}
diff --git a/tests/js/common/mf-navigation.js b/tests/js/common/mf-navigation.js
new file mode 100644
index 0000000..5ddb38c
--- /dev/null
+++ b/tests/js/common/mf-navigation.js
@@ -0,0 +1,44 @@
+( function( nav, $ ) {
+
+module( 'MobileFrontend: mf-navigation.js', {} );
+
+test( 'Simple overlay', function() {
+ var overlay = nav.createOverlay( 'Title', 'Text' );
+ strictEqual( overlay.$el[0].parentNode, document.body, 'In DOM' );
+ strictEqual( overlay.$el.html(), '<h2>Title</h2>/Text' );
+} );
+
+test( 'HTML overlay', function() {
+ var overlay = nav.createOverlay( $( '<div>Awesome: <input></div>' ),
+ $('<div class="content">YO</div>' ) );
+ strictEqual( overlay.$el.html(), '<div>Awesome: <input></div>/<div
class="content">YO</div>' );
+} );
+
+test( 'Close overlay', function() {
+ var overlay = nav.createOverlay( 'Title', 'Text' );
+ overlay.close();
+ strictEqual( overlay.$el[0].parentNode, null, 'No longer in DOM' );
+} );
+
+test( 'Stacked overlays', function() {
+ var overlay = nav.createOverlay( 'Overlay 1', 'Text' ),
+ overlayTwo = nav.createOverlay( 'Overlay 2', 'Text' );
+ overlay.show();
+ overlayTwo.show();
+ strictEqual( $( 'html' ).hasClass( 'overlay' ), true, 'In overlay mode'
);
+ strictEqual( overlayTwo.$el.is( ':visible' ), true,
+ 'The second overlay is the active one' );
+ strictEqual( overlay.$el.is( ':visible' ), false,
+ 'The first overlay is marked as inactive' );
+
+ // now close the top stacked one...
+ overlayTwo.close();
+ strictEqual( overlayTwo.$el[0].parentNode, null, 'No longer in DOM' );
+ strictEqual( overlay.$el[0].parentNode, document.body, 'Still in DOM' );
+ strictEqual( overlay.$el.is( ':visible' ), true,
+ 'The first overlay is now active' );
+ strictEqual( $( 'html' ).hasClass( 'overlay' ), true, 'Still in overlay
mode' );
+} );
+
+
+} )( mw.mobileFrontend.require( 'navigation' ), jQuery );
diff --git a/tests/js/fixtures-templates.js b/tests/js/fixtures-templates.js
index f49f256..0cb2c96 100644
--- a/tests/js/fixtures-templates.js
+++ b/tests/js/fixtures-templates.js
@@ -2,3 +2,4 @@
mw.mobileFrontend.template.add( 'leadPhoto', '' );
mw.mobileFrontend.template.add( 'photoUploader', '' );
mw.mobileFrontend.template.add( 'ctaDrawer', '' );
+mw.mobileFrontend.template.add( 'overlay', '{{{heading}}}/{{{content}}}' );
--
To view, visit https://gerrit.wikimedia.org/r/54069
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I26dc25cf47a2a964e7353a05a0fb4400388b79bf
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits