Refactor existing Restbase gateway and extract shared logic into
shared Restbase provider. Also introduced new createNullModel()
which defines an empty preview model.
Additionally improve naming in new gateways/formatter so function
names are more explicity.
* Htmlize() became formatPlainTextExtract() as it should be used
only with plain text extracts
* removeEllipsis() became removeTrailingEllipsis() as it removes
only trailing ellipsis.
* src/gateway/index.js defines gateways by configuration name stored
in extension.json
Bug: T165018
Change-Id: Ibe54dddfc1080e94814d1562d41e85cb6b43bfc1
Depends-On: I4f42c61b155a37c5dd42bc40034583865abd5d7a
Follows-up 79f3b318d0.
Number#toString supports up to Base 32.
Same collision behaviour but with a shorter string.
Typical length with Base 32: 7 (max: 11)
Typical length with Base 16: 9 (max: 14)
Change-Id: I91e91341cbecdec24549ace6a6300550f5b449ee
This reduces the number of 301 Redirect responses when fetching previews
from RESTBase.
Bug: T167633
Change-Id: I830947ab79e72dcc023193412c8d5bcee986e23f
Page Previews should be able to consume HTML response generated by
MediaWiki. First we need to move out plain text crunching from
renderer.js and model.js. Mediawiki and Restbase gateways will have
to parse/htmlize plaintext into nice HTML by themselves.
Bug: T165018
Change-Id: I5d7e9f610bb809aa9fb035a4a9f96e9e8796c9d8
...instead of 1 event per link
Supporting changes:
* Delegate events on the container when booting up
* Check eligibility of title on event triggered
* Pass the title from the event handlers into the actions instead of
storing it in the dom
* Add title.fromElement as sugar over isvalid(gettitle())
* Not tested as it is sugar over the other 2 functions
* Fix action tests and integration tests
processLinks to be removed next
Bug: T165572
Change-Id: I4d9837706dc77ec64121ac94410c0d2da83692e4
... and update the RESTBASE_PROFILE constant to the latest "stable"
profile for the endpoint.
Prior to this change the Accept header sent by the rest gateway was
application/json; charset=utf-8profile="..."
This was discovered while responding to T166605.
Change-Id: I00f277e724c561634b26c9ab10bd35332c6dba91
When there's an interaction, then the "tapped settings cog" event should
have the same properties set as the other interaction-specific events.
This was discovered while QAing T164256.
Bug: T164256
Change-Id: I4749b52656203c7e0c42ae742556ee996eee322a
This ensures all files belong to a module.
When generating documentation no globals should be present
Bug: T158236
Change-Id: I134f38620fe46db11ba94dbede739f4336e0482c
The benefit of this is if there are any problems with the
documentation they will not enter our codebase.
We do a similar thing in MobileFrontend
Bug: T158236
Change-Id: I30329dd868fe596c490f95354c3226c9cd4a2fc7
... and the previewType property as well.
Per the Popups schema [0], the "opened" action should have the
perceivedWait and previewType properties set.
Bug: T166323
Change-Id: I957d123434a6b750aff6f5279865321a08367382
Changes:
* Assign exports to exports rather than reassigning module.exports so
that JSDoc can guess inner members.
* Tidy up parameter types with JSDoc's "nullable" syntax.
Bug: T158236
Change-Id: I7261d1bb3924c9f14301490f54d7813dcffc959b
Given that interactions end up with an event logged, there shouldn't be
a reason to keep an interaction active after it's corresponding final
event has been logged. See Tbayer's state graph.
This patch removes the current interaction if an event with that token
is logged, effectively finalizing it and making it impossible for the
token to be reused from the state tree again.
Additional changes:
* Pass the logged event with the action EVENT_LOGGED so that the reducer
can determine if it needs to do anything else.
* Since the interaction is removed, when undefined, guard against
actions that use state.interaction freely. (Only allow BOOT,
LINK_PREVIEW, and EVENT_LOGGED)
Bug: T161769
Bug: T163198
Change-Id: I99fd5716dc17da32929b6e8ae4aa164f9d84c387
This fixes a bug in I8a63d82, where the pageTitleHover and
namespaceIdHover properties of EventLogging events weren't being set.
Bug: T164256
Change-Id: Ie2c2d253f6508b89d48129fd17a902e5ded7cad5
Action changes:
* Include the namespace ID in LINK_DWELL.
Reducer changes:
* Add the createEvent helper, which adds the pageTitleHover and
namespaceIdHover properties in the event.
* Create "dismissed", "dwelledButAbandoned", and "opened" events using
the createEvent helper.
Additional changes:
* Store the target page's associated mw.Title using jQuery.
* Update the eventLogging reducer's test cases so that all LINK_DWELL
representations include title and namespaceID attributes.
* Create the createStubTitle factory function, which returns a minimal
usable mw.Title stub, and use it in the actions and integration test
cases.
Bug: T164256
Change-Id: I8a63d82a65324680dff9176020a8ea97695428c4
It enables certain optimizations, see:
* https://webpack.js.org/guides/production-build/
Code is minified by uglifyjs.
Aditional changes:
* Add banner so that sources are not minified by ResourceLoader
Bug: T160061
Change-Id: I50c9148ebf2d860db42a24225bc128bfcfe56927
I6a38a261 made the eventLogging change listener count and discard
duplicate events and count duplicate tokens.
While we isolate the issue(s) that lead to duplication (reuse, likely)
of tokens, make the eventLogging change listener discard events with
duplicate tokens as well.
Bug: T161769
Bug: T163198
Change-Id: I0dbb16c37814d39d7aec35c8fb7cc7309704c550
Binding the behavior has been left out as it requires some refactoring.
Ideally, that functionality should be tested via integration tests, which
is already done.
Bug: T133022
Change-Id: If2fd472847eb3557de97c7ec9619e8831e9bda6d
Per the Popups schema [0], the "dismissed" action expects the
perceivedWait property to be set.
Happily, the time until the preview was shown is already recorded and
used to determine whether or not to create a "dismissed" or
"dwelledButAbandoned" event.
Reducer changes:
* When creating the "dismissed" event, set the perceivedWait property to
the already accumulated timeToPreviewShow.
[0] https://meta.wikimedia.org/wiki/Schema:Popups
Bug: T164256
Change-Id: I3fd253f1c2ff5fa8e24c9225060d728ffd8dfd27
Since Ieea378c9 all QUnit tests are run in Node.js and not in the
browser. Tidy up references to QUnit inside of the codebase and tooling.
Changes:
* Don't exclude src/processLinks.js in Istanbul code coverage reports.
* Don't test for window.QUnit in createSchema. We no longer run the risk
of sending beacons while running the QUnit test suite as it's no
longer run in the browser.
Bug: T160406
Change-Id: Ifb6adb84b8019dd69231b50af00bf978b708fc60
The tests were removed in Iae0a78d0b8a13353de70794b67387f2c3bab44c6.
The ultimate goal is to refactor the renderer code and make it
testable, but before doing so we need to add tests to cover the existing
code. This will give us confidence that we won’t accidentally break
anything when we refactor.
Some of the tests have been removed as the functionality covered by
those were moved to model.js in I20f29657fcf94101a71ed13c0920508db71292ce.
Bug: T133022
Change-Id: I7b20324dd5fe8a428cdd96959b65bc82d44fb515
The ultimate goal is to refactor the renderer code and make it
testable, but before doing so we need to add tests to cover the existing
code. This will give us confidence that we won’t accidentally break
anything when we refactor.
Bug: T133022
Change-Id: I3ecbfb9bb3ac9c63fdd40df502796748c62949fe
The tests were removed in Iae0a78d0b8a13353de70794b67387f2c3bab44c6.
The ultimate goal is to refactor the renderer code and make it
testable, but before doing so we need to add tests to cover the existing
code. This will give us confidence that we won’t accidentally break
anything when we refactor.
Bug: T133022
Change-Id: I897276a1a953f6be62e4c2d4a24e0f22fc6ef141
With the final goal to remove the real mw stubs, move the processLinks
tests away from test cases, and split getTitle to be tested standalone.
Supporting changes:
* Move getTitle out to it's own module
* Will be tested separately in a followup commit
* Remove global declaration of mw.popups.processLinks (not needed any more)
Bug: T160406
Change-Id: Ieebd1257a2476081c67a318d3f05dffa1d3b9bdd
The eventLogging change listener is responsible for ensuring that the
internal state of Page Previews matches its external state (that
perceived by the user and UA). It does this by logging events with
ext.eventLog.Schema#log. This makes it the perfect place to track and
discard duplicate events enqueued by the Page Previews codebase observed
in T161769.
Make the change listener track events that it's logged by storing hashes
of the dynamic parts of them in memory. If the eventLogging change
listener sees the same event more than once, then it discards it and
increments a counter in StatsD.
This behaviour should be enabled for a matter of days as we should see
whether the duplicate events are being enqueued by the Page Previews
codebase immediately.
Bug: T163198
Change-Id: I6a38a2619d777a76dd45eb7300079e1f07b07b12
The statsv change listener depended on both the analytics tracking
function and whether it should log metrics to StatsD. We can simplify
the behaviour of the change listener by passing in a function which
doesn't log metrics to StatsD if such logging is disabled.
The change listener is now more isolated from other components.
Moreover, sharing the analytics tracking function with other components
is simpler as there's no repeated code.
Bug: T163198
Change-Id: Ibf4785fa4c27c1ad4739f02410f57412f56ff481
... by running the following:
svgo --disable removeXMLProcInst --pretty --folder images/
svgo --disable removeXMLProcInst --pretty --folder resources/ext.popups.images/
Also, add an XML declaration to resources/ext.popups.images/close.svg so
that it's recognised as an SVG by libmagic. This isn't strictly an issue
because of the way the SVG is served by the ResourceLoaderImageModule RL
module but it's consistent with the other SVGs.
Change-Id: I10b2286d6577701ba3b9a8651d5165fa81b8d293
If the user dwells on a link for long enough, then the gateway makes a
request, which is allowed to complete regardless of whether or not the
response is required.
If the user abandons the link but the request completes before the
abandon completes - currently, ABANDON_END_DELAY is 300 ms - then the
preview will be rendered temporarily.
Fix this by not rendering the preview if the user has started to abandon
the link.
Bug: T163350
Change-Id: I154dde4e3ccaed3d11cb023c85c44451fc0ad957
* Merge mwe-popups-icon with mwe-popups-settings-icon
* Remove PNG - now generated by the ResourceLoader module
* Adjust popup footer paddings/widths and store them in variables
* RTL and LTR compatible
Bug: T133956
Change-Id: I14ccd7b6731e9ec49f9959411fd17f7c9fdf43be
When the user dwells on a link and there's enough room to display a
preview above it, then the preview should rest atop the link rather than
above the mouse.
Bug: T161366
Change-Id: Ia7266f6e5c272817581bdbcb3710429b266556e4
If the user CmdOrCtrl+Clicks on a link, then the link will remain
focussed. If a preview is shown, clicks another element on the page, and
then there'll be no token to include in ABANDON_* with.
Bug: T162924
Change-Id: Ie2237aa55ea9a11070498b66c73b8bf1898d8d44
I09d8776 introduced a bug in the eventLogging reducer where reducing
LINK_CLICK would remove any accumulated interaction state but not close
the interaction.
Update the associated tests so that they correctly test the reduction of
this action.
Bug: T162924
Change-Id: Ia03e719c228ee96f279c1fa89252dc6b6371a8e9
... the interaction.
Following on from Iccba3c4c, LINK_CLICK shouldn't be considered the end
of an interaction because the link or preview can still be abandoned by
the user. Unlike ABANDON_END and LINK_DWELL, therefore, LINK_CLICK
musn't destroy the interaction but indicate that no more events should
be enqueued for the interaction.
More concretely, if the user has clicked the link or the preview, then
a "dwelledButAbandoned" or "dismissed" event shouldn't be logged.
Changes:
* Distinguish between "finalizing" and "closing" an interaction, where
the latter is the current behavior of ABANDON_END, LINK_DWELL, and
LINK_CLICK, in the eventLogging reducer and associated tests.
* If the interaction is finalized, then either the "dwelledButAbandoned"
or "dismissed" events shouldn't be logged.
Bug: T162924
Change-Id: I09d8776da992053f89a77508e29a7cde3cfeeac6
As noted in T160406, the only QUnit tests that requires a running
MediaWiki instance is the test for mw.popups.processLinks. The function
itself is isolated from the rest of the codebase.
Now, as noted in T162876#3182198, during boot the
ext.eventLogging.Schema module is loaded asynchronously with
mw.loader.using. Since boot is unconditional and happens ASAP this
happens when the tests are loaded and run.
In the short term this can be avoided by not making the tests depend on
the entire codebase. The long term solution is laid out in T160406.
Supporting changes:
* Bundle assets with webpack@2.4.1.
Bug: T162876
Change-Id: If1ee1853ba7a9b2a66b24bb93b4e6062b92b0dba
... in the eventLogging reducer.
Like ABANDON_END, the LINK_CLICK should be considered the end of the
interaction in the context of the EventLogging instrumentation, i.e. no
events should be logged after the user clicks the preview or the link.
See T159490#3172692 for additional context.
Bug: T159490
Change-Id: Iccba3c4c2b6121016ff7923c11b1622bc046ad6b
Like the FETCH_COMPLETE and ABANDON_END actions, the PREVIEW_SHOW action
was delayed but not conditionally reduced. As ABANDON_END is delayed,
there's a potential for a race and if ABANDON_END is reduced before
PREVIEW_SHOW, then there's no interaction to reduce the action into,
which causes an error, e.g. T159490#3165276 and T162373. Making
PREVIEW_SHOW require a token stops the error occurring in this scenario.
An alternative would be to clear the timeout created in
ext.popups.Preview#show in #hide. However, this would be inconsistent
with actions#fetch and actions#abandon.
Bug: T159490
Change-Id: Ibd2c0c6f45e4392582cc6ed08517f6ca1146d57a
Mirroring all other actions that are dispatched after some delay, add
the token to the PREVIEW_SHOW action.
Supporting changes:
* Pass the token to ext.popups.Preview#show so that it can be passed to
actions#previewShow.
Bug: T159490
Change-Id: I128fd56e770ed09d5d0dc55db73d11b013049c79
... instead of using the active element.
In the case of the eventLogging reducer, this fixes scenario 4.1 from
T159490#3150331, which was caused by late FETCH_COMPLETE actions being
reduced regardless of whether interaction had been finalised or a new
interaction had started.
Bug: T159490
Change-Id: If9d718625b0302ea2f75a778005643b4eef62bde
Treat these responses not as an API failure. Show a generic
preview whenever the server responds with a 404.
Bug: T160744
Change-Id: Id6169d9d4c7493f5b6511cc78fe65d448cdadc03
I6d9ff52b introduced a regression where if a logged out user clicks the
settings cog then an error is thrown.
For now, passing the event to the behavior for further processing is
required. However, it's clear that this makes the
ext.Popups.PreviewBehavior abstraction leaky.
Bug: T162324
Change-Id: I9dea04eb7435f9349e60d477f5701ec5dd655ebd
We have to be careful about the namespaces here, and then we don't
need the awful `.html( .html() )` hack. (I honestly have no idea
why that even worked for some browsers, it really shouldn't have.
The comment next to it is wrong.)
* Construct the 'svg:svg' element with the right namespace
* Set 'xlink:href' attribute on 'svg:image' element with the right namespace
Doing this correctly makes the thumbnails work in Opera 12, and it also
works as before in (at least) Chromium 57, Firefox 53, IE 11 and Edge.
I can't find out what version of Safari the other hack here was
supposed to apply to, but the code was wrong in both cases, and the
hack was mistakenly also applied to modern Chromium.
Useful resources for dealing with SVG embedded in HTML while scripting:
* http://stackoverflow.com/questions/6701705/programmatically-creating-an-svg-image-element-with-javascript
* http://jsfiddle.net/UVFBj/8/
* https://www.w3.org/Graphics/SVG/WG/wiki/Href#xlink:href
Bug: T161799
Change-Id: I30b2a1291811296424018e013bd07055ae7551d7
Require that two promises are resolved (or one is rejected) before the
FETCH_COMPLETE action is dispatched. The first promise represents the
gateway request and the second represents an arbitrarily long delay. If
the first resolves before the second, then there'll be a delay until the
second resolves; whereas if the first rejects, then there's no delay.
Change-Id: I496fe317337745c593594efff26688c46d661bf3
Mixing in the delay was introduced in If3f1a06f so that the total RTT
for an API request could be calculated. Now that the FETCH_END action is
dispatched when the gateway request ends and not when the preview model
is resolved, this additional information (state) is redundant.
Change-Id: I7e6ffe0945ffedd9425525fa7da855e729d50b77
Ideally, the preview model is resolved after 500 ms, regardless of
whether the internal gateway takes 100 or 300 ms. Given this, there's an
important distinction to be made between the "fetch" ending and it
completing and their associated actions.
Changes:
* Dispatch the FETCH_COMPLETE action when the preview model is resolved.
* Update the reducers accordingly.
Change-Id: I62c9cb0430284b76338ea80bd170cac5af4be9d0
If the user has disabled PP via the settings dialog or they aren't in
the experimental condition, then link titles shouldn't be emptied.
Because this behavior has to respond to the user enabling/disabling PP
within the same page session, change the linkTitle change listener
rather than conditionally registering it.
Bug: T161277
Change-Id: I53c1a1d3e4436e2ffe08da27da388f394f4e8817
Binding the behavior to the preview before it's shown means that the
application will respond to user interactions with the preview even
though it's transparent.
This fixes scenario 4 from T159490.
Bug: T159490
Change-Id: Ia2d06869868d07af60bdeb49d46612a4a0dc02e9
If the user abandons link A (or preview A) and immediately dwells on
link B, then log a "dismissed" or "dwelledButAbandoned" event.
In this context, "immediately" means before the ABANDON_END action is
dispatched, which, currently, is 300 ms after the ABANDON_START action
is dispatched.
Bug: T159490
Change-Id: I49f0f5dfb3e6c08844f1794fee8cb6170e93981b
Reducer changes:
* Add tests for ABANDON_END case.
* Extract the body of the ABANDON_END case into the createAbandonEvent
helper function.
Additional changes:
* totalInteractionProperty -> totalInteractionTime elsewhere in the same
file.
Bug: T159490
Change-Id: Ifff34271395f330b83cfe487e84800fe2d6f3811
Reducer changes:
* Make the eventLogging reducer queue a "tapped settings cog" event when
reducing the SETTINGS_SHOW action.
This was discovered while testing I6ce7d72b.
Bug: T159490
Change-Id: I6ce7d72b364d20c71b0e2cfed98e99f7997895e5
Like dwelling and abandoning, clicking on a preview is the same as
clicking on a link.
This fixes scenario 3 from T159490.
Bug: T159490
Change-Id: I6d9ff52b62bec93ebfcc9b6d267a46cf961852fb
For now, mirror the interaction modelling in the preview reducer in the
eventLogging reducer to handle the user either:
* Repeatedly dwelling on and abandoning a link.
* (Repeatedly) moving their mouse between the link and the preview.
This fixes scenarios 1, 2, 5, and the general issue from T159490.
Bug: T159490
Change-Id: Ia771f325e541c107348b16b47c5b786c97847652
Step 1 of T161284. Given that the median API response time (as measured
by the client) is ~115 ms [0] and the API response is artificially
delayed so that the preview starts fading in at 500 ms, we can increase
the API request delay to 150 ms without affecting the current UX while
decreasing the number of incidental HTTP requests triggered by the user
glancing their mouse over a link to another page.
[0] https://grafana.wikimedia.org/dashboard/db/reading-web-page-previews
Bug: T161284
Change-Id: I4c4a766467cdb4cd47c4231c1106c35bab67855e
When EventLogging is unavailable do not initialise the EL-related code
or try to send any events.
When EL is enabled for a brand new user we request an additional module
during boot causing an additional HTTP request. Page Previews continues
to boot normally regardless of whether the request fails.
This approach doesn't impact boot or first paint time. Once the module
is loaded once it should be cached locally, subject to the
ResourceLoader's policy. Moreover, the RL will not attempt to load the
module twice so this doesn't impact the performance of other modules.
Bug: T158999
Change-Id: I7ed7f00d52279151ece23e5aced4f2adb0f7fdc3
... container.
I19e67ae4 hide the overflowing parts of the SVG image element in IE9-11
for a number of cases but not all of them, e.g. see T139297#3089714.
Moving the overflow: hidden property to the SVG element fixes the above
case and is clearer.
Tested in IE9-11 on Windows 7, and Chrome (56.0.2924.87) on macOS Sierra
(10.12.3).
Bug: T139297
Change-Id: I9c397d7333766b40abbf14b6ade96788f5023dfa
Changes:
- remove focus events listeners as they are triggered after switching tabs
- show PagePreview on keyup event
Bug: T158631
Change-Id: I7533f896604e0e0a8ea6e900ae4f7d12b6458836
IE doesn't appear to update/redraw the SVG image element when Setting
its clip-path attribute to '', not removing it. This is problematic as
the attribute is always set to a default value (in the createThumbnail
function) before the preview is laid out.
Bug: T160237
Change-Id: I4559ff5018b8f4ecf06f6f5d9462a999d9726b94
For logging to work:
1. $wgWMEStatsdBaseUri needs to point to a valid statsv endpoint,
e.g. 'https://en.wikipedia.org/beacon/statsv'.
2. $wgPopupsStatsvSamplingRate needs to be set. Note that the codebase
already contains the EventLogging functionality, which is configured
separately. Separately configuring different logging mechanisms
allows us to avoid sampling mistakes that may arise while choosing
one or the other. For example, let's say we want to use EventLogging for
10% of users and statsv for 5%. We'd sample all users into two
buckets: 50/50. And then we'd have to set the sampling rates as
20% and 10% respectively, only because of the bucketing above. To avoid
this kind of complications, separate sampling rates are used for each
logging mechanism. This, of course, may result in situations where a
session is logged via both EventLogging and statsv.
3. The WikimediaEvents extension needs to be installed. The extension
adds the `ext.wikimediaEvents` module to the output page. The
logging functionality is delegated to this module.
Notable changes:
* The FETCH_START and FETCH_END actions are converted to a timed action.
* The experiments stub used in tests has been extracted to the stubs
file.
Logged data is visualized at
https://grafana.wikimedia.org/dashboard/db/reading-web-page-previews
Bug: T157111
Change-Id: If3f1a06f1f623e8e625b6c30a48b7f5aa9de24db
... thumbnails.
A good example of the difference in behaviour of the PageImages API is
here <T156800#3087507>. The API defers to File#transform, which scales
the largest dimension of an image, not always the width, e.g. if an
image is 1000px x 2000px and the request is for a thumbnail "of 1800px",
then the thumbnail will be 900px x 1800px.
Bug: T156800
Change-Id: I64bc2244ee78a594298d8637233b0da1083700eb
Keep all configuration-like values in one file.
Changes:
- moved EXTRACT_LENGTH to constants.js file
Change-Id: Ibe5ecfc60f2c09a30a9ecb3586bc5fb6a7365476
Webpack 1.14.0 is an old version, switch to using latest stable which
has better documentation, tree shaking, ES2015 modules and a core team
of contributors with funding. See https://webpack.js.org/
Additional changes:
* Recompile the frontend assets
Change-Id: I2c5940276e99dee104d04c6a0b83d8ab36a99df5
If the image isn't an SVG then it shouldn't be scaled past its original
dimensions. Handle the case where the requested thumbnail can't be
generated on the server as the original is too small ( < 320px,
currently [0]) in the same way.
Moreover, if the image happens to have the exact dimensions that we're
requesting (300px or 600px wide, currently [1]), then use the original
image to avoid unnecessary work/pressure on caches.
Supporting changes:
* Update the SVG_RESTBASE_RESPONSE fixture to use the extension returned
by RESTBase (and the PageImages extension) for the thumbnail:
.svg.png.
[0] https://github.com/wikimedia/restbase/blob/master/v1/summary.yaml#L121
[1] https://github.com/wikimedia/mediawiki-extensions-Popups/blob/master/src/constants.js#L2
Bug: T156800
Change-Id: I5d0aa161e80869e4b4f5425d906d1e753047a3a3
Instead of importing the modules from sources (which you should do if
you properly define NODE_ENV and use uglifyjs from webpack) import the
already compiled files on the npm packages.
This results in 5kb less on the compiled bundle.
Change-Id: I83732ea79a59b611c117ddcf4c262948c795f642
Following on from I19e67ae4, IE9-11's treatment of SVG elements that
overflow their containers means that the truncating pseudo-element and
the settings cog is occluded in a portrait-mode preview.
"Pad" the extract horizontally using a margin to force the SVG element
into the correct position.
Bug: T156800
Bug: T139297
Change-Id: I0da6af6d4cbcc69c6465b37714856e59199ae6e4
Unlike modern browsers, IE9-11 (at least) don't hide the overflowing
parts of an SVG image element. Make this explicit by adding the
overflow: hidden property to the preview's container element.
Bug: T156800
Bug: T139297
Change-Id: I19e67ae4584d90c02dc5a2dd1c8bdb5773cd2283
Now that most unit tests are run in node with common.js for loading
sources there is no reason to keep global variables around exposing all
the sources.
Only exception is the only qunit integration test processLinks.test.js
which still consumes mw.popups.processLinks, which is the only global
variable remaining in the codebase.
Changes:
* Remove references to mw.popups in code comments and reference the JS
file instead
* Remove popups.js which exposes all common.js modules as global
variables
* Export mw.popups.processLinks in processLinks.js for testing in
processLinks.test.js
Change-Id: I91066654b9282f73a80eb1ba5018bd091656c61d
We used to query the MediaWiki API to only return non-free images.
This patch allows us to query the API for images with any license.
The RESTBase end point is already returning images with any license.
Bug: T158632
Change-Id: I9ac60b6f74a7f7eb2cb160ee522c2c3a26dd0858
All the other masks use an 8px offset for the triangle. But this
specific mask used 250 - 243 = 7px offset.
Bug: T153840
Change-Id: Ib72842d18bd844ff37509cf5bf1dedd4e0f99dbc
Rather than manipulating the URL of the original image to get the URL of
the appropriately sized thumbnail, manipulate the URL of the thumbnail
image.
While we could manipulate either the thumbnail or original image URL,
there are subtle differences between the two, so manipulating the latter
makes the generateThumbnailData function as simple as possible, e.g. we
don't have to splice in "/thumb" after "/commons".
Also, ensure that the thumbnail's dimensions are scaled appropriately.
Bug: T156800
Change-Id: I6825bad14b1131dc81f23dcf120cf8ffb7d7b4f6
* Logged in users bypass bucketing. They keep working as before.
* When Page Previews is configured as a beta feature, logged out users
won't see the feature.
* If an anonymous user has enabled/disabled the feature using
the settings cog then they will see or not see the feature
depending on the value of their setting.
* The other anonymous users are bucketed. By default 90% of these
users see the feature, the other 10% don't. These numbers can be
controlled by the config variable `wgPopupsAnonsEnabledSamplingRate`.
Bug: T157700
Change-Id: I5307587b10f4849c4e82d3b064ff759121c2de67
mw.storage#get doesn't take a default value to return if the underlying
storage is disabled or the key is missing. In the former case it'll
return false and in the latter it'll return null, i.e. in neither case
will it return undefined.
Bug: T157700
Change-Id: I3f653c11468e17b64765e85ebb3b8f03e311352a
Because of the globals mw.popups.wait usage and mocking in both actions
and integration, they need to be migrated in a single step, fixing them
both to require wait.js and mock using mock-require instead of the
global variable.
Additional changes:
* Fix FIXMEs about actions.js using the global mw.popups.wait instead of
the require one.
* Fix the unit tests to use require mocking for wait.js instead of
global variable mocking in both integration and actions tests
* Change tests that use deferreds and promises to be async qunit tests
(Deferreds are asynchronous with jQuery in node, apparently they
weren't in the browser)
* Change integration.test.js to use require on Redux and ReduxThunk
Change-Id: I8e3e87b158bd11c9620e77d0a73e611cf9e82183
The "checkin" part of the Popups schema was superseded by the
ReadingDepth schema, the implementation of which is tracked by T155639.
As well as removing all checkin-related code, update the Popups schema
to the latest version - the version that doesn't have the checkin
property.
Bug: T155639
Depends-On: I762ec3fc91decf3cffa869dbd783faf62f01329a
Change-Id: If764917b6e121e1f9db980a4efa30c0f7a166197
CSSJanus v1.1.3 doesn't appear to flip the "to right" argument for the
linear-gradient CSS function. As with the position of the truncating
element in I0d50a8b5, the direction of the gradient doesn't vary with
the text direction of the current page but that of the target page.
Bug: T158858
Change-Id: I4b6fcf68bdf57722348513f12c7b19f80b2545c4
The render change listener is hard coupled to the renderer file, so in
order to migrate the test, instead of stubbing a global variable, we had
to either inject the renderer into the change listener factory as done
everywhere else, or mock the require call.
In order to do one thing per commit, we're mocking the require call
here to get the migration done, but added a FIXME to use dependency
injection instead in a future change.
Change-Id: I50f82cdc9664d34b8a8ccc1ff368f7209404159d
In index.js. Instead of using the global variable/object popups, require
things from their files so that we can remove the global variables when
we can run qunit tests with commonjs in node.
Change-Id: I85408f01eca27f97cf46b2076176fcc16c037829
This change resizes thumbnails to the appropriate width
based on the value of mw.popups.gateway.THUMBNAIL_SIZE
Tests cover
* When requested thumbnail is < than original size
* When requested thumbnail is > than original size
* When requested thumbnail is an svg and originalimage
smaller than requested thumb size
Bug: T156800
Change-Id: Ib375b97e2bc959e91de5177efc3df1f2ded54a5b
This way, src contains sources, and dist contains distribution files.
Also, add some documentation about the folders in the README and an adr.
Change-Id: Ie0b9f6475b8423b90e927633d883bde3cd5d5e4d
In order to automatically verify in CI that the built assets are up to
date with the commited sources, we need to keep the built assets in
a folder separate from the RL assets.
* Rename the compiled assets folder to industry standard `dist`
Change-Id: I8c5898f9bb29fee7164a7038b835a5f7efd33dbc
So that production code can be debugged properly. Independent source
maps files aren't loaded until the developer tools are open.
Change-Id: Ic8c3c10315d3a3be0f42505834005a3cab77d130
Until this appears in core it makes sense to package it up as
part of ext.popups resource loader module.
Version numbers from npm are pinned to exact versions to control the
upgrade path of the libraries instead of leaving it to semver on
developers machines.
Bug: T156333
Change-Id: I33368ecc3c8e911d96f846669bcd831c182749f2
boot.js is renamed to index.js and popups is now bundled
up inside popups.js
To support qunit tests, the library is still exposed as
mw.popups with a FIXME to remove later when it is no longer
necessary
Bug: T156333
Change-Id: Ieb6b4b0344af2701f99ef0fcc786d2378fd2fceb
Generate changeListeners via webpack
We now use a build folder to build the JavaScript for
our ResourceLoader modules. This is the first change
in a line of changes.
A source map is provided for debug support.
Bug: T156333
Change-Id: I771843d1ddb4b50adedc3fa53b30c2f1d8a76acb
Sometimes we make choices on the users behalf if we don't have
sufficient information, so this name is more applicable.
If beta features is disabled and the user is anon they have not
explicitly opted in.
Change-Id: I5d816f569fc54f8bf74d6e5a06246b7fa7036e06
* Create new namespace mw.popups.gateway to contain them
* Create folder resources/ext.popups/gateway/
* Split gateway{,.test}.js into gateway/{mediawiki,rest}{.test,}.js
* Extract stateless functions out of factory scope now that there are no
name collisions between the factories.
Bug: T123445
Change-Id: Ib256871c3e4cfe3f13361cb66d4e9a67e9823c7b
Instead of using constructor functions, use factory functions to
generate the gateway objects, because of:
* Consistency on the approach in the repository, no constructor
functions are used, the factory function pattern prevales.
* Real private data with closures
* No use of `this`, which is dynamic and unbound in JS and a source of
errors. In contrast, by using a factory function, the
function/methods-of-the-object are tightly bound to the internal data.
Additional changes:
* Specify more the type of createRESTBaseGateway's parameter to improve
clarity on the intent of the parameter
* From: @param {jQuery} api
* To: @param {Function} ajax function from jQuery for example
Supporting documentation:
* https://medium.com/javascript-scene/javascript-factory-functions-vs-constructor-functions-vs-classes-2f22ceddf33e
Change-Id: Iacbb098b646843a01f459b15343057e2e4851d35
Prepare to shift to a JS bundler by placing definitions at bottom
of page (these are currently assignments to mw.popups). In future
these are easily switched to module.exports line
Change-Id: Iaa5d78fee1cdb6fc572d2f1781f1d4fb59475e84
* Introduce the new config variable `PopupsAPIUseRESTBase`.
* Create a gateway interface that exposes the getPageSummary
method. Both MediaWiki API gateway and RESTBase gateway
implement this interface.
Bug: T123445
Change-Id: I71a8a848f3143fa4a0dfd4ca182ee086903110bc
Extract the getBaseData function from the eventLogging reducer so that
changes in the shape of the base data will be isolated to that function.
Additional changes:
* Clarify that the eventLogging reducer is specific to the Popups
schema. Add a TODO for revisiting the name, at least.
Bug: T156893
Change-Id: I99c102d3a1dbf77d526e5ab33e99929f351f5768
The existence of these files was causing me much confusion as I thought
they were still being used in the mpga branch.
If this is note the case they should be removed to make the repo easier
to understand.
Changes:
* Move the ext.popups.animation.less into ext.popups since that's where
its shipped.
* Remove files which are not being used.
* Since csslint now runs on ext.popups.animation.less fix the linting
issues (previously linting was not occuring)
Change-Id: Iae0a78d0b8a13353de70794b67387f2c3bab44c6
In I6bbff6a5 a preview was assigned the "extract" type if it had an
extract whereas it should've been assigned the "page" type.
Bug: T152004
Change-Id: I5e0cdc8f528647f1e20873753be29c6b85b3a384
Note this is a breaking change in the sense that it breaks the function
signature for createModel which no longer needs to be passed the last
modified time. Given this change is in the mpga branch at current time
and hasnt been exposed for public use I have deemed this okay.
The change removes tests relating to the last modified bar, removes
lines in the templates and updates existing tests and code to reflect
the new function signature for create model.
Settings icon is floated to right which will be flipped for RTL
users.
Bug: T137775
Change-Id: I7737e37d956c62f1f1c0694d7a25a58d91651f4d
* Load the close icon (previously was not loaded)
* Take opportunity to simplify selectors in setting panel and remove
unnecessary id selectors
* Correct size of header to be consistent with mediawiki ui icon
Note: there's a slight movement in the heading text's position
presumably due to inconsistiencies between the text
inside the Done/Save buttons
Bug: T154645
Change-Id: Icd978b45051c43f24ee1c9a8574a961b942082f1
The preview model is included in the FETCH_END action so, when reducing
that action, pluck the preview type from the model and add it to the
interaction state.
Change-Id: I0e51a85b4dada8f9a17ec4882e0c13b2c4382d24
Per T152004, if the preview has an empty extract, then it's a "generic"
preview; it's an "extract" preview otherwise.
Bug: T152004
Change-Id: I6bbff6a507fe3e4f03b3a44f64d875e7dbb512df
Following on from I20f29657, simplify the gateway by making it return
instances ofext.popups.PreviewModel.
Supporting changes:
* data -> model in mw.popups.renderer#render and the
create{,Empty}Preview helper functions.
Bug: T152004
Change-Id: I531f609056ae813ae5e6b1d53010d77be0799ec1
As noted in the review of I71a8a84, creating a new object to represent
the thumbnail is confusing. It's also somewhat wasteful.
Since both the MediaWiki API and RESTBase both agree on using "source"
as the key for the thumbnail's URL, it's reasonable to use it in the
gateway and renderer.
Bug: T152004
Change-Id: Ie1346d13b6e88004b817f5968448188ed83cfda4
After the gateway has made a request, it processes the page. This
processing both mangles and processes the MediaWiki API response. The
latter step contains two pieces of related business logic:
1. Deciding if a page has been modified recently.
2. Processing the extract/deciding if it's viable (see processExtract).
In order to support switching between the MediaWiki API and RESTBase and
to simplify the event logging reducer when it comes to instrumenting the
"type" of preview, extract this business logic into a model.
Bug: T152004
Change-Id: I20f29657fcf94101a71ed13c0920508db71292ce
I4c15296e introduced the wgPopupsConflictsWithNavPopupGadget client-side
config variable, an always-available flag that represents whether the
user has enabled the NavPopups gadget. This property has been missing
from the Popups instrumentation since I8a3f5835.
Changes:
* Add the value of wgPopupsConflictsWithNavPopupGadget to BOOT action
and reduce it into the base instrumentation data.
Bug: T151058
Change-Id: I09924d0cb10e96b0a846940506ebfeaa7086cd17
Ieb00709e changed the names of the page content language related
variables returned by the API from langdir and langcode to
languageDirection and languageCode respectively without updating the
renderer.
Moreover, the extract truncation mechanism introduced in I2ec0c04
couldn't handle RTL languages.
Both of these issues were found while writing a test plan for Page
Previews.
Change-Id: Ied3dbd7cf82749198e792a2f9d2241582aeff25c
Since the footer link part of the settings system - clicking the link
opens the settings modal - it seems appropriate that it should be
controlled by state managed by the settings reducer.
Bug: T146889
Change-Id: I3a8549dbf1952cd0556f663496c55de91acaf2c0
As before, we need to send the Page Previews blob that logged out users
can enable/disable previews.
Changes:
* Unconditionally add the ext.popups RL module to the output.
* Send the value of Popups\PopupsContext#isEnabledByUser to the client
as $wgPopupsIsEnabledByUser.
* Make mw.popups#isEnabled return $wgPopupsIsEnabledByUser if the user
is logged in.
Bug: T146889
Change-Id: Id2ccfaa81a327e222fff400f4a5f22f96c99ea31
The behavior of the cog varies when:
* The user is logged in/out.
* Page Previews is enabled as a beta feature.
Since the behavior of the cog doesn't vary per-preview, it can be
determined at boot time and passed to the renderer. However, in order to
keep the renderer stateless, we pass the behavior to it when a preview
is added to the DOM.
Changes:
* Add the mw.popups.createPreviewBehavior factory function, which
returns an object that encapsulates how a preview responds to the user
dwelling on it, abandoning it, and clicking on the cog.
* Invoke mw.popups.createPreviewBehavior at boot time and pass it to the
mw.popups.changeListeners.render change listener, which then passes it
to mw.popups.Preview#show.
* Make mw.popups.Preview#show responsible for binding event handlers
and configuring the cog based on the behavior.
Bug: T146889
Change-Id: I39d7d0afd7b1fe896019a1b3a82ee907bfb20edd
The SchemaPopupsSamplingRate config variable is inconsistently named and
even forwarded to the client as wgPopupsSchemaPopupsSamplingRate.
Changes:
* SchemaPopupsSamplingRate -> PopupsSchemaSamplingRate
* Forward PopupsSchemaSamplingRate to the client as
$wgPopupsSchemaSamplingRate.
Bug: T146889
Bug: T146434
Change-Id: I80d6a0abccf462e2eb0fd96af6849b5e82b49c26
Per Id1339dc2, the LINK_ABANDON_* and PREVIEW_ABANDON_* actions can (and
should) be merged, as they are always reduced in the same way.
Change-Id: I71b30d4d2774deb4efea9e565f2ccd7383bf08c1
Initially, the link element was added to LINK_ABANDON_* to determine
when an interaction should be reset. However, this wasn't enough to
protect against timing-related bugs, e.g. T154923. Now that tokens are
used to determine when interactions should be reset, the link element
can safely be removed from the LINK_ABANON_* actions.
Supporting changes:
* Update the return type of mw.popups.actions.linkAbandon in its
DocBlock.
Change-Id: Iaaed7a4846af75f9c4051d7bc761022ea5b3f6cf
I2ecf575b introduced a regression where the linkTitleChangeListener
wouldn't destroy the active link's title if it had been dwelled on
within 300 ms of the previous active link being abandoned.
The LINK_ABANDON_END action is dispatched after 300 ms and ignored if
the active link has changed.
Change-Id: If0c16afd6ca1c44f0e7eed497f62f0190005a619
... instead of using the active elements, and check also the user
dwelling flag to only act if the user is not dwelling.
Preview and link abandon end and start share now test cases, meaning it
can be collapsed into one action creator in a followup commit.
Change-Id: Id1339dc23e8f1b1b7514c769cd09f8bdadc759b4
When dwelling back to a link, previously a new LINK_DWELL action would
be sent and the reducer would reset the interaction as if it was a new
one.
This shouldn't happen, since dwelling back to the active link (from
the preview, for example) is not a new interaction, and should not
create a new interaction or hide and show the preview.
With this change, the preview reducer has the notion of new or repeat
interactions, and only resets state on new ones, and only sets
isUserDwelling when dwelling on a the link of the current interaction.
Also when the interaction is repeat, we guard on the action creator and
don't trigger the wait or the fetch request.
Change-Id: I71cde81cbfe50b6f955e562e7e5b57d0f920fdb9
... after dwelling on preview.
Currently, the asynchronous PREVIEW_ABANDON_END action wouldn't be
ignored if the user were to have dwelled on the link that the preview is
about. The action is only ignored if the user is dwelling on the
preview, i.e. if preview.isUserDwelling is truthy.
Set preview.isUserDwelling to truthy if the user is dwelling either on
the link or on the preview.
Bug: T154923
Change-Id: I8e6989790da5884992ee9dda9e4895e2e58e6694
Consider the user repeatedly dwelling on and abandoning a link. Testing
whether or not the element has changed before modifying state is not
sufficient. Fortunately, we already generate a unique token and include
it in the LINK_DWELL action for use in the eventLogging reducer - the
so-called "interaction token".
Change-Id: Iae9544055f7eccb4f7f071797eb360bc3456861a
* To speed the time the tests spend running
* To make them reliably execute and not depend on magic numbers
Additional changes:
* Use mw.now instead of Date on checkin.js
* Split big setVisibleTimeout test into several smaller ones
* Extract helpers for the tests
Change-Id: I9d3233fccf6de0997f968d096e375df996e87786
After the preview fade out animation has completed, then the preview
element should be removed from the DOM as it'll never be used again.
Supporting changes:
* Add the preview element to the DOM in ext.popups.Preview#show so that
it mirrors removing it from the DOM in #hide.
Change-Id: I6b3adc962aa13fbd46dce5f4c4f741299e43c6d9
While I1bf953b2 fixed the typo in FETCH_START_DELAY, it didn't do
anything to address the inconsistency in the time it takes to render a
preview (preview delay).
If the gateway result resolves before the target preview delay (500 ms)
is met, then delay dispatching the FETCH_END action until it is. If,
however, the gateway result resolves after the target preview delay,
then dispatch the FETCH_END action immediately.
Supporting changes:
* Expose the fetch action to ease testing it and to help tidy up the
mw.popups.actions.linkDwell tests.
Change-Id: Idf02343a0417cfbb33093a81d97ecebc5c1c7379
Use schema revision 16163887.
Add the 'checkin' action, which is accompanied by the 'checkin'
property. The action is logged at the following seconds
(Fibonacci numbers) after the page loads: 1, 2, 3, 5, 8, 13, 21,
34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765.
The `checkin` property contains the values listed above.
Bug: T147314
Change-Id: Ib9ec7bd0e60aa34a04e32222b025347f6ee31794
...with the wikimedia presets.
For automatically fixing most of the JS lint problems run
grunt eslint:fix
Some rules of stylelint were disabled given they cause problems with
existing popups code (like no id selectors for example).
Change-Id: I2153047c3ddbea50572dd329989088bb20787515
Action changes:
* Update the BOOT action to include isEnabled and update the associated
tests.
Reducer changes:
* Make the preview and eventLogging reducers handle the BOOT action's
new shape.
Bug: T152687
Change-Id: I3fa2098269a32912eda99ceb8f13887688a14c15
The Page Previews A/B test was disabled in T144490. After the changes
for that task had been deployed we discovered that the old definition
for when previews are enabled was invalid.
Previews are enabled:
* If the beta feature is enabled and the user has enabled the beta
feature.
* The user hasn't disabled previews via the settings modal.
* And soon, if the beta feature is disabled and the user hasn't disabled
previews via their user preferences (see T146889).
Changes:
* mw.popups#createExperiment -> mw.popups#isEnabled
* Make mw.popups#isEnabled act like a factory to maintain backwards
compatibility.
* Update the associated tests.
Bug: T152687
Change-Id: I713a90dfb29866b27738e7d19e8a22518a12d417
When opening the settings dialog, the form didn't represent the current
enabled status of the application. This change makes sure that every
time the form is shown, the form state represents the current
application state.
If the application is enabled, then the 'simple' (Enabled) option is
selected on the form. If it is disabled then if there's Navigation
popups, it selects 'advanced' (Advanced popups), if there are not, it
selects 'off' (Disabled).
Changes:
* Change listeners
* Set the form state every time the form is going to be shown
* Update tests
* Supporting changes
* Add settingsDialog#setEnabled which updates the DOM form based on the
enabled flag and the navpops state
* Extract isNavPopupsEnabled function in settingsDialog.js to be used in the
form creation and also when setting the form enabled state
* Add test verifying changeListeners#settings shows and sets enabled state
properly when showing the dialog more than one time
Change-Id: Ic660f48d9a78e47c09a192ab86681196d2e01d61
Changes:
* Generalized previewCount change listener to syncUserSettings
* Added state.preview.enabled to be saved on change
Change-Id: I403a490fee9c8e125175996ba30c63c232b5598b
The save action has been implemented, and it is listened to by the
canonical enabled state in the previews reducer, and by the settings
reducer to perform UI changes.
The enabled state of the application has been kept in the preview
reducer as the canonical source of truth. See supporting changes for
documentation about the decision.
Actions:
* Introduce new action SETTINGS_CHANGE with the enabled status
* Trigger that action when clicking Save in the settings dialog
Reducers:
* Listen to SETTINGS_CHANGE in the preview reducer to update enabled
status
* On the settings reducer
* Handle the SETTINGS_CHANGE action
* Add showHelp flag to determine if the help should be showing
Change listeners:
* Switch to compare past vs present changes in the implementation
* Handle showing and hiding the help
Supporting changes:
* On the rendered settings dialog:
* Change #hide to actually just hide and remove legacy if statement
* Add #toggleHelp method to show or hide the help dialog
* Add doc/adr/0003-keep-enabled-state-only-in-preview-reducer.md to
support the decision of making the saveSettings action creator return
a Redux.Thunk and keeping the enabled state just in the preview
reducer.
* Add NB to actions#saveSettings explaining and linking to the
document
Follow commits soon:
* Persist the settings change to local storage when it changes, and
unify with the preview change listener
Change-Id: I80dc5f29fbe6286f2e3e3b50d909894bc5041ccd
Reducer changes:
* Break the mw.popups.reducers.rootReducer test into @@INIT tests
for each reducer as there's shouldn't be any need to test that a
framework works as documented.
Changes:
* Move the mw.popups.reducers#preview, #eventLogging, and #settings
reducers into their own files in resources/ext.popups/reducers/.
* Make the associated tests mirror the new layout.
* Move the initialization of the mw.popups.reducers namespace into its
own file.
* Remove the mw.popups.rootReducer property in favour of a simple
private factory function per the reducer change above.
Change-Id: I94229d9ef1985f3806eec44c2e8234a5bbddc94f
Now when on a hovercard and clicking the cog, it should show the hovercards
settings menu.
Additional changes:
* Change the changeListener/settings to create and attach the DOM element
just once to the DOM
Change-Id: Id685ddcda9532528fc62b383539788f785089ef0
* Port ext.popups.desktop/ext.popups.settings.js to settingsDialog.js
* Blank tests for now. Needs Qunit integration tests.
* Transform into a factory function for future testing.
* Saving functionality is commented out, will be removed when immplemented in
the actions
* Add new incomplete action saveSettings
* Will perform the saveSettings async tasks and then trigger enabling or
disabling popups.
* Rename action settingsDialogClosed to hideSettings for consistency
Change-Id: I3936d3a4bc476de16d76025139be09f1798796c4
The changeListener is not wired up, so nothing will actually happen if you
click the link or cog. You should see redux actions flow trying to show it
though.
Change-Id: I29e629db63a4511a76c132f44f2ebf13254a4c6f
Since the user can dwell on a link, abandon it while moving to dwell on
the preview and vice versa:
* The time at which the link/preview was abandoned is recorded and can
be updated.
* The event can only be queued when the link/preview has definitely been
abandoned.
Reducer changes:
* Make the eventLogging reducer:
* Calculate the time it took to show the preview.
* Mark the interaction as finished when the user abandons the link or
the preview.
* Queue a "dismissed" event if the preview hasn't been shown or a
"dwelledButAbandoned" event if it has when the abandon has
finalized.
Bug: T152225
Change-Id: I6a254136f615484fc26e440fe5125289e74688a6
Reducer changes:
* Make the eventLogging reducer queue an "opened" event with the
requisite supporting data.
Changes:
* Update the Popups EventLogging schema to the latest revision, which
defines the "opened" action.
Bug: T152225
Change-Id: I9d67daf83815f1c08b6479497c566dfa337de4bc
Action changes:
* Mix in timing information into actions that are likely to need it:
LINK_DWELL, {LINK,PREVIEW}_ABANDON_START, LINK_CLICK, and
PREVIEW_CLICK.
* Generate and include an unique token in the LINK_CLICK action.
Reducer changes:
* Make the eventLogging reducer:
* Handle the LINK_CLICK action's new shape.
* Start (create) and maintain a model of the user interacting with a
link.
Bug: T152225
Change-Id: I671b12432ba2f7a93bf81043adb57ac30a4c38c3
Move all of the change listeners into
resources/ext.popups/changeListeners and remove the ChangeListener
suffix. Also, do the above for the associated tests.
Bug: T152225
Change-Id: I90ada465ea291d601f8f1c5c6e775148a2100319
Action changes:
* Add the PREVIEW_SHOW action.
Reducer changes:
* Increment the user's preview count in the eventLogging reducer.
Changes:
* Dispatch the PREVIEW_SHOW action when the preview has been shown.
* Add the previewCount change listener, which is responsible for
persisting the user's preview count to storage when it changes.
* Call the change listener factories individually in
#registerChangeListeners as their signatures aren't consistent.
Bug: T152225
Change-Id: Ifb493c5bff66712a25614ebb905251e43375420a
Action changes:
* Include the user's preview count in the user property of the action.
Reducer changes:
* Make the eventLogging reducer add the bucketed user's preview count to
the state tree.
Changes:
* Extract mw.popups.UserSettings#getPreviewCount and #setPreviewCount
and associated tests from the ext.popups.core module.
Bug: T152225
Change-Id: I6b7afef31311be8fede685deb536f577845cb9cf
Action changes:
* Group user-related data in the user property, rather than repeating
"isUser" and "user" prefixes.
* Include user's edit count in the user property of the action.
Reducer changes:
* Make the preview reducer handle the action's new shape.
* Make the eventLogging reducer add the bucketed user's edit count to
the state tree.
Bug: T152225
Change-Id: I8fae9e2d0f6889ffdd30bb5192513d194f791967
Action changes:
* Include whether the user is logged in/out and information about the
current page in the BOOT action.
* Add the EVENT_LOGGED action, which represents the eventLoggined change
listener logging the queued event.
Reducer changes:
* Move all tokens and timing information from the preview reducer to the
eventLogging reducer.
* Make the eventLogging reducer reset the state.
Changes:
* Add the mw.popups.createSchema function, which constructs an instance
of the mw.eventLog.Schema object that can be used to log Popups
events.
* Add the eventLogging change listener, which logs the queued event.
* Add hand-crafted, artisanal documentation.
Bug: T152225
Change-Id: I8a3f58358b211cc55417dcda7e796fe538e3d910
This reverts commit 047bccfac1.
It created merge conflicts with a bunch of patches that were days old and about to be merged. Instead of rebasing 10 patches, let's revert this one, finish merging the other ones and just rebase and fix this one. I'll re-introduce the patch in a bit.
Change-Id: Ib495755b0ab4bfa5fdf5590b1271792862a47d4b
Since the state was cloned into an empty object with $.extend, undefined
properties were being deleted from it, not actually preserving those
keys. So:
nextState({hi: undefined, ho: 1}, {ho: 2})
//> {ho: 2}
It seems like a more consistent behavior would be to not lose any own
keys on the state as we do with the updates too, so that:
nextState({hi: undefined, ho: 1}, {ho: 2})
//> {hi: undefined, ho: 2}
Which is what this commit does by not using $.extend to clone the state
and instead just manually copy the keys to the new object, even the
undefined ones.
Change-Id: If4f2a3b0d25bb5ef34cfbc1f2c9c0b5479aeee9b
Changes:
* Make the gateway handle missing pages, which are characterised by the
MediaWiki API response having both the missing property set to truthy
and the page not having any revisions.
* Add the preview-empty template and associated "mwe-popups-is-empty"
CSS class, which describe what an empty preview contains and how it
should look.
Supporting changes:
* Move the original preview template into the ext.popups module.
Bug: T151054
Change-Id: Ife75bf9c6bafdfe0a6cc3e20eea853b4ac8f951b
The preview reducer would treat the LINK_ABANDON_END and
PREVIEW_ABANDON_END actions as the PREVIEW_DWELL action. Fortunately,
this was a NOOP as they would only fall through if the preview was being
dwelled upon.
HT Joaquin Hernandez.
Change-Id: I01ff47de34ac41f1e6aa46aa5baccc2a27013f1b
Per T150814#2833030.
Changes:
* Round the preview's border.
* Adjust the shadow cast by the preview.
* Make both fade-in and -out animations last 200 ms.
Bug: T150814
Change-Id: I55c728680ebb208e7cd1bd4c99a8453ae9915f2e
It would seem that nextState should be $.extend({}, state, updates), but
as it was noted in the commit message that introduced the function
$.extend doesn't copy undefined|null values and that's why we iterate
manually over updates to copy any prop that exists over. That way we can
override properties to null|undefined in the state.
This commit expands the comment to explain so, and why OO.copy couldn't
be used.
Change-Id: If6c7119a4713328bb23c8f77042500510d515049
Instead of defaulting the config to the global mw.config when the param
is not defined, always pass it in (it is called just once in application
code), that way there's no need to test for the optional argument
behavior and the function is pure.
Change-Id: Ib1addb3060826f58dce2d6f928252ce1888a4293
Given this UI elements are going to change this comment would get
outdated really soon. Instead refer to generic interaction.
Change-Id: Icf56a864c47847bdef23985e9afd702ccb0de3b7
I59ac2e32 removed support for non-SVG capable UAs but didn't remove all
of the associated styles.
Additional changes:
* Give the inner container a name, "mwe-popups-container", so that it
can be styled with reduced specificity.
Supporting changes:
* Move the "core" styles into the ext.popups module.
Bug: T151054
Change-Id: I8deb6e76daf6f33fcb6f496129e6baf9e6793231
I14b437e7 introduced a regression where neither the preview's thumbnail
nor extract linked to the page.
Change-Id: I51793640d882aec711af8683ffbea794fad1b047
Action creator changes:
* Make the linkAbandon action creator asynchronous by splitting it into
two distinct actions, LINK_ABANDON_START and _END, the latter of which
is dispatched after a 300 ms delay.
* Introduce the previewDwell and previewAbandon action creators. The
latter is an asynchronous action that mirrors the linkAbandon action.
Reducer changes:
* Make the LINK_DWELL, LINK_ABANDON_END, and PREVIEW_ABANDON_END action
hide a preview, if one has been shown.
* Make the LINK_ABANDON_END action NOOP if:
* The user has interacted with another link, or
* The user is interacting with the preview.
Supporting changes:
* Update the mw.popups.reducers#preview and #renderer unit tests to use
an empty previous state so that the tests are more resilient to
modifications of the state tree.
Change-Id: I2ecf575bbb59bb64772f75da9b5a29c071b46a8d
I14b437e7 introduced a regression where the `moment`ed last modified
timestamp wasn't rendered.
Additional changes:
* Remove the HTML comments from the preview template.
Change-Id: I78047dd0f8acc6292e0592887e128e6046119212
If the user abandons the link after the API request delay (500 ms) but
before the it resolves (~10e3 ms), then the preview shouldn't be
rendered.
Changes:
* actions: Include the link in the FETCH_START, FETCH_FAILED, and
FETCH_END actions.
* reducers: If the active link has changed, then FETCH_END is a NOOP.
Supporting changes:
* reducers: Signal that a preview should be rendered and shown with
preview.shouldShow.
Change-Id: I3dd1c0c566ec63de515174c14845d7927583ce93
The QUnit test suite now completes in ~10e2 ms rather than ~10e3 ms.
Changes:
* Make mw.popups.actions#linkDwell to use mw.popups.wait.
* Make the tests for mw.popups.actions#linkDwell complete faster, but
still asynchronously, by stubbing mw.popups.wait.
Change-Id: I5cbef0ea69bc860f75cac27c1adea3d419c1ffad
Changes:
* Reduce the fade-in animation delay to 200 ms.
* Truncate a long extract by fading it out gradually.
* Increase the depth of the shadow cast by a preview and remove its
border.
Bug: T150814
Change-Id: I2ec0c0472bc24767bbf1f4db000cc9d690454629
Extract core rendering functionality from the mw.popups.renderer and
mw.popups.renderer.article objects.
For now, render and show the preview when the user dwells on and
abandons a link respectively.
Supporting changes:
* Add mw.popups.wait, which is sugar around window.setTimeout.
* action.response -> action.result in the FETCH_END case of the preview
reducer.
Change-Id: I14b437e7c2f55b988837fcb2800dd61a23c29a01
Supporting changes:
* Remove the preview.previousActiveLink property from the state tree as
it's unnecessary.
Change-Id: I657decf9425a7a9e2b27a798ed60b162569661d8
OO.copy doesn't copy Element instances, whereas $.extend does. However,
OO.copy does copy properties whose values are undefined or null, whereas
$.extend doesn't.
Since the state tree contains an Element instance - the
preview.activeLink property - we need to use $.extend.
Add the nextState helper function which copies the current state tree
with $.extend and mixes in all updates manually.
Change-Id: Ie8edd9fa0cc3a62a792ed60b49288f85b3ca73e9
If the user has abandoned the link or dwelled on a different link, then
don't make the API request.
Changes:
* Fix a bug in the linkDwell reducer where the activeLink was always
being set to undefined.
* Add the private fetch action creator.
* Make the linkDwell action dispatch the result of the fetch action
creator after 500ms.
Supporting changes:
* Make the link* action creators take DOM elements rather than jQuery
instances so that:
1. Testing whether the state tree has changed is an identity
comparison.
2. jQuery instances are constructed only when required.
* Document the ext.popups.Gateway type.
* Document the Redux.Store type.
* Rename the "previews-page-title" data attribute to
"page-previews-title" to avoid confusion.
Change-Id: I0b1cf3337a6f8d6450ad2bd127cb292ebb73af4f
Supporting changes:
* Add mw.popups.registerChangeListener, which registers a change
listener that will only be called when the state in the store has
changed.
Change-Id: Ibe6934058327c7f02f7d8092e74a667a5a1c600a
Changes:
* Add sessionToken and pageToken properties to the BOOT action and
update the preview reducer.
Supporting changes:
* Move the mw.popups.createActions to ext.popups/boot.js so that Redux
is used in one file and the actions can be tested in isolation more
easily.
Change-Id: Icd61bf1aeb466899e047432bf9798e2574652830
Reducers as a whole are a WIP, but this implements a baseline from which
to add more.
Changes:
* Create ext.popups.reducers to house all reducers
* Create reducers for preview and renderer state manipulation
* Create rootReducer by combining preview and renderer reducers
* Add QUnit tests for reducers
* Move action types into ext.popups.actionTypes
* Extract rootReducer from boot.js
Change-Id: I8a2296c6846cd4b0552a485e671af1d974944195
Supporting changes:
* Automatically register JavaScript files in the
tests/qunit/ext.popups/ directory.
Additional changes:
* Fix a grammatical error in the docblock for
mw.popups.createExperiment.
Change-Id: Ieb00709e353f0b960375fdaa0ca0dcdf950f2eb9
Changes:
* Make grunt:qunit run all QUnit tests in those modules whose names
being with "ext.popups".
* Add ext.popups/index.js, which initialises the mw.popups namespace.
* Add ext.popups/userSettings.js, which contains the code that deals
with interacting with the User Agent's storage.
* Add ext.popups/experiment.js, which contains the code that that
decides whether or not the user is in the experiment condition.
* Add tests for both units, converting existing tests where appropriate.
* Remove the associated code from ext.popups.core/ext.popups.core.js.
* Finally, dispatch the BOOT action against the store in
ext.popups/boot.js.
Change-Id: I697207677304bd49c7cfe1d37bb0a4af7810f387
Also, fix a bug introduced in Ib7168217 wherein the non-existent
Redux.thunk was referenced rather than ReduxThunk.default.
Change-Id: Ia4cc28b16b17442de69ed84bb8e8c88a6a9f201d
Changes:
* Create the ext.popups.lib module, which contains redux@3.6.0 and
redux-thunk@2.1.0.
* Rely on the Resource Loader's minification and mangling (?)
mechanisms.
* Create an asynchronous bootstrap script, which creates a Redux store
when the User Agent is idle.
Change-Id: Ib7168217a5673bb2a8378eb30d6aa45043c66e62
There is one reference to removeTooltips in
ext.popups.targets.desktopTarget.
I suspect this got broken in a rebase. It seems Jenkins only runs
browser tests post merge. We should fix that.
Please resubmit the patch with this amended.
This reverts commit 0ff40a6532.
Change-Id: Idd8dffb853db760ebc5866190d008f173e3025ba
Tooltips are intended to be stripped upon `mouseenter` and `focus`
events and then restored during their corresponding `mouseleave` and
`blur` events. This was broken due to duplication of event registration
and no proper deregistration.
Changes:
* Rename `mw.popups.removeTooltips` to `mw.popups.removeTooltip` to
more accurately describe its effect
* Narrow the scope of `mw.popups.removeTooltip`
* Add `mw.popups.restoreTooltip`
* Add `onLinkBlur` to `desktopTarget.js` to handle tooltip restoration
* Update qunit test to reflect changes to functions
* Minor hygiene changes regarding event namespaces
Bug: T142723
Change-Id: I776a72e436ac823fdd6b68435d9a042a91c934e5
If a user has hovercards disabled, when they right click a link
this will trigger another hover event which will reset dwellStartTime.
This means when a dwelledButAbandoned event fires shortly afterwards
the totalInteractionTime will not be correct.
To remedy this, the calculation of totalInteractionTime and
perceivedWait is moved into ext.popups.schemaPopups
Now that we can trigger events without logging to the server and
checking the total interaction time duration in two places,
let's always run the event and only check it once.
A `hover` event triggers the setting of a dwell start time
A `display` event triggers the setting of the perceivedWait value
* Both are reset on a dwelledButAbandoned.
Since dwellStartTime is controlled inside a single place, getMassageData
no longer needs to clear it.
The test "returns false if dwelledButAbandoned event without a dwellStartTime"
is removed as this should no longer be possible.
Bug: T147846
Change-Id: Ie5917ca86f0d0ab27f4cf507e6dfa2c271433c03
This adds two new events "display" and "hover" which are not
recorded back to the server. The benefits of having these events
is that they are important events in the lifecycle of a hovercard.
This allows us to debug trackSubscribe and ensure we see the behaviour
we expect to see and in a future patchset will allow us to use these
events to drive the calculation of interaction time in one single location
(Sneak preview:
https://gerrit.wikimedia.org/r/316481 to get a feel for the why.)
Change-Id: I58eefc29444179fd245cfd722093dedea19455e8
I plan to track events that will not be logged by the schema so
am dropping the 'schema' from the topic name.
This will allow us to track events that we do not log via the schema
Change-Id: I0c2762f7ed6e54fff765513b2c2d32f73fe8902f
Since DWELL_EVENTS_MIN_INTERACTION_TIME is always
zero the check will always be true so let's not make
that check unnecessarily.
We might change this in future is not a good reason
for keeping this code.
Change-Id: I23cb7ef9caeb3df470ccf109b815c4c566b0a735
Given we currently have modules defined in extension.json and in hooks
it can be really confusing understanding how the code fits together.
This change hopefully makes this a little clearer by using folder names
that are named after the resource loader modules - this is also consistent
with how we do things in our other extensions.
A images folder is added to the route so that it is clearer that the images
are not used in ResourceLoader module definitions and are only used to illustrate
the beta feature.
Change-Id: Ia650ec03e3a6d3069165441ddfa069d390be4d10
* Make it clearer what event is being bound, consistent with
onLinkClick and onLinkAbandon
* Don't create event data twice
* Refactor to reduce function size
Change-Id: Ie4368531612a2829ad191629410ba548eadb2007
Per T143051, hovercards was asked to be closed after the user clicks on
the hovercard (or the link that showed it). Closing the popup before
logging the `click` event causes `logData` to be lost. This patch logs
the data first and then clears it.
The regression was introduced in Ifd6f75c2a53d8d7b5ef9fd3f232f85b55eea24c8.
Also do not attempt closing a popup when it may not be open.
Bug: T146934
Change-Id: I02febc83036130bcea0a769114c9126cb481bafe
Per T143051, hovercards was asked to be closed after the user clicks on
the hovercard (or the link that showed it). Doing so before logging the
`dismiss` event caused `logData` to be lost. This patch logs the data first
and the clears it.
The regression was introduced in I3f3c4780cc31dc8d84cdd76df2c77fa45fbea882
Bug: T146927
Change-Id: Ie965d43b04962b2dbe2d15caa4c14bf62d1e39ea
The dismiss event is currently a side effect of closing a popup.
This should be more closely coupled with the event that causes it.
This allows the closePopup method to be called without trigging
an event which is a necessary precursor to closing popups when
navigating away from the page.
Change-Id: I3f3c4780cc31dc8d84cdd76df2c77fa45fbea882
The parameter types are incorrect and this leads to confusion
Use $ prefix for $link parameter to make clear it is a jQuery.Object
Change-Id: I3f98f3729cd06aedd791e7503233082c1402dc95
The handler for the hook `wikipage.content` was long
and undocumented but is a crucial piece of code.
To make it a little easier for people not so familiar with the code
to find this code and understand what it does I've pulled it out into
a named function.
Change-Id: I3ada53e135dea7dc6846440999b0d42285e14013
ext.popups.experiment depends on .core as it initialized the mw.popups
namespace and .core depends on .experiments for
mw.popups#getEnabledState.
By merging the experiment module into core, we can eliminate any
circular dependencies.
Changes:
* Move ext.popups.experiment.js code into ext.popups.core.js
* Remove mw.popups.experiment module and any references to it
Note: ext.popups.experiment.test.js was left in its own file for cleaner
QUnit module setups and easier removal later. I'm not entirely happy
with doing it this way, but I'm not sure changing the mw.config within
the mw.popups.core QUnit module is worth merging the files.
Bug: T146035
Change-Id: I1f024567010acaa61c1d613c6e59c998198a5976
Extract the minimum interaction time of dwelledButAbandoned events to
a unique place: mw.popups.render.DWELL_EVENTS_MIN_INTERACTION_TIME
Lower that interaction time to 0 so that all dwelledButAbandoned events
are logged.
Bug: T145379
Change-Id: Id68183367966b9f0d52e0cd570cab64671a3e87e
When hovercards are off clicking of a link will log the click
event as many times as you hovered over the link prior to clicking.
To prevent this, stop listening to old events before listening to
new ones.
Bug: T143805
Change-Id: I3e0dd2d1f259cdadfd3e02c67a137697540ca955
Improving Hovercards' settings dialog to fulfill design specification.
Also fixing HTML structure by removing invalid `radiogroup` element and
adding missing `</div>` element, fixing related QUnit test.
Changes:
* Add close icon instead of using text
* Style header as a table for alignment
* Remove redundant "OK" button and have it replace "Save" instead
* Update text of "OK" button to "Done"
* Fix description for translation of "Done" button
* Fix qunit and selenium tests
* Remove unnecessary markup and less
* Add mediawiki-ui-button and mediawiki-ui-icon dependencies
* Shrink dialog width some per design spec
* Fix dialog horizontal position calculation to remove hard-coded value
Bug: T138612
Change-Id: I7395e3438836149becdd576942bdaf6f21b4163f
The schema introduces a new field called `hovercardsSuppressedByGadget`,
which is `true` when the Navigation Popups gadget, rather than the Popups
extensions, is being used to fetch and display article summary.
Note that it may take some time before the Navigation Popups gadget is
loaded onto the page, thus actions taking place before this happens will
record the value of `hovercardsSuppressedByGadget` as `false`. This is
mostly the case with the `pageLoaded` action which almost always happens
before the gadget code is loaded.
Bug: T137203
Change-Id: Ie31deea7ae2323d6a346c67ed84fdf587ad55bd1
* Change labels in English for settings options
* Update description for enable option
* Remove description for disable option
Bug: T138233
Change-Id: Id23dcc7b7e655f7939bb2e455b8680ed5a2c6331
These errors do not have any value, they just happen when the user
cancels the current request. Removing these events will result in
less noise for data analysis.
Bug: T137059
Change-Id: Ia9d921553791d1b7be5941a98716297b74b706b2
Tested in IE9 and Safari. It seems in Safari the mixture of jQuery
and setAttributeNS causes issues.
Bug: T138430
Change-Id: I4bc63da18d008487d0c8f7b906688e4c8c809efd
Aligning Hovercards' Less to Coding Standards and also variablize
`linkpreview-title` font-family.
Change-Id: I11f2d71ce50dcd0fe47f3c5c528779e29a81cbc6
Before this change we only used to check whether NavPopups gadget is
enabled once per page load. The premise was that we could figure out
whether the gadget was enabled easily given the module name. Since
the gadget module name can be different on diffirent wikis, that
solution would not scale.
With this change we check whether the gadget is enabled before each
hover over an eligible link. We rely on the existence of the global
`window.pg` object. The existence of the object means that the
gadget is enabled, thus we do not show Hovercards.
Bug: T135628
Change-Id: Ica154dd3bfd913202a8b558ea4b10ad177176f83
This is temporary fix to get Hovercards not to show up when
Navigation Popups gadget is enabled on huwiki. The gadget module is
named 'ext.gadget.latszer' and not 'ext.gadget.Navigation_popups'.
Also check whether the global 'pg' variable is created, which means
the Navigation Popups gadget is enabled.
Bug: T135630
Change-Id: I35e1b911967200bfdfd8f44ad4e4b8dcfd844ee7
Unlike what was previously implemented, this patch does not care whether
the user hovers over another link while dismissing the popup.
The `dismissed` action is correctly logged in these cases too.
Bug: T136649
Change-Id: I68473cb8b66bae53213bce186345ca1ce436573f
According to caniuse.com SVG support is available
from IE > 8, Firefox > 3, Safari > 3.1 and Android
> 2.3. Android 3-4.3 does not support masking.
Out of all these browsers, considering market share
and ResourceLoader support, none of these browsers
are of concern to us. In IE8 for example we do not
run JavaScript for our end users. Thus we should remove
this fallback support.
Changes
* Remove createImgThumbnail method and its test
* Groups duplicate CSS groups
* Refactor createThumbnail function
** Leave a FIXME on some curious code
Change-Id: I59ac2e320b2e07815bc4136d5942016fdc1d4340
Bug: T135554
article.surveyLink, article.SIZES and currentRequest do not need to be
globally available on mw.popups.render object. They can be local variables.
Similarly openTimer and closeTimer should not be public APIs.
Changes:
* Add an abort method for purpose of aborting existing requests.
Change-Id: Ic2add9c611990bf80e8b80ab154563f6551a77ea
Use the standardised MediaWiki storage system for the simple use
case of disabling/enabling Popups. The jStorage library is 12kb
uncompressed and cannot be justified for this usage (and if it becomes
the standardised library mw.storage will begin using it)
This means that browsers with full localStorage or no localStorage
support will not be able to disable Popups. Given the current ecosystem
of the web - localStorage is widely supported - and the fact that grade
A browsers enjoy localStorage support - this is not a problem.
See https://github.com/wikimedia/mediawiki/blob/REL1_27/resources/src/startup.js#L59
Changes:
* Stop using jStorage
* Cleanup and migrate previous values in jStorage with plan for removing this
in a month.
Bug: T136241
Change-Id: I6dac2911e84d6cb20731be34add01576cf407c46
To avoid sentence parsing bugs in other languages.
We have to artificially remove the always-added ellipsis from textextracts to
mimic previous behavior, and we'll add ellipsis via CSS afterwards.
Bug: T135824
Change-Id: Idf27f2fd18f7197e588c609eeb62ac8fc80626d7
This action was sent correctly when popups are enabled, but not when
disabled. This commit sends this event also when popups are disabled
so that we are able to compare the metric with popups enabled vs disabled.
Additional changes:
* Chain events in resources/ext.popups.targets/desktopTarget.js
* Add a separate property to the list of defaults and fix formatting.
Bug: T131315
Change-Id: I426f0a1a735b8fe6b16f3d2695d9099dd0d0469b
* Remove floats;
* Get rid of margin collapsing so that the space is easy to understand;
* Fix invalid rules.
Bug: T135629
Change-Id: I3bfaf137e4d02f0dc809c809edac9b28cb4bdc3a
Changes:
* Disable the desktop target by default
* If the user is in the experiment condition, then enable the desktop
target
* Add PopupsExperiment config var, which, if set to true, causes: the
experiment config to be added to the output as config vars, as well as
the ext.popups.desktop Resource Loader module
Bug: T132604
Change-Id: Ia71ca924c3e2ec2ee0b0191ea2573fa7ff5e8a7e
As there are an unmanageable amount of synchronous checks of
mw.popups.enabled, convert mw.popups.experiment.isUserInCondition to a
synchronous method.
Follow on I4959749.
Bug: T132604
Change-Id: Ide07e62868c77bfcd78af58dcec7303a35a72157
Breaks EventLogging as the old schema is not compatible with these
new properties. We will reapply the patch later when in a better state.
My bad for merging.
This reverts commit ca20031a0e.
Change-Id: Ia961e0f99339f9045af9d0a4653599a48518cc95
Changes:
* Add the ext.popups.experiment module
* Add the mw.popups.experiment.isUserInCondition function, which
returns a promise that resolves with true if the user is in the
experimental condition, otherwise false
* If the experiment isn't configured, i.e. wgPopupsExperimentConfig is
null or undefined, then the user isn't entered into the experiment,
providing a kill switch
Bug: T132604
Change-Id: I49597494273e3862711a32e4951c8598e6c8bf59