I decided to keep the comments because they are sooo helpful, but
tried to shorten them a bit. The biggest change is the indention with
tabs and the much more compact <path> elements. The shapes are the
exact same. I manually confirmed this for all four.
Change-Id: I2d1294c9ae7e398dcbe2d111c42848d17be8a67e
I tested this with all 16 possible combinations:
* The pointer can show up in all 4 corners.
* The popup can contain a thumbnail or not. The code for the pointer
is very different then, because the SVG masks are only relevant in
this scenario.
* The thumbnail can be tall or not.
* I even tested tall popups without a thumbnail. This is a combination
that is impossible in production scenarios.
I found 3 issues. This patch fixes 2 of them:
* The pointer is misplaced in the bottom-right corner when the popup
does not have a thumbnail (as reported in T215194).
* The pointer is misplaced in the upper-right corner when the popup
shows a thumbnail.
* The pointer in the upper-right corner is gray instead of white when
the popup is tall, but does not show a thumbnail. As this is not
relevant in production, I did not fixed it.
It seems both misplacements are because of the same reason: For some
reason, calculations are done based on the assumption the popup would
be 300px wide, but it is 320px wide.
Note I did not just added 20 everywhere, but manually alligned the
pointer triangles so they are placed exactly the same distance from
the corner as in the three other corners.
Note I did not tested this (yet) in RTL scenarios.
Bug: T215194
Change-Id: If0ca63d4d4b6e8083c7de1517fe32f49671a40e6
As well as:
* Simplify the selectGatewayType() function a bit. Or was this
intentional?
* Remove a TODO we don't need any more, at least not in this file.
Change-Id: I5528f0012cbaf8b4e88e22c7e2a8d87bf027e8f1
We discovered a bunch of possible solutions (see previous patch sets),
including replacing the `$( document )` selector with a more specific
one. That idea does not pass the linter.
Very late I realized the original selector starts with
`#mw-content-text`. This heavily limits where popups are allowed to
appear: really only in the main text content area.
We should limit reference popups to the exact same scope.
This fixes the issue described in T215195. Before, the content of the
popup was covered by the selector. Reference links *inside* the popup
would trigger another popup, which makes the current popup disappear.
Now the popup itself is not covered by these event handlers any more.
Bug: T215195
Change-Id: I142aee68abbd57ca321873855fef9209e0db0bbf
There are a few cheap checks done before this regular expression is
even needed, most notably the check for a pretty URL (without query
parameters). Since the vast majority of links processed by this parser
are pretty, I believe this optimization is worth it.
Change-Id: I730b87dc010161e8bc3f311c517293c0ad553326
This is now possible since the render functions return jQuery objects.
All this code is exclusively used in the pagePreview.js file, and
doesn't need to make the already very big renderer.js file even
bigger.
Note the tests for all renderers have always been collected in a
single file. That's why the test case does not move.
Change-Id: I0c24638751c5f0e93d2bc0f3f4bb61fa0cf50d15
To make sure that we enable the link highlighting in the Cite extension we want
to trigger the click handler on the original footnote link. This is done by
passing the id of the source element to the model and the renderer.
Bug: T213905
Change-Id: I0bd59ac326269f3c0850946851fb79b611dc2a57
This CSS class is used by the regular wikitext content area, and used
by certain CSS selectors (e.g. the external web link arrow).
The DOM structure for each popup is (intentionally) created outside
of this scope, at the end of the current page's body. This works
great for page previews because the do *not* want to share any styles
with the rest of the page. But reference previews want to do this.
In this patch I also remove the inner <span>. It was misplaced (note
the name) and resulted in block elements nested in an inline element.
Bug: T214463
Change-Id: I740e37a2ed929edf971b348fbf20e5fb12012d37
This gets rid of a little bit of code duplication, and makes the
interfaces all conform to one standard again after I05ed4b8 left them
in a little inconsistent (but properly documented) state.
Bug: T214970
Change-Id: If8407c1a48aff1cb31fc2e74b3c2b846e79a3cb5
As discussed in Iaadcce9. This does have a few benefits:
* Less code in the already pretty big render.js file.
* The code setting the target attribute is much closer to where it
belongs: in the file that specifies how the content of a reference
popup should look and behave.
* The class name "mwe-popups-extract" is not mentioned in two different
files, but in the same.
Note this changes the signature of this src/ui/templates/… file to not
return an HTML string any more, but a jQuery object. The other templates
still return strings. I believe this is fine, and not that much of a
difference anyway. The signatures don't need to be identical. And the
jQuery object still represents the exact same HTML as before.
If it helps we could change all templates/… signatures accordingly.
Could be done in this or a separate patch.
Bug: T213908
Bug: T214970
Change-Id: I05ed4b886f79c5ae748f53ab9fed965dfd217620
This solves the (I believe) only regression we introduced: A bad fake
reference like <span class="reference">[[Other article#Section]]</span>
showed a page preview for the "Other article" before we introduced
reference previews, but would have shown nothing after I9ec57e0.
Checking if the link is a self-link solves this and possibly more related
issues. Only self-links can point to a footnote on the same page.
Manually created fake-references like
<span class="reference">[[#Section]]</span> still have a chance to show
nothing in case the manually created HTML does not strictly follow the
expectations in the gateway. There is not much we can do about this. We
should not accept any arbitrary HTML but need to make at least *some*
assumptions.
Bug: T214970
Change-Id: I86e91bf45c3ae4c6a4086f7f1c7b1280fd400d17
This is mainly done to increase testabilty of this part. I am a bit
unsure if this should ( have been ) integrated in the former index.js
that's now the page.js. - See also the refactoring done before.
Bug: T214971
Change-Id: I90d0441510bc1ec0b4900a392afcbaff6a552377
This installs a series of safety nets:
* The selector [href*="#"] skips links without a fragment.
* It's still possible that a fragment exists, but is empty.
mwTitle.getFragment() checks this.
* The gateway does not assume the element exists, but checks this first.
If there is no such element, the gateway aborts the request in a way
that no error popup is shown. This is currently only possible with the
`{ textStatus: 'abort', xhr: { readyState: 0 } }` response as seen in
this patch. We might need to introduce a new, more clean way to silently
quit a fetchPreviewForTitle() call.
* The test for the reference gateway finally covers the scraping code.
Bug: T214970
Bug: T214971
Change-Id: I9ec57e0fbb0d21beaaa7b359c1c2bef64d2c14f5
Including tests for all situations.
I believe it is impossible or extremely hard to actually abuse any of
these places. All these data are not extracted from the current page, but
delivered either by MediaWiki's api.php or a RESTful endpoint, as
configured via $wgPopupsGateway and $wgPopupsRestGatewayEndpoint. A
possible attacker would need to write it's own endpoint (which must either
run on the same server or somehow ignore the CSRF token), and set the
value of mw.config.values.wgPopupsRestGatewayEndpoint on the client to
this endpoint – which requires just *another* attack vector to be able to
do this.
It's "the right thing"(tm) to escape all this anyway.
I found two possibly relevant security reviews of this extension, T88171
and T129177, resolved in 2015 and 2016.
Bug: T88171
Bug: T129177
Bug: T214754
Bug: T214971
Change-Id: I1d118c9ccaea434a253a772d18139b9b077118ab
This will affect all links, including [[Other page#Fragment]] for
example. But it will not have much of an effect there. The mw.Title
class is able to understand strings like "Other page#Fragment". All
old code calls title.getPrefixedDb() on the result. This will *not*
include the fragment. Only the new code will use title.getFragment().
I made sure this does not affect regular page previews, even when the
link is something like [[Other page#Fragment]].
Bug: T213415
Change-Id: I15611a44aa0477cc5e48ee4b12aae3cd981d977c
I tried hard to keep the CSS as small and robust as possible. The
icon will be align with the text by adding a negativ margin. With
that we also decided against using RTL and LTR specific icons that
are positioned at the edge of the canvas for now.
Bug: T213907
Change-Id: I98888114e1c50e249cf31e71749323bd4f69da3f
I guess both is fine: either having the default in the gateway (as it
was before), or in the renderer (as this patch proposes). I, personally,
feel better with having it closer to where it is needed. This way it's
not possible to accidentially deliver a model object with an empty title.
The renderer will catch this.
At the moment we don't know exactly how we will fetch other titles (e.g.
"Book").
This change is split from I15611a4 where it was a little misplaced.
It also includes a test for the default fallback title.
Bug: T213907
Change-Id: I8ec3ddc21a417da7f95feff7b080cbd60d5472e7
Including tests. I also changed the title to include quotes as well,
even if not critical in that case.
Bug: T214754
Change-Id: I2f92a5714f7adc229a003f9167bcc9afdbc55583
Special characters that have a meaning in one of the many different input
formats jQuery accepts must be escaped.
The real-world use-case are references like <ref name=":1"> with a colon.
But it's many more characters that need escaping. See
http://api.jquery.com/category/selectors/
Note this patch misses a test. I already uploaded I9ec57e0 to fix the
currently incomplete tests. But I can't make it work. How do I create an
element in the test environment so that jQuery finds it?
I suggest to merge this and continue working on the tests later, because
this is currently one of the most annoying issues that makes all testing
unreliable.
Bug: T214710
Change-Id: Ifb5fe896936078f799298ac803d019d9caa048c8
The need for this is more a sign for a broken specification than an
actual issue with this code. But better be sure than sorry. More
details at
https://mathiasbynens.github.io/rel-noopener/
Bug: T214776
Change-Id: Idbcfae6d146fbbe3bff730239329beeb3455e18c
Excluding tests for the renderer which keeps failing. This will be
readded in a later patch.
Bug: T213415
Bug: T213908
Change-Id: If79fa3d0a7a20f121b1ceda6e0e33ad691b1ad30
It's not exclusively about page summaries any more.
We had a few suggestions in mind:
* get, fetch, request, or issueRequest. But I feel these are all to
generic and don't describe well what the method does. As a reminder:
It expects a Title object and returns a promise, which returns a
PreviewModel object, which contains an HTML "extract".
* fetchPreview? I feel this can still mean to many things.
* fetchPreviewModel? But we don't really need to repeat that it will
return a model object.
So I went for fetchPreviewForTitle. What do you think?
Bug: T213415
Change-Id: Icb32c63cec82f72453dc1507c9f8b8d461fd4f4c
This adds support for preview popups on reference/footnotes from
the Cite extension. For that a new preview type was introduced and
integrated into the existing structures.
The essential starting points were this code comes into action are
added behind the feature flag introduced in the previous patches.
Bug: T213415
Change-Id: Ie0ccb03117bd654373d0f458b62cc52018361c67
This is split from the current draft patch Ie0ccb03. This is part of a
series of very small patches that prepare the code for new types of popups.
Bug: T213415
Change-Id: I4f4392057f6d3eff78409c8b6f49898c8be45d3e
This became an issue after the patch Ifa56d41 (part of T206323) removed
some hidden <span> and replaced them with title="…" tags. The CSS selector
in src/index.js get's active on all <a> elements that have a title="…"
attribute. This is now the case for all references that are used one time
and have their ↑ (or ^ on the English Wikipedia) linked.
I realized this is really only an issue for these ↑ links.
The more general issue described in T198652 still holds true, but becomes
less urgent with this bugfix.
Bug: T198652
Bug: T206323
Bug: T212419
Change-Id: I9287e8692d031f9d2ba50f967520bf327ed5c42f
This is split from the current draft patch Ie0ccb03. This is part of a
series of very small patches that prepare the code for new types of popups.
Bug: T213415
Change-Id: I00d46a716c0e6ada82ffc0034a7dd5582363c657
Copy learnings from MobileFrontend's Webpack configuration. If nothing
else, the files are more consistent and easier to diff. When the change
to rename source maps is excluded, the build products are identical.
The following changes were copied:
- DRY up the output directory and source map extension as variables. For
the latter, rename the source map from ".json" to ".map.json". Without
renaming, the build products are unchanged.
- Reduce verbosity. Only report warnings and errors.
- Fail to build when an error occurs.
- Update ordering and add comments for easier reasoning and diffing with
MobileFrontend.
Bug: T212527
Change-Id: Icf11dff91358ad021932aa209c65ed8aac77d12b
Due to loosely versioned dependencies, master's resources/dist is out of
date. This won't be an issue when package-lock is supported. Rebuild the
assets as a workaround.
Change-Id: I2bb8eab5b849616f5ae96a7915f8f1a9069109a6
Replace $.noop dependency with inline empty function.
The tests relied on a single function instance to pass. A toString()
comparison of the noop function cannot be used as they differ when
coverage is enabled.
Change-Id: I641801593beb240a8f7d06e388a0e41dc8a25bc6
redux | 3.6.0 | 4.0.1
redux-thunk | 2.2.0 | 2.3.0
Upgrading these two dependencies caused the build size to increase from
from 12.2 KB to 12.4 KB (gzip) and so the bundlesize was adjusted
accordingly in our package.json.
Additionally, our linters flagged two rules that were then turned off in
.eslintrc.es5.json.
Looks like the changes in Redux were mostly cosmetic with much work
dedicated to typescript definitiions and dropping support of private
imports [1].
The changes to redux-thunk only involved changing typescript typings and
should not affect us. [2]
The upgrade was tested locally and did not appear to break anything.
[1] https://github.com/reduxjs/redux/issues/1342#issue-130452197
[2] https://github.com/reduxjs/redux-thunk/releases/tag/v2.3.0
Bug: T209314
Change-Id: I35284793ca0c72914d9b9b2e7c28dd407bafd4d8
webpack | 4.1.1 | 4.27.1
webpack-cli | 2.0.12 | 3.1.2
The upgrade of webpack modified our build files and included these
side effects:
* Our linter flagged the usage of bitwise operators in the build files
so I turned that off in our build file lint config (.eslintrc.es5.json)
* Our build file's size increased slightly from 12.1 KB to 12.13 KB
(gzip) so the package.json's bundlesize was updated accordingly.
No deleterious effects were noticed to popups running locally, but the
jump in webpack version included these notable changes:
* Switch from uglify-es to terser minimizer [1]
[1] https://github.com/webpack/webpack/releases/tag/v4.26.0
The upgrade for webpack-cli was a major version jump, but the params
that we pass to it in our package.json file appear to work as before.
Bug: T209314
Change-Id: I1403f2c4d354cf54554a740f8c23176bf80fd3c6
FETCH_COMPLETE_TARGET_DELAY is used to introduce an artificial delay to
HTTP requests as needed. However, FETCH_START_DELAY is always accounted
for so it makes sense to define FETCH_COMPLETE_TARGET_DELAY with it. The
docs are updated to draw the distinction between total delay and API
response delay.
Change-Id: I4cddc89b8090d54db0dd85f270441cab17c54993
Currently the Popups schema is disabled but if we were to re-enable
it, the page tokens would now be consistent with the ReadingDepth
schema
The getToken function is kept to allow generation of the
pageInteractionToken's relating to a link interaction, for which
there is no centralised API.
Additional changes:
* I've updated various tests to use the central mw.user stub to make
clearer where tokens come from.
Bug: T203013
Change-Id: If746bea5aeed2b4c192a9b8a02feb1fe06480633
diffs now correctly output errors. This will pick up changes to
index.js and index.js.json that have not been committed
--exit-code is passed to ensure that if there are changes then an
error is thrown and the action is not allowed.
The dist folder became out of date as depending on what version
of node you run, the output is different.
To aid debugging, the script that checks the diff now outputs the
node version and the npm version. From now on, we will all have
to use the same node version to build assets.
This is annoying, but we will re-evaluate the approach we are taking
to build assets in T202743. We can easily work around this by all using
nvm and making consistent use of the same node version.
The assets have been rebuilt with the node version that CI uses.
Bug: T202748
Change-Id: I82aee879d4b04ca06447f95eb81230bfc24d20e9
jQuery.hidpi was deprecated by T127328
(https://gerrit.wikimedia.org/r/441614). This repo used the
"bracketedDevicePixelRatio" function from that plugin. Since browser
compatibility is good now for window.devicePixelRatio, this commit adds
a function which relies on that instead.
Bug: T198579
Change-Id: I56c234048d7741f12f35bfff5f7319c6e085c29f
This change made it impossible to open links in new tabs.
Reverting so we can try again.
This reverts commit ff5bfd1d04.
Bug: T200940
Change-Id: I10a387df8bdeb891f8d8be0eb9075f0d324646b6
Whe user moves mouse away and we abort the http request we shouldn't
count that request as a FETCH_FAILED. The reasoning behind is that
FETCH_FAILED state increments the counter.PagePreviewsApiFailure.
Our StatsD graph gets polluted with lots of aborted requests and it
becomes unsuable. It doesn't show only the failed requests.
Changes:
- introduced new state: FETCH_ABORTED
- switch to FETCH_ABORTED when browser aborts the request
Bug: T199482
Change-Id: I58047eb80f0700b78b2991daff9395ecc92553b8
Previous implementation did not pass the `result` variable
to the catch() statement. Because of that every execution that
ended with exception inside fetch() statement was threated as
not a network exception and tried to present the null preview.
Changes:
- properly handle data returned by rejected fetch promise
- chaged the big if (result && result....) into something easier
to read
- pass Error object instead of 'http' string
- Restbase can return exception, it doesn't have to handle the 404
errors by itself, it's already taken care in the catch() logic
- fixed unit tests to reflect new logic in restbase gateway
Bug: T199482
Change-Id: Ibb30fc58248623d9ad4c5388a5b2ff9b387e01de
Instead of mixing window.mediaWiki / mediaWiki and window.jQuery /
jQuery references, always refer to globals which exist whether code is
executed in browser or headless Node.js environments.
find src tests -iname \*.js|
xargs -rd\\n sed -ri 's%window.(mediaWiki|jQuery)%\1%gi'
Change-Id: I21d0a602dcbd2bc6774934bee6c487e443270fe0
Changes:
- added acceptLanguage as a config option passed to
both mwApi and restbaseApi, by default code will use
the language defined in `wgContentLanguage` config
variable. The `wgContentLanguage` is always defined
(see ResourceLoaderStartUpModule::getConfigSettings())
so there is no need for checking the variable existence.
The new logic was tested both on MediaWiki API and Restbase API
Bug: T198619
Change-Id: I1cb31f1999fd674a8b870b2b5effb92ed3dfaa1f
Whenever an HTTP request sequence is started, i.e. wait for the fetch
start time, issue a network request, and return the result, abort the
process if the results are known to no longer be needed. This occurs
when a user has dwelt upon one link and then abandoned it either during
the fetch start wait time or during the fetch network request itself.
This change is accomplished by preserving the pending promises in two
actions, LINK_DWELL and FETCH_START, and whenever the ABANDON_START
action is issued, it now aborts any previously pending XHR-like promise,
called a "AbortPromise" which is just a thenable with an abort() method.
There is a similar concept in Core:
ecc812f06e/resources/src/mediawiki.api/index.js.
Aborting pending requests has big implications for client and server
logging as requests are quickly canceled, especially on slower
connections. These differences can be observed on the network tab of
DevTools and the log in Redux DevTools.
Consider, for instance, the scenario of dwelling upon and quickly
abandoning a single link prior to this patch:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_END STATSV_LOGGED ABANDON_END EVENT_LOGGED FETCH_COMPLETE
And after this patch when the fetch timer is canceled (prior to an
actual network request):
BOOT EVENT_LOGGED LINK_DWELL ABANDON_START ABANDON_END EVENT_LOGGED
In the above sequence, FETCH_* and STATSV_LOGGED actions never occur.
And after this patch when the network request itself is canceled:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_FAILED STATSV_LOGGED FETCH_COMPLETE ABANDON_END EVENT_LOGGED
FETCH_FAILED occurs intentionally, STATSV_LOGGED and FETCH_COMPLETE
still happen even though the fetch didn't complete successfully, and
FETCH_END doesn't.
Additionally, since less data is transmitted, it's possible that the
timing and success rate of logging will improve on low bandwidth
connections.
Also, this patch tries to revise the JSDocs where possible to support
type checking and fix a call to the missing assert.fail() function in
changeListener.test.js.
Bug: T197700
Change-Id: I9a73b3086fc8fb0edd897a347b5497d5362e20ef
If a thumbnail is narrow, then the extract can expand to take
the available space. It does this via JavaScript taking the difference
between the normal space for a thumbnail minus the actual space needed
to display the thumbnail.
This removes unused whitespace in both the thumbnail and extract.
Bug: T192928
Change-Id: I59e87f9160e707fbce321a567c0a68e85f6d72ec
Prevents the source_url param in virtual page-views from getting
too long and causing an error because it exceeds varnish's max-url size.
Bug: T196904
Change-Id: Idf3667c4c2ad7e0436f013c70d5ff4ebea453d7a
Make it so the entire popup area is clickable.
Update the click handler to reflect the actual parameter
it receives (an Event not an Element) and do not pass it
in the action, given it is unusedt
Bug: T192773
Change-Id: If80969f4759b1675278d11caaf5cb093ce72031c
Since we use an SVG mask, we cannot use border-left to visually
separate the page preview thumbnail from the text. We can however
make use of a polyline and programatically work out it's start and
end.
Bug: T192928
Change-Id: I0f983a80e3210b2f7e9aa197d2a632680675973e
Prevents video files and other non-image files from being rendered as
popup thumbnails. Restricts thumbnail format to either jpg, png, or gif.
Bug: T193792
Change-Id: I7a9be5d1c8396c02ebf0893c960f65644acc9d99
- Adds an extra element in popups template to contain settings icon.
- Resizes the setting icon so that the hover/active state is a square.
- Updates the settings icon SVG file.
- Modifies margin rule for icons placed near top of popup.
Bug: T193058
Change-Id: Icc16a788bba8e2f0a82a27c2b5c7be6c2cccaa90
No longer needed. We can't turn something off again for people
now they expect it to exist.
Clarified usage instructions of PopupsEventLogging to make sure
it's more scary given the implications
Bug: T173952
Change-Id: I7be005b79da498d8e7b7df8f18b60c1327636a2c
Popups is out of beta feature and this code is no longer needed.
Removing code is the happiest activity a developer can do.
Other changes:
* Remove redundant type field on extension.json
(If not set, the extension will default to the "other" section.)
* Repurpose `name` with `namemsg` and make use of existing i18n
messages
Bug: T193053
Change-Id: Iea832cd1f37b0e7df6ff95efd66e4a1ff2a9004e
I've yet to meet the bloke who knew how to take a poke without an
explanation such that they have never mispoke. This patch which renames
pokies to pointers will surely be my masterstroke.
find \
-not \( \( -name node_modules -o -name .git -o -name vendor -o -name dist -o -name package-lock.json \) -prune \) \
-type f|
xargs -rd\\n sed -ri 's%([Pp])(okey|okie)%\1ointer%g; s%([Pp])oke%\1oint%g'
Bug: T190831
Change-Id: I363e6dd49bfcdb9515cd5fab2904a58725b18720
Thumbnails are displayed as SVG image elements. The SVG itself has a
width 3px greater than necessary for landscape thumbnails specifically.
For left-to-right languages, this additional space is empty and
unnoticed. For right-to-left languages, this extra spaces shows as a gap
on one side of the thumbnail and exceeds the popup's bounds on the other
side.
This extra 3px appears to have been mistakenly applied to landscape
thumbnails when it is only applicable to portrait, for which it is
already accounted for. Remove the 3px slop.
Bug: T190831
Change-Id: I6096f416f7e102975c4753a6b093b192aa1b45d7
When the UI is RTL, show preview thumbnails on the left. Otherwise, show
them on the right.
Bug: T190831
Change-Id: Ic1fc54f6547b31908905db8cb2ec4d58f37a6538
• Instead of removing 'mwe-popups-no-image-tri' in
renderer#layoutPreview(), add more conditions to #getClasses().
The addition condition in getClasses() was:
( !hasThumbnail || isTall ) && !flippedY
The removal condition in layoutPreview() was:
flippedX && !flippedY && hasThumbnail && isTall
To combine them, the removal logic is inverted and the conjunction is
taken:
( ( !hasThumbnail || isTall ) && !flippedY ) &&
!( flippedX && !flippedY && hasThumbnail && isTall )
Push the negation inwards:
( !hasThumbnail && !flippedY || isTall && !flippedY ) &&
( !flippedX || flippedY || !hasThumbnail || !isTall )
Expand:
!hasThumbnail && !flippedY && !flippedX ||
!hasThumbnail && !flippedY && flippedY ||
!hasThumbnail && !flippedY && !hasThumbnail ||
!hasThumbnail && !flippedY && !isTall ||
isTall && !flippedY && !flippedX ||
isTall && !flippedY && flippedY ||
isTall && !flippedY && !hasThumbnail ||
isTall && !flippedY && !isTall
Eliminate always false conditions and combine redundancies:
!hasThumbnail && !flippedY && !flippedX ||
!hasThumbnail && !flippedY ||
!hasThumbnail && !flippedY && !isTall ||
isTall && !flippedY && !flippedX ||
isTall && !flippedY && !hasThumbnail
Further eliminate redundancies:
!hasThumbnail && !flippedY ||
isTall && !flippedY && !flippedX ||
isTall && !flippedY && !hasThumbnail
Factor:
!flippedY && (
!hasThumbnail || isTall && !flippedX || isTall && !hasThumbnail
)
Factor more:
!flippedY && (
!hasThumbnail || isTall && ( !flippedX || !hasThumbnail )
)
Eliminate last redundancies:
!flippedY && ( !hasThumbnail || isTall && !flippedX )
The getClasses() test is updated for the new logic.
• Move thumbnail clip path manipulation from renderer#layoutPreview() to
a new function, #setThumbnailClipPath(). The new function flips the
order of the series of if statements so that an if / else block can be
used instead which clarifies that clip-path state is exclusive. In
other words:
if ( a ) { foo.prop = 1; }
if ( b ) { foo.prop = 2; }
if ( c ) { foo.prop = 3; }
if ( d ) { foo.prop = 4; }
Can generically be refactored regardless of condition or value to:
if ( d ) { foo.prop = 4; }
else if ( c ) { foo.prop = 3; }
else if ( b ) { foo.prop = 2; }
else if ( a ) { foo.prop = 1; }
Because prop was originally overwritten which implies if / else-like
priority.
Additionally:
• The entire function call is wrapped in a hasThumbnail conditional
which previously was checked as an input in each case.
• Consolidate the last two conditions since they only differed by a
single boolean input.
• Move the setAttribute() action to the end of the function since the
conditionals just map condition to value and the action is now
identical.
• Revise pokey mask doc to use clip-path terminology. This inverts the
thinking about the mask but better matches usage.
Bug: T190831
Change-Id: Ib460c6c07fcb054f8d425d127c588bb28a1d2473
We change page_title and source_title as a last step
just before we send the event.
Doing it elsewhere is risky at the current time because:
* the non-canonical form is needed for
mwApiGateway to bold title (formatPlainTextExtract). Needing both
would require updates to the Page model.
* title is used by EventLogging (Schema:Popups)
Bug: T191471
Change-Id: I93e7343643dcd9f32a86459907eb0b7051df91aa
We already request an idle callback when loading the code in the init
module.
Doing so here seems redundant.
Bug: T191089
Change-Id: If132c3331c49a4e74be70a5486a8270a8ce380bd
...by using a delegate event handler on the document instead of waiting
in the hook for the content div.
Bug: T191089
Change-Id: I88baa12a9aad9ed5e6c1288b39089843c19cec6c
The clip-path SVG property was conditionally set in thumbnail.js and
also conditionally set or removed in renderer.js. This patch refactors
the logic to occur in a single place, renderer.js.
The refactor was made with the following considerations:
• The one condition under which thumbnail.js would set clip-path was,
given a thumbnail exists, the thumbnail was not tall and clip-path
would be set to `url(#mwe-popups-mask)`. Otherwise, thumbnail.js would
not set clip-path.
• The logic in renderer.js for setting the attribute doesn't change
since overwriting the clip-path is equivalent to not having a
preexisting value. The case for removing the attribute itself is
replaced by inverting the condition, `flippedY`, and combining it with
the thumbnail.js condition, `!isTall`. The operation is only valid for
an existing thumbnail so the `hasThumbnail` remains unchanged.
This patch also clarifies that the "flipped" classes are exclusively set
by using an if / else chain instead of reconsidering all inputs for each
condition.
Bug: T190831
Change-Id: I4062ec7068dcadecbdbc4791447ea2ed1ce2a1de
This moves the footer icon into the ResourceLoaderImage module
providing us a consistent way of serving image assets.
This means we no longer need to provide PNGs for icons
However, given mw-ui-icon-large is not large enough for the given
use case we do have to wrestle with icon styles and override them
to get the desired result. I think this is a small price to pay given
icons are now discoverable
Change-Id: I38b62c01fd930dcbfb73b95e6128885cb483f86e
We are using EventLogging to track page views not user behaviour.
This is an exception to the rule and requires special handling.
Bug: T190188
Change-Id: If096ccaf0ac884d57744ed57e2f26b51446de2d7
Comment became a bit stale. This updates it to reflect reality and
normalizes the verb forms for consistency.
Noticed as part of https://gerrit.wikimedia.org/r/c/420839/2/src/index.js#167
Additional changes:
* Merged all the const statements in L63 into one, for consistency.
Before, some were merged and some were independent.
Change-Id: I23aa824bb811f03a3630b4695e84c468bd9cd8b5
In I7395e3438836149becdd576942bdaf6f21b4163f the settings templates
were rewritten so that they no longer displayed an image.
descriptionText and images were dropped from the template but not from
the template provider. These are artifacts from relating to that patch
and are no longer used.
Change-Id: I1be7ef288d37f338e83dab3cf041e628a06608d2
Use i18n close label in the settings dialog since we have it instead of
hardcoding English. A cross is shown instead of the text so this change
may not be visible in all browsers.
Change-Id: I66284b04fe905cc8e460ea10b56c88cacd66ed28
Replace Mustache.js templates with template literals. An effort was made
to minimize additional refactoring, so feel free to ask for more but it
ain't coming in this PS.
Bug: T165036
Change-Id: I4a6a1d93a2922c3a9ef3ae93c47da17a35c644f0
- Add SVG Inline Loader for Webpack. This allows SVG files to be
imported.
- Update the Webpack and test configurations to use the new loader.
- Scope the ESLint rules down to just JavaScript files so that linting
isn't attempted on the SVG.
Bug: T165036
Change-Id: I00bccff4c3167975c19d577be6343dcaca7ddb2d
Creating a different page preview for disambiguation pages.
This patch:
- modifies the Preview model to accept a new 'type' property
- modifies the Restbase Gateway to pass the 'type' prop to the Preview model
- creates a new template to accept both generic/disambig previews
- modifies the renderer to render the new template
- generates icons for new template through resource loader
- adds new i18n strings
- modifies event-logging "preview seen" event to send new "disambiguation" previewType
- updates event logging schema version
- adds tests for Preview model and renderer for new preview type
- does way too much? yes, yes it does.
Bug: T168392
Change-Id: Idc936cc3eabbdd99a3d98f43c66b4cdbb7d24917
Instead load it via mw.loader.using
We retain the module name ext.popups as this will be present
in cached HTML, however now it will load the bulk of the code
inside ext.popups.main
Bug: T176211
Change-Id: Ibe212721807d3698dc45ef46b2dbde15ca9d2f70
Allow developers to use different endpoints for summaries
= developer happiness
This is useful for the following use cases:
* A developer wants to test against a production endpoint via
CORS
* A developer has setup an API where REST is hosted elsewhere
e.g. http://localhost:6927/en.wikipedia.org/v1/
* A user wants to create their own REST summary compatible
endpoint
* A wiki e.g. wikidata wants to use a different endpoint which is compatible
with the summary endpoint.
We are unlikely to use it ourselves on Wikimedia wikis (the
default should suffice) but this will be a powerful tool for
When not configured this will continue to work as per normal
Change-Id: I8a7e12fbc43cddbac678e0d7b81d1e877b747b22
Stripping parentheticals were designed specifically for working around
issues with content inside wikimedia wikis and error prone.
This problem for wikimedia wikis is solved by the mobile content
service.
Given we have no intentions to use the MediaWiki API for summaries.
They are not necessarily useful to third parties and it makes little
sense to maintain them (a third party can configure their own API or
use their own REST endpoint if they really do need them).
Bug: T189042
Change-Id: I2729dc9f172af0afee1c6f0cd563c556b4ae0aeb
These are now taken care of by the Mobile-Content-Service's
summary endpoint and no longer needed here!
They are actually breaking certain previews so time for these
to go!
Bug: T183833
Change-Id: Icd2a21127c2f5881943564eca4df6bed3c15e223
This change updates the schema and begins to log
additional information such as source_namespace, id
and title. This information is provided inside the
boot action.
Additional changes:
* Allow camel case in bundle artifact
Bug: T184793
Bug: T186728
Change-Id: I425ffecc018bef2958d0dfe957a40a065e3e6c56
Don't assume that thumbnail URLs contain a dimension delimiter of "px-".
Previously, thumbnail URLs always contained the width. e.g.:
https://upload.wikimedia.org/wikipedia/commons/a/aa/100px-Red_Giant_Earth_warm.jpg
However, thumbnail URLs that actually point to the original are not
sizable:
https://upload.wikimedia.org/wikipedia/commons/a/aa/Red_Giant_Earth_warm.jpg
These are provided, for example, when the thumbnail size requested is
larger than the original. There was code designed to handle this
scenario but it only applies when RESTBase and page preview thumbnail
sizes happen to be in sync. In other words, if RESTBase requests a large
thumbnail on behalf of page previews, and page previews only requested a
small thumbnail, the original may be unexpectedly provided. A
conditional is introduced in this patch to verify that "px-" is actually
detected. If it is not present, the original is used.
Bug: T187955
Change-Id: If4e29dd870aecd6d461cc8203f6576d1bb8844f2
Pageview is consistent with verbiage used by Research and Analytics
Engineering in their reports and documentation, e.g.
https://wikitech.wikimedia.org/wiki/Analytics/Pageviews.
Bug: T184793
Change-Id: I8ae085b4af85aa72f234f3db27f0cac2c4d014e5
* New action added PREVIEW_SEEN
* The action will be used to signal that a page view needs
to be recorded.
* PREVIEW_SEEN is a delayed action which is triggered
as a side-effect of the previewShow action. It is only dispatched
if the user is still previewing the same card and the page
related to the card has preview type `page`
* The pageview changelistener is added when
$wgPopupsVirtualPageViews is set to true.
* The page view changelistener listens for page views and logs
them using EventLogging when needed using
https://meta.wikimedia.org/wiki/Schema:VirtualPageView
Note:
* Currently if a user has enabled the DNT header, the
event will not be logged. There is ongoing discussion on the
ticket and fixing this will be addressed separately.
* Only title and referrer are logged in the initial version.
The task demands that "namespace" is logged but this information
is not provided by the summary endpoints we use so will need
to be added later (if indeed needed) either via a change to that
endpoint of by using JavaScript to parse the URL.
Bug: T184793
Change-Id: Id1fe34e4bdada3a41f0d888a753af366d4756590
This change fixes some issues with assertions not running, removes
unnecessary promise dances, and improves legibility and some code
patterns in the action and integration node tests mainly.
Detailed changes:
* actions.js
* Fully migrate out of jQuery 1 promises (no done/fail)
* Fix linkDwell action not returning the fetch action promise
* actions.test.js
* Simplify setupWait for the tests
* It always autoresolves immediately the wait call to ensure speedy tests
* No waitDeferreds or waitPromises array coordination, rely on action
returned promises instead
* Get rid of that = this in favor of arrow functions
* Rename generic "p" promises to meaningful names
* Add assert.expect for more solid tests (so that we don't skip assertions in
the future if we change them)
* Fix some assertions that weren't being run because of the incorrect promise
being returned (p.then, and then just returning p)
* Get rid of $.when stubbing in favor of waiting for the promise returned from
the action
* Get rid of hacky setTimeout(..., 0) to run assertions after the promises
* integration.test.js
* Get rid of wait(0) calls to hack around asynchronous actions
* Use the action returned promises instead of the waitPromises/Deferreds
* Remove unused "el" parameter being passed to this.abandon in several tests
* Remove unnecessary test helper this.abandonPreview (it was the same as
this.abandon)
* Clarify a bit the last and more complex test with some comments and variable
name changes
* Get rid of that=this in favor of arrow functions
* container.test.js
* Get rid of that=this in favor of arrow functions
* previewBehavior.test.js
* Get rid of that=this in favor of arrow functions
* Get rid of $.each in favor of .forEach
Bug: T170807
Change-Id: I06fafd92a1712f143018e2ddff24fadf1a6882b3
Returning promises from the `linkDwell` and `abandon` thunks and
removing some of the `wait` stubs in the unit test for these actions.
Also converting a fetch callback from a `.fail` to a Promise A+
compatible `.catch`.
Bug: T170807
Change-Id: I4bbf2863db090e222ba926d3bc36a99da4bdb601
- Removing the javascript positioning of the settings dialog.
- Placing the settings dialog inside the settings overlay.
- Using flexbox to center the settings dialog.
Bug: T157072
Change-Id: If8d929fe019a04ed5f96aa593779841a52f58eff
In the mediawiki gateway fetch uses mw.Api which when calling ajax
returns a promise (not a deferred).
Thus .promise() here is unnecessary and happens to work because of
jQuery promises but it is not a standard method on JS promises so it
shouldn't be used on promises, only on deferreds.
Change-Id: Iec609b90bffad8b99b3908897dfb72d7c4ed5481
Functional changes
- Show the default / error preview for all extract request failures
except those due to network circumstances (such as CORS) or no
connectivity (offline). Previously, the error preview was displayed
only for missing pages.
- FETCH_COMPLETE was previously only dispatched after FETCH_END. Now
it's also dispatched after FETCH_FAILED. The additional "fetch
complete" is not expected to impact logging. The states of success
are: START, END, COMPLETE. The new failure states are consistent with
success: START, FAILED, COMPLETE.
Testing
Errors may be stimulated in a number of ways including:
- Timeout: add a timeout field to RESTBaseGateway /
MediaWikiGateway.fetch().
http://api.jquery.com/jquery.ajax/
- Bad request: change MediaWikiGateway.fetch's action field to
`Math.random() > 0.5 ? 'query' : 'fail'` and RESTBaseGateway.fetch's
url field to
`RESTBASE_ENDPOINT + ( Math.random() > 0.5 ? encodeURIComponent( title ) : '%%%' )`.
- Desired Gateway can be configured in Gateway#createGateway().
- Note: T184534 describes a circumstance where cached previews may not
appear when offline. Disable browser caching to avoid confusion.
Bug: T183151
Bug: T184534
Change-Id: I7332284da0e0fb1ecd234a6f1e146ebd9ad8d81f
Functional changes:
- Require page URL when constructing a PreviewModel null object. These
models have valid titles and are used to display a preview when an
extract is unobtainable. When presented with an empty URL, their
linkage incorrectly pointed to the browser's current URL. Additional
tests were added to verify the fix.
- Check missing title in addition to falsy response in RESTBase gateway
and update the test assertion to check title. It isn't clear if this
can happen in the wild.
- Forbid state mutation in the conclusion of
MediaWikiGateway.getPageSummary() with a call to Deferred.promise().
This is consistent with the rest of repo including RESTBaseGateway.
http://api.jquery.com/deferred.promise/
Nonfunctional changes:
- Collapse two RESTBase gateway 404 tests into one as the scenarios and
expectations were very similar.
- Add failure HTTP status to 'MediaWiki API gateway handles API failure'
test stub HTTP response for consistency with other cases.
- Add nullity expectations to JSDocs touched and fix a couple typos
throughout.
- Make the gateway tests a little more consistent by collapsing Deferred
variable usage where appropriate.
This change is necessary to the completion of T183151 which uses the
PreviewModel null objects for additional error cases.
Bug: T183151
Change-Id: Ib77627fb9c80d8e806208bbafcfc615b130e3278
Event timestamp (as reported by `window.performance.now()`) is also sent
along with every action.
Bug: T180036
Change-Id: Ie3a648298005d51b8b4fbaa6a53e78caf50fa2d3
When bundled by ResourceLoader this can interfere with debugging
of other concatenated files.
The nomin instruction introduced in 7bd29bb058
was meant to avoid RL minifying an already
uglified bundle, but that shouldn't matter here.
Bug: T177344
Change-Id: I90829668544e7c4ff7ddfdbb90d91b88a27a69f4
.catch is only available with jQuery 3, which is only now starting to
roll out (see https://phabricator.wikimedia.org/T124742)
This patch rolls back the usage of .catch introduced in
https://gerrit.wikimedia.org/r/#/c/373327/ to use .fail, but only the
source part, given that patch introduced unit tests for this behavior
Bug: T174724
Change-Id: I6e1c342d812b35846061266bc59e493e87423fd8
We cannot serve .map files from production servers. This makes
Popups extension difficult to debug. As a simplest solution we
decided to store map files as .json files so we can easily access
js maps files.
Changes:
- changed webpack config to store map files under .json extension
Bug: T173491
Change-Id: Iaa55f75a8c5f3e8f1f169b3ac33241cc54f0413f
Number.isNaN is a new function introduced in ECMAScript 6.
MediaWiki only requires ECMAScript 5 supports from browsers.
Notably, Opera 12 does not have Number.isNaN. Instead, use
the global isNaN function (which behaves the same except for
non-numeric inputs).
Change-Id: If436cd26b21ce0336dfbc37144f6226e7b948e5e
Instead of using the non-standard old Promise implementation by relying
on .fail, migrate it to .catch.
In this specific case, where we were chaining promises with $.when, the
semantics from going from fail to catch actually change. .fail keeps the
promise in a rejected state, while .catch will change it to resolved
unless another error is thrown.
As such, when changing it to .catch, the catched error will be re-thrown
to keep the promise in a rejected state, so that $.when.then is not
executed.
Additional changes:
* Make actions.js#fetch return its promise for ease of testing.
* Test FETCH_FAILED, which was fully untested.
Bug: T173819
Change-Id: Ibd380b714586979c6e60b4c969d17f36a0796b52
Introduce PopupsAnonsExperimentalGroupSize config variable. This defines
a population size who will be subject to experimentation. If the group
size is undefined or 0 (default) and PopupsBetaFeature is false
(default value) Popups will be enabled for everyone. If it is any other
value, half that group will see page previews.
Drop the config variable PopupsSchemaSamplingRate - we will now only
EventLog when an experiment is occuring. This means we can simplify the
MWEventLogger class as shouldLog will always be truthy. Given server
side eventlogging is only used for preference changes
traffic should be low and not need sampling.
Introduce getUserBucket which determines whether a user is in a bucket
on, off or control based on the value of
PopupsAnonsExperimentalGroupSize. Add tests showing how these
buckets are calculated.
Caution:
A kill switch wgPopupsEventLogging is provided for safety.
It defaults to false. Before merging, please check if any config changes
are necessary.
Bug: T171853
Change-Id: If2a0c5fceae78262c44cb522af38a925cc5919d3
There are some cases when the preview count stored in local storage
evaluates to NaN. When this happens we should override the value
to zero, store it in localStorage, and return it.
Bug: T168371
Change-Id: Ic44b7c7b5b716f6a0859f33278d56d2d95bbfb3e
We haven't seen the PP EventLogging instrumentation produce duplicate events
for weeks.
Bug: T172106
Change-Id: I6f3d7c0cdbf23161f63259e4d20d8a710376468b
Under some unknown circumstances getPreviewCountBucket() is called
with a value that is not a -1 or a natural number. When that happens
function returns 'undefined bucket' which causes eventLogging to
fail. I wasn't able to reproduce the issue, it might be specific
to browser/os. The safest way is to return 'unknown' for any other
case.
Bug: T168371
Change-Id: I374bb629762a86ac06a18e775d3c1a14682c9f55
Instead of registering global variables in a function, make it pure
return the external interface and set it to mw.popups in the
src/index.js entry point.
Explicitly comment on index.js what is being set and why.
Bug: T171287
Change-Id: I94d467bfa7fa6e56033dd254518ad50b5dde5bfc
Changes:
- introduced js module defining mw.popups object
- introduced isEnabled() method which checks the redux store to retrieve
isEnabled status
Bug: T171287
Change-Id: I523369831e2aa8a915ed1cb001b35d13b770f9da
Why: Because they are the approved standard by TC39 and Ecma for
JavaScript modules.
Changes:
* Wrap mw-node-qunit in run.js to register babel to transpile modules
for node v6
* Change all sources in src/ to use ES modules
* Change constants.js to be able to run without
jQuery.bracketedDevicePixelRatio given ES modules are hoisted to
the top by spec so we can't patch globals before importing it
* Change all tests in tests/node-qunit/ to use ES modules
* Drop usage of mock-require given ES modules are easy to stub with
sinon
Additional changes:
* Rename tests/node-qunit/renderer.js to renderer.test.js to follow
the convention of all the other files
* Make npm run test:node run only .test.js test files so that it
doesn't run the stubs.js or run.js file.
Bug: T171951
Change-Id: I17a0b76041d5e2fd18e2d54950d9d7c0db99a941
Previously, if the browser didn't support the Beacon API, then
instrumentation/eventLogging#isEnabled would bucket the user with a
sampling rate of 0, which is equivalent to returning false. This change
simply does the latter.
Additional changes:
* Update the documented module names of the instrumentation/eventLogging
and statsv modules.
Bug: T168847
Change-Id: I7ae5c10da42ca614b5b1a6619f9555e5665344cf
We had instrumentation for over 4 weeks and duplicate events rate
was very low. We want to keep stats so we check the duplicate events
rate but there is no need to filter those.
Bug: T167365
Change-Id: I72585beb21e9db589e45eeace657ef25f432abc9
Changes:
- introduced new event 'disabled', sent from settings popup
- added unit tests for 'disabled' event handling
Bug: T167365
Change-Id: I048b38122b8843199c86fd1ed9ec2ff21767e114
In order to debug the EventLogging instrumentation in production
environments, we want to be able to bucket ourselves at will.
When the debug flag (?debug=true) is passed send all events
for given page view.
Bug: T168847
Change-Id: Id1b13b0ecaa791b4f26be4d1151bdbbe5270b64d
Changes:
- when event doesn't have linkInteractionToken do not check for
duplicated tokens
- hygiene, move event duplication logic into separate functions
for better readability
Bug: T168449
Change-Id: I3ae197567ec9f67e104af109d4f1a1c1a6769d32
Following on from I4f653bba, since the schema and statsvInstrumentation
modules are similar, let's group/rename them:
schema -> instrumentation/eventLogging
statsvInstrumentation -> instrumentation/statsv
Change-Id: Ic59e0da7d4917f6733fd090f15d3c269af863f05
Currently, the mw.eventLog.Schema class samples per pageview. However,
we expect that if a user is bucketed for a session, then all
EventLogging events logged during that session are in the sample.
Moreover, loading the class in the way that we did - asynchronously,
using mw.loader#using - introduced an issue where the eventLogging
change listener would subscribe in the next tick of the JavaScript VM's
event loop and miss the "pageLoaded" event being queued (see T167273).
Changes:
* Make the schema module follow the form of the statsvInstrumentation
module, i.e. make it expose the #isEnabled method, and add the
associated getEventLoggingTracker function.
* Update the eventLogging change listener accept the tracker returned by
getEventLoggingTracker.
* Update/fix related JSDoc documentation.
Bug: T167236
Bug: T167273
Change-Id: I4f653bbaf1bbc2c2f70327e338080e17cd3443d4
preview/model is just a module/namespace object, not a builder class or
similar.
This patch changes a couple of imports to reference some of the exposed
functions of the preview/model where required.
In a shiny future, this pattern would be:
const { createModel, createNullModel } =
require( '../preview/model' )
Bug: T165018
Change-Id: If6ad4611538ca4f24e2443c0c3ed433275e995a6
gateway/*/rest were copies of gateway/restProvider just passing
a different provider. Docs were the same, they were untested, and
looking at them they seemed like unnecessary abstraction.
This patch removes the plain vs html structure, and separates gateways
like before, by endpoint.
There is a light utility in gateway/restFormatters.js that adapts the
call from the rest gateway to use formatters.js functions. It needs
testing, that I'll add in the next patch.
The flow for creating a gateway ends up as follows:
1. index.js calls gateway/index#createGateway( mw.config )
2. createGateway chooses based on wgPopupsGateway and invokes
* mediawiki.js#createMediaWikiApiGateway or
* rest.js#createRESTBaseGateway w/ restFormatters.js#parsePlainTextResponse or
* rest.js#createRESTBaseGateway w/ restFormatters.js#parseHTMLResponse
Changes:
* Removed src/gateway/{plain,html}/rest.js
* Extracted formatter functions to src/gateway/restFormatters.js
* src/gateway/plain/mediawiki.js -> src/gateway/mediawiki.js
* tests/node-qunit/gateway/plain/mediawiki.test.js ->
tests/node-qunit/gateway/mediawiki.test.js
* gateway/restProvider{,.test}.js -> gateway/rest{,.test}.js
* Change gateway/index.js#createGateway to properly call the rest
gateways with the rest formatters
Bug: T165018
Change-Id: Ia75695dfc192aad5bc581a68882514bad6c29646
And add tests, given it is growing in complexity.
Additional changes:
* Interface ext.popups.Gateway -> Gateway in docs
Bug: T165018
Change-Id: I8a12333ad9d14d6a7fbde11afc42f607881e8ea3
... from the statsvInstrumentation module so that the bucketing logic
can be shared with other instrumentation modules.
Change-Id: I5732fa539a3911939fa85fa88c102fa8dcfa5613
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
... 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
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
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