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
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
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