jenkins-bot has submitted this change and it was merged.
Change subject: Hijack watchstar behaviour in alpha
......................................................................
Hijack watchstar behaviour in alpha
Note: This only overrides default page watchstar. Watchstars in other places
still save to normal watchstar for time being.
Dependency: I00d83f28f88cd3ae63a0858b7b48c5765fe35c20
Dependency: I90e172ba3e1fe2531a7f50f20bb9319a7f5747d3
Bug: T91294
Change-Id: Iac6df0166e12a19acbce44aa23f201ce4e050ce8
---
M Gather.php
M i18n/en.json
M i18n/qqq.json
M includes/Gather.hooks.php
M includes/Resources.php
A resources/ext.gather.watchstar.icons/green_check.svg
A resources/ext.gather.watchstar.icons/grey_check.svg
A resources/ext.gather.watchstar/CollectionsContentOverlay.js
A resources/ext.gather.watchstar/CollectionsWatchstar.js
A resources/ext.gather.watchstar/content.hogan
A resources/ext.gather.watchstar/contentOverlay.less
A resources/ext.gather.watchstar/init.js
A tests/browser/features/add_to_collection.feature
A tests/browser/features/step_definitions/add_to_collection_steps.rb
M tests/browser/features/step_definitions/common_steps.rb
M tests/browser/features/support/pages/article_page.rb
16 files changed, 431 insertions(+), 2 deletions(-)
Approvals:
Robmoen: Looks good to me, approved
Jhernandez: Looks good to me, but someone else must approve
Jdlrobson: Looks good to me, but someone else must approve
jenkins-bot: Verified
diff --git a/Gather.php b/Gather.php
index ebaf74a..64899bd 100644
--- a/Gather.php
+++ b/Gather.php
@@ -74,7 +74,7 @@
$wgHooks['UnitTestsList'][] = 'Gather\Hooks::onUnitTestsList';
$wgHooks['getUserPermissionsErrors'][] =
'Gather\Hooks::onGetUserPermissionsErrors';
$wgHooks['ContentHandlerDefaultModelFor'][] =
'Gather\Hooks::onContentHandlerDefaultModelFor';
-
+$wgHooks['SkinMinervaDefaultModules'][] =
'Gather\Hooks::onSkinMinervaDefaultModules';
// ResourceLoader modules
require_once __DIR__ . "/includes/Resources.php";
diff --git a/i18n/en.json b/i18n/en.json
index 58d5a73..2caa2bb 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -2,6 +2,12 @@
"@metadata": {
"authors": []
},
+ "gather-collection-member": "Is member of collection.",
+ "gather-collection-non-member": "Is not member of collection.",
+ "gather-anon-cta": "Add this page to a collection that you can share
with the world.",
+ "gather-add-to-existing": "Add to existing collection",
+ "gather-add-toast": "The page has been added to your \"$1\"
collection.",
+ "gather-remove-toast": "The page has been removed from your \"$1\"
collection.",
"gather-desc": "Component of Mobile Frontend allowing users to curate
lists.",
"gather-anon-view-lists": "You need to be logged in to see your
Collections.",
"gather-watchlist-title": "Watchlist",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index c782389..ca70159 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -4,6 +4,12 @@
"Liuxinyu970226"
]
},
+ "gather-collection-member": "Alternative text displayed next to
collection name when page is a member.",
+ "gather-collection-non-member": "Alternative text displayed next to
collection name when page is not a member.",
+ "gather-anon-cta": "Message that shows to anonymous users when they
click the add to collection button.",
+ "gather-add-to-existing": "Heading that shows in the watchstar content
overlay above a list of your existing collections.",
+ "gather-add-toast": "Message displayed when you add an item to a
collection. Parameters:\n* $1 - Name of collection.",
+ "gather-remove-toast": "Message displayed when you remove an item from
a collection. Parameters:\n* $1 - Name of collection.",
"gather-desc":
"{{desc|name=Gather|url=https://www.mediawiki.org/wiki/Extension:Gather}}",
"gather-anon-view-lists": "Note: Experimental feature. Messages and UI
may change radically at any time. Translate at your own risk.\n Text shown when
trying to see your own collections on [[Special:Gather]] but the user is not
logged in.",
"gather-watchlist-title": "Note: Experimental feature. Messages and UI
may change radically at any time. Translate at your own risk.\n Title used for
special casing the Watchlist collection on the [[Special:Gather]]
page.\n{{Identical|Watchlist}}",
diff --git a/includes/Gather.hooks.php b/includes/Gather.hooks.php
index c1595da..c0f88e0 100644
--- a/includes/Gather.hooks.php
+++ b/includes/Gather.hooks.php
@@ -26,6 +26,20 @@
die( -1 );
}
}
+
+ /**
+ * Modify mobile frontend modules to hook into the watchstar
+ * @param SkinMinerva $skin
+ * @param array $modules Resource loader modules
+ * @return boolean
+ */
+ public static function onSkinMinervaDefaultModules( $skin, &$modules ) {
+ if ( MobileContext::singleton()->isAlphaGroupMember() ) {
+ $modules['watch'] = array( 'ext.gather.watchstar' );
+ }
+ return true;
+ }
+
/**
* Add collections link in personal tools menu
* @param array &$items Items array to be added to menu
diff --git a/includes/Resources.php b/includes/Resources.php
index 7524dac..78315dd 100644
--- a/includes/Resources.php
+++ b/includes/Resources.php
@@ -71,4 +71,43 @@
'group' => 'other',
),
+ 'ext.gather.watchstar.icons' => $wgGatherResourceFileModuleBoilerplate
+ array(
+ 'class' => 'ResourceLoaderImageModule',
+ 'prefix' => 'mw-ui',
+ 'images' => array(
+ // FIXME: ':before' suffix should be configurable in
image module.
+ 'icon' => array(
+ 'tick-disabled:before' =>
'ext.gather.watchstar.icons/grey_check.svg',
+ 'tick:before' =>
'ext.gather.watchstar.icons/green_check.svg',
+ ),
+ ),
+ ),
+
+ 'ext.gather.watchstar' => $wgGatherResourceFileModuleBoilerplate +
array(
+ 'dependencies' => array(
+ 'mobile.watchstar',
+ 'mobile.contentOverlays',
+ 'ext.gather.watchstar.icons',
+ ),
+ 'styles' => array(
+ 'ext.gather.watchstar/contentOverlay.less',
+ ),
+ 'messages' => array(
+ 'gather-add-to-existing',
+ 'gather-watchlist-title',
+ 'gather-add-toast',
+ 'gather-remove-toast',
+ 'gather-anon-cta',
+ 'gather-collection-member',
+ 'gather-collection-non-member',
+ ),
+ 'templates' => array(
+ 'content.hogan' => 'ext.gather.watchstar/content.hogan',
+ ),
+ 'scripts' => array(
+
'resources/ext.gather.watchstar/CollectionsContentOverlay.js',
+
'resources/ext.gather.watchstar/CollectionsWatchstar.js',
+ 'resources/ext.gather.watchstar/init.js',
+ ),
+ ),
) );
diff --git a/resources/ext.gather.watchstar.icons/green_check.svg
b/resources/ext.gather.watchstar.icons/green_check.svg
new file mode 100644
index 0000000..15afc29
--- /dev/null
+++ b/resources/ext.gather.watchstar.icons/green_check.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version:
6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 51.6 51.6" enable-background="new 0 0 51.6 51.6"
xml:space="preserve">
+<g>
+ <circle fill="#00AF89" cx="25.8" cy="25.8" r="24.7"/>
+ <polygon fill="#FFFFFF" points="39,18.6 35.7,15.3 21.3,29.8 15.9,24.3
12.7,27.6 21.3,36.3 "/>
+</g>
+</svg>
diff --git a/resources/ext.gather.watchstar.icons/grey_check.svg
b/resources/ext.gather.watchstar.icons/grey_check.svg
new file mode 100644
index 0000000..c4e93a6
--- /dev/null
+++ b/resources/ext.gather.watchstar.icons/grey_check.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version:
6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 51.6 51.6" enable-background="new 0 0 51.6 51.6"
xml:space="preserve">
+<g>
+ <circle fill="#CCCCCC" cx="25.8" cy="25.8" r="24.7"/>
+ <polygon fill="#FFFFFF" points="39,18.6 35.7,15.3 21.3,29.8 15.9,24.3
12.7,27.6 21.3,36.3 "/>
+</g>
+</svg>
diff --git a/resources/ext.gather.watchstar/CollectionsContentOverlay.js
b/resources/ext.gather.watchstar/CollectionsContentOverlay.js
new file mode 100644
index 0000000..d441fd9
--- /dev/null
+++ b/resources/ext.gather.watchstar/CollectionsContentOverlay.js
@@ -0,0 +1,108 @@
+( function ( M, $ ) {
+
+ var CollectionsContentOverlay,
+ icons = M.require( 'icons' ),
+ toast = M.require( 'toast' ),
+ Icon = M.require( 'Icon' ),
+ WatchstarApi = M.require( 'modules/watchstar/WatchstarApi' ),
+ ContentOverlay = M.require( 'modules/tutorials/ContentOverlay'
);
+
+ /**
+ * A clickable watchstar for managing collections
+ * @class CollectionsContentOverlay
+ * @extends ContentOverlay
+ */
+ CollectionsContentOverlay = ContentOverlay.extend( {
+ /**
+ * FIXME: re-evaluate content overlay default classes/css.
+ * @inheritdoc
+ */
+ className: 'collection-overlay content-overlay overlay
position-fixed',
+ /** @inheritdoc */
+ templatePartials: {
+ content: mw.template.get( 'ext.gather.watchstar',
'content.hogan' )
+ },
+ /** @inheritdoc */
+ events: {
+ click: 'onClickInsideOverlay',
+ 'click .overlay-content li': 'onSelectCollection'
+ },
+ /** @inheritdoc */
+ hasFixedHeader: false,
+ /** @inheritdoc */
+ defaults: {
+ /** @inheritdoc */
+ fixedHeader: false,
+ iconButton: new Icon( {
+ name: 'tick',
+ label: mw.msg( 'gather-collection-member' )
+ } ).toHtmlString(),
+ iconDisabledButton: new Icon( {
+ name: 'tick-disabled',
+ label: mw.msg( 'gather-collection-non-member' )
+ } ).toHtmlString(),
+ title: mw.config.get( 'wgTitle' ),
+ spinner: icons.spinner().toHtmlString(),
+ subheading: mw.msg( 'gather-add-to-existing' ),
+ collections: []
+ },
+ /** @inheritdoc */
+ initialize: function () {
+ this.api = new WatchstarApi();
+ ContentOverlay.prototype.initialize.apply( this,
arguments );
+ },
+ /** @inheritdoc */
+ postRender: function () {
+ this.$( '.spinner' ).hide();
+ },
+ /**
+ * Event handler for all clicks inside overlay.
+ * @param {jQuery.Event} ev
+ */
+ onClickInsideOverlay: function ( ev ) {
+ ev.stopPropagation();
+ },
+ /**
+ * Event handler for selecting an existing collection.
+ * @param {jQuery.Event} ev
+ */
+ onSelectCollection: function ( ev ) {
+ var self = this,
+ api = this.api,
+ collection,
+ $target = $( ev.target ),
+ page = M.getCurrentPage();
+
+ collection = {
+ title: $target.data( 'collection-title' ),
+ id: $target.data( 'collection-id' )
+ };
+ api.toggleStatus( page ).done( function () {
+ var msg, page = M.getCurrentPage();
+ // update current page
+ page.options.isWatched = api.isWatchedPage(
page );
+ // show toast
+ msg = api.isWatchedPage( page ) ?
'gather-add-toast' : 'gather-remove-toast';
+ toast.show( mw.msg( msg, collection.title ),
'toast' );
+ self.hide();
+ if ( page.options.isWatched ) {
+ /**
+ * @event watch
+ * Fired when the watch star is changed
to watched status
+ */
+ self.emit( 'watch' );
+ } else {
+ /**
+ * @event unwatch
+ * Fired when the watch star is changed
to unwatched status
+ */
+ self.emit( 'unwatch' );
+ }
+ } );
+ this.$( '.spinner' ).show();
+ ev.stopPropagation();
+ }
+ } );
+ M.define( 'ext.gather.watchstar/CollectionsContentOverlay',
CollectionsContentOverlay );
+
+}( mw.mobileFrontend, jQuery ) );
diff --git a/resources/ext.gather.watchstar/CollectionsWatchstar.js
b/resources/ext.gather.watchstar/CollectionsWatchstar.js
new file mode 100644
index 0000000..aa57197
--- /dev/null
+++ b/resources/ext.gather.watchstar/CollectionsWatchstar.js
@@ -0,0 +1,84 @@
+// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+( function ( M, $ ) {
+
+ var CollectionsWatchstar,
+ CollectionsContentOverlay = M.require(
'ext.gather.watchstar/CollectionsContentOverlay' ),
+ Watchstar = M.require( 'modules/watchstar/Watchstar' );
+
+ /**
+ * A clickable watchstar for managing collections
+ * @class CollectionsWatchstar
+ * @extends Watchstar
+ */
+ CollectionsWatchstar = Watchstar.extend( {
+ /** @inheritdoc */
+ ctaDrawerOptions: {
+ content: mw.msg( 'gather-anon-cta' ),
+ queryParams: {
+ campaign: 'gather',
+ returntoquery:
'article_action=add_to_collection'
+ }
+ },
+ /**
+ * @inheritdoc
+ * @cfg {Object} defaults Default options hash.
+ * @cfg {Object} defaults.collections definitions of the users
existing collections
+ */
+ defaults: $.extend( {}, Watchstar.prototype.defaults, {
+ collections: []
+ } ),
+ /** @inheritdoc */
+ postRender: function ( options ) {
+ var $el = this.$el;
+ Watchstar.prototype.postRender.apply( this, arguments );
+ // For newly authenticated users via CTA force dialog
to open.
+ if ( options.isNewlyAuthenticatedUser ) {
+ setTimeout( function () {
+ $el.trigger( 'click' );
+ }, 500 );
+ delete options.isNewlyAuthenticatedUser;
+ }
+ },
+ /** @inheritdoc */
+ onStatusToggle: function ( ev ) {
+ // Open the collections content overlay to deal with
this.
+ var self = this,
+ overlay = new CollectionsContentOverlay( {
+ collections: this.options.collections
+ } );
+ overlay.on( 'watch', function () {
+ self.newStatus( true );
+ } );
+ overlay.on( 'unwatch', function () {
+ self.newStatus( false );
+ } );
+ overlay.show();
+ ev.stopPropagation();
+ },
+ /**
+ * Sets a new status on the watchstar
+ * @param {bool} newStatus
+ */
+ newStatus: function ( newStatus ) {
+ if ( newStatus ) {
+ this.options.isWatched = true;
+ this.render();
+ /**
+ * @event watch
+ * Fired when the watch star is changed to
watched status
+ */
+ this.emit( 'watch' );
+ } else {
+ this.options.isWatched = false;
+ this.render();
+ /**
+ * @event unwatch
+ * Fired when the watch star is changed to
unwatched status
+ */
+ this.emit( 'unwatch' );
+ }
+ }
+ } );
+ M.define( 'ext.gather.watchstar/CollectionsWatchstar',
CollectionsWatchstar );
+
+}( mw.mobileFrontend, jQuery ) );
diff --git a/resources/ext.gather.watchstar/content.hogan
b/resources/ext.gather.watchstar/content.hogan
new file mode 100644
index 0000000..be10732
--- /dev/null
+++ b/resources/ext.gather.watchstar/content.hogan
@@ -0,0 +1,10 @@
+{{{spinner}}}
+<h3>{{subheading}}</h3>
+<ul>
+{{#collections}}
+ <li data-collection-title="{{title}}" data-collection-id="{{id}}">
+ {{title}}
{{^titleInCollection}}{{{iconDisabledButton}}}{{/titleInCollection}}
+ {{#titleInCollection}}{{{iconButton}}}{{/titleInCollection}}
+ </li>
+{{/collections}}
+</ul>
diff --git a/resources/ext.gather.watchstar/contentOverlay.less
b/resources/ext.gather.watchstar/contentOverlay.less
new file mode 100644
index 0000000..e943d80
--- /dev/null
+++ b/resources/ext.gather.watchstar/contentOverlay.less
@@ -0,0 +1,52 @@
+@import "minerva.variables";
+@import "minerva.mixins";
+
+.overlay.collection-overlay {
+ font-size: .9em;
+ text-align: left;
+ left: 3.4em;
+ right: 3.4em;
+ width: auto;
+ // No padding on the overlay to have the header stuck at the top,
padding on
+ // the content goes on .overlay-content
+ padding: 0;
+
+ .overlay-header-container .overlay-header {
+ li {
+ // Make the heading row normal height
+ padding: 0;
+ margin: 0;
+ }
+ }
+
+ .overlay-content {
+ padding: 1em;
+
+ h3 {
+ margin-top: 0.5em;
+ }
+
+ li {
+ cursor: pointer;
+ border-top: solid 1px @grayLight;
+ font-size: 1.4em;
+ padding: 12px 0;
+ margin: 12px 0;
+
+ > div {
+ float: right;
+ }
+ }
+ }
+
+ &.content-overlay {
+ background: white;
+ color: @grayDark;
+ top: @headerHeight * 1.2;
+ bottom: @headerHeight * 1.2;
+ left: 2em;
+ right: 2em;
+ width: auto;
+ }
+
+}
diff --git a/resources/ext.gather.watchstar/init.js
b/resources/ext.gather.watchstar/init.js
new file mode 100644
index 0000000..a446cd3
--- /dev/null
+++ b/resources/ext.gather.watchstar/init.js
@@ -0,0 +1,34 @@
+// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+( function ( M, $ ) {
+
+ var CollectionsWatchstar = M.require(
'ext.gather.watchstar/CollectionsWatchstar' ),
+ util = M.require( 'util' ),
+ user = M.require( 'user' );
+
+ /**
+ * Toggle the watch status of a known page
+ * @method
+ * @param {Page} page
+ * @ignore
+ */
+ function init( page ) {
+ var $container = $( '#ca-watch' );
+ if ( !page.inNamespace( 'special' ) ) {
+ new CollectionsWatchstar( {
+ el: $container,
+ collections: [
+ {
+ id: 0,
+ title: mw.msg(
'gather-watchlist-title' ),
+ titleInCollection:
page.isWatched()
+ }
+ ],
+ page: page,
+ isAnon: user.isAnon(),
+ isNewlyAuthenticatedUser:
util.query.article_action === 'add_to_collection'
+ } );
+ }
+ }
+ init( M.getCurrentPage() );
+
+}( mw.mobileFrontend, jQuery ) );
diff --git a/tests/browser/features/add_to_collection.feature
b/tests/browser/features/add_to_collection.feature
new file mode 100644
index 0000000..6d1b0a4
--- /dev/null
+++ b/tests/browser/features/add_to_collection.feature
@@ -0,0 +1,17 @@
+@chrome @en.m.wikipedia.beta.wmflabs.org
+Feature: Add to a collection
+
+ Background:
+ Given I am logged in
+ And I am using the mobile site
+ And I am in alpha mode
+ And I am on the "Selenium Gather test" page
+
+ Scenario:
+ When I click the watchstar
+ Then I see the collection dialog
+
+ Scenario:
+ When I click the watchstar
+ And I select a collection
+ Then I see a toast
diff --git a/tests/browser/features/step_definitions/add_to_collection_steps.rb
b/tests/browser/features/step_definitions/add_to_collection_steps.rb
new file mode 100644
index 0000000..770f825
--- /dev/null
+++ b/tests/browser/features/step_definitions/add_to_collection_steps.rb
@@ -0,0 +1,7 @@
+When(/^I select a collection$/) do
+ on(ArticlePage).collections_overlay_collection_one_element.when_present.click
+end
+
+Then(/^I see the collection dialog$/) do
+ expect(on(ArticlePage).collections_overlay_element).to exist
+end
diff --git a/tests/browser/features/step_definitions/common_steps.rb
b/tests/browser/features/step_definitions/common_steps.rb
index 3511c82..68f3d4c 100644
--- a/tests/browser/features/step_definitions/common_steps.rb
+++ b/tests/browser/features/step_definitions/common_steps.rb
@@ -6,3 +6,26 @@
page.refresh
end
end
+
+Given(/^I am in alpha mode$/) do
+ on(MainPage) do |page|
+ page.goto
+ # A domain is explicitly given to avoid a bug in earlier versions of Chrome
+ page.browser.cookies.add 'optin', 'alpha', domain:
URI.parse(page.page_url_value).host
+ page.refresh
+ end
+end
+
+Then(/^I see a toast$/) do
+ expect(on(ArticlePage).toast_element.when_present).to be_visible
+end
+
+Given(/^I am on the "(.+)" page$/) do |article|
+ # Ensure we do not cause a redirect
+ article = article.sub(/ /, '_')
+ visit(ArticlePage, using_params: { article_name: article })
+end
+
+When(/^I click the watchstar$/) do
+ on(ArticlePage).watch_star_element.when_present.click
+end
diff --git a/tests/browser/features/support/pages/article_page.rb
b/tests/browser/features/support/pages/article_page.rb
index 635a589..98a53b0 100644
--- a/tests/browser/features/support/pages/article_page.rb
+++ b/tests/browser/features/support/pages/article_page.rb
@@ -3,5 +3,14 @@
include URL
page_url URL.url('<%=params[:article_name]%><%=params[:hash]%>')
-end
+ # UI elements
+ li(:watch_star, id: 'ca-watch')
+
+ # toast
+ div(:toast, class: 'toast')
+
+ # collections
+ div(:collections_overlay, css: '.collection-overlay')
+ li(:collections_overlay_collection_one, css: '.collection-overlay ul li',
index: 0)
+end
--
To view, visit https://gerrit.wikimedia.org/r/193015
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Iac6df0166e12a19acbce44aa23f201ce4e050ce8
Gerrit-PatchSet: 15
Gerrit-Project: mediawiki/extensions/Gather
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: Jhernandez <[email protected]>
Gerrit-Reviewer: Robmoen <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits