aboutsummaryrefslogtreecommitdiffstats
path: root/resources/src/mediawiki.watchstar.widgets
Commit message (Collapse)AuthorAgeFilesLines
* resources: Use simple for-in instead of Object.keys().forEach()Timo Tijhof2024-12-221-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Once upon a time, there was an object for-in loop. Supported since ECMAScript 1.0, bravely iterating every key in the object given. ``` for (let key in myObject) { … } ``` This brave warrior has been through quite the journey. Step by step, it has escalated. * During the 2010s, we favoured $.each(Object) over for-in because of the convenient access jQuery provided to both the key and the value, instead of only the key: ``` $.each(Object, function (value, key) { … }); ``` * Then, perhaps for consistency, or brevity of code, we also changed some array `for (i = 0; i < len; i++)` loops to $.each(Array), despite the function call overhead, and lack of `this`. This rightfully validated the belief that for-loops were long and complicated, and functions were often user friendly. This was a lesson about for loops, not for-in loops. But... spoilers! <history-sidenote> Unlike the later-invented Array.forEach(), jQuery.each() supports breaking the loop by returning false! <history-sidenote> We $.each() so much, we even convinced outselves to workaround its lack of `this` by using `.bind(this)` rather than going back to a for loop. It was worth it! Can you feel the productivity? * By now, ES5 had became ubiquitous and we raised our Grade A browser support accordingly. We embraded the native Array.forEach(), over $.each(Array). Except, it couldn't break loops, of course, so we left those as $.each() or went back to for loops. And, it doesn't do objects, so we left those, too. * Then came the linter rules like `no-jquery/no-each-util` to remind ourselves to call Array.forEach instead of $.each(Array). But, alas, lint rules trigger regardless of parameter type, due to limited static analysis, so it too warns on `$.each(Object)`. This allowed the following the coincide: - this lint rule triggers, creating friction, with an incentive to change, - the mention of "Array.forEach" in that lint rule's warning still rings fresh in our minds, - ES5 is far in the rear-view mirror by now, and ES6 just became our Grade A requirement, offering a new toy: Object.keys(). - a long-overdue desire for "consistency" between array and object handling. Could we have our cake, and eat it too? Mix all that together on the stove, and you get the familiar workaround we see in many places today: ``` Object.keys(myObject).forEach(function (key) => { .. }); ``` But: * It iterates twice, and allocates an extra array. * It adds function call overhead. * It can't break. * It needs an arrow function in order to access `this`. Since Array.forEach is iterating the temporary keys array, and not the object itself, the "value" it sees are the keys of the object. So you do still need myObject[key] to access the value. Let's remind ourselves how this story began: ``` for (let key in myObject) { … } ``` What's that? A new ES7 syntax feature? Not quite. But, perhaps marketing it as such would help. It does all the same stuff as `Object.keys().forEach()`, but without the downsides: * One iteration. * No temporary array allocation. * No function call overhead. * Can break loop. * Access to `this`. * Native in ES3, ES5, and ES6. We've come full circle, and it was there all along.. since ES 1! * Meanwhile, over in the land of arrays, the Array.forEach method, whilst still so young and full of life (new in ES5), has now been thoroughly obsoleted by the native `for-of` ES6 syntax: ``` - myArray.forEach((value) => { … }); + for (let value of myArray) { … } ``` * By the way, what about that longing desire for consistency in array and object handling? Well, we have it! The for loop is cool, at last. ``` for (let value of myArray) { … } for (let key in myObject) { … } ``` Change-Id: If16d0a3682047537d0a089cddaec58b7c1dec7c8
* eslint: Manually enforce prefer-const in all remaining codeEd Sanders2024-10-051-14/+9
| | | | Change-Id: Ic9f254b55d3936f351ba9c7cc3b553544fc63a58
* eslint: Autofix var to let/constEd Sanders2024-09-121-4/+4
| | | | | | | Temporarily disable no-var & prefer-const as resulting errors need to be fixed manually. Change-Id: I6cb62a2c70a4c1fc265a00b1f18af127ac9d5029
* ESLint: Enforce prefer-arrow-callback and autofixEd Sanders2024-06-111-4/+4
| | | | Change-Id: Iddfa574e42e569ac5e2a2b098ad2f11ca80c5955
* Use ESLint "sourceType": "commonjs" for package modulesBartosz Dziewoński2024-02-131-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | When using MediaWiki package modules, `var`/`let` etc. statements at top-level define local variables rather than global variables, unlike normal MediaWiki modules (and unlike <script> code in the browser), and like CommonJS modules (although we don't follow the whole spec). We used two different ways to silence ESLint warnings about that: * { "rules": { "no-implicit-globals": "off" } } * { "env": { "commonjs": true } } Recently, a new sheriff arrived in town: * { "parserOptions": { "sourceType": "commonjs" } } I can't figure out which ESLint version introduced it, but it seems to work as of 8.54.0, which we're using currently. It's a part of a new config system they're working on, but it seems we can use it already despite using the old one. Related: https://eslint.org/blog/2022/08/new-config-system-part-2/#reimagined-language-options https://eslint.org/docs/latest/use/configure/configuration-files-new#configuring-the-javascript-source-type Change-Id: Iac2824f012cbc2c05c3c26d69d860d9b6dc45be6
* Document mediawiki.widgets.visibleLengthLimit and ↵Jon Robson2024-01-291-1/+1
| | | | | | | resources/src/mediawiki.watchstar.widgets Bug: T352308 Change-Id: I651ca7c7955daf1d8fd9adcf6ac1576c08f33816
* mw.util: introduce isInfinity to parity MW's wfIsInfinity()MusikAnimal2023-12-131-3/+4
| | | | | | | | | | | | | In our JS, especially around watchlisting, we use both 'infinity' and 'infinite' as infinity values, depending on if we're talking about the expiry dropdown (which uses 'infinite') or API interaction (which more commonly uses 'infinity'). This patch adds a stable method to test if a string is infinity so that we don't need to worry about which context the value is coming from. Bug: T353389 Change-Id: If53a88b20deb09998281794028704a64d1379f92
* Fix remaining uses of 'parent'->'super'Ed Sanders2023-11-021-1/+1
| | | | | Bug: T120821 Change-Id: Ia26c1242c69cba169d3ef600fa435b7280e1fc8a
* Synchronise watchstars and create new client hook 'wikipage.watchlistChange'Ed Sanders2021-12-201-7/+1
| | | | | | | | | | | | Deprecate the custom jQuery event added in 2012. Also introduce `watch.updatePageWatchStatus` for when 3rd parties update the watch status of the page. This method will update watchstars attached to the current title. Bug: T294254 Change-Id: I88af8585e8fc75f77ebef867d267199aeb2c6592
* Use shortcut mw.msg( ... ) instead of mw.message( ... ).text()Fomafix2021-10-071-1/+1
| | | | Change-Id: Ide51c960717676adc117823096bfc353e3a6539f
* Set watch star to half-filled when temp. watched by any interfaceBartosz Dziewoński2021-09-201-12/+0
| | | | | | | | | | | | | | | The code to set the half-filled state was only included in: * SkinTemplate.php (used when reloading the whole page, e.g. after saving in the wikitext editor) * WatchlistExpiryWidget (the special dropdown that appears inside a notification after clicking the watch star) If a page was temporarily watched by some other interface, for example while making an edit with VisualEditor, the watch star would not appear half-filled. Bug: T251348 Change-Id: Ib8ccfbbde6c5fecb4a3db0f285893bb419c82c1e
* Minor cleanup to WatchlistExpiryWidget.jsDannyS7122020-12-122-10/+16
| | | | | | Should be a no-op Change-Id: Ifcc0521db289044c40782257f85b55358803c5de
* Pass jQuery object to OO.ui.infuse()Ammar Abdulhamid2020-11-271-1/+1
| | | | | | Passing id has been deprecated Change-Id: I7868662426e587ec508b978d504d06f2eab2c64c
* Merge "WatchlistExpiryWidget: Move focus to expiry dropdown after hitting Tab"jenkins-bot2020-09-291-1/+33
|\
| * WatchlistExpiryWidget: Move focus to expiry dropdown after hitting TabMusikAnimal2020-09-281-1/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit allows the user to tab into the expiry dropdown directly from the watch link. This reason for this is becuase there is limited time to get to the popup before it is automatically dismissed. To avoid redundantly listening to keystrokes for the entire session, the listener is only valid for the initial keystroke after the popup is shown. So the workflow for someone with motor impairment might be to hit [alt-shift-w] to watch via the watch link, then hit [tab] to jump to the expiry dropdown and change the expiry as desired. Hitting [tab] again when focus is on the dropdown will move focus bcak to the watch link. This is because we can't be certain what elements follow #ca-unwatch across all skins (also scripts and gadgets could cause conflicts). Bug: T261430 Change-Id: Ia7d3f8d963810821f7915690dc62a66c7c778de3
* | Ensure dropdown label is always on its own lineSam Wilson2020-09-211-0/+1
|/ | | | | | | | | | Make the watchlist expiry dropdown in the watchstar widget always display on its own line. We were already adding a top margin to this element, so were assuming that it was a block anyway, but this isn't the case in all skins (e.g. Minerva). Bug: T262934 Change-Id: I363c57d2c595c4cdeef257777cf9a7d51d973e75
* Watchlist: Fix updateWatchLink removing css class when action=watchDayllan Maza2020-08-261-4/+6
| | | | | | | | | | | | | updateWatchLink was removing mw-watchlist-temp class when watching a page during the loading animation transforming what should be a half star spining into an empty star This patch also consolidates the logic of adding and removing mw-watchlist-temp css class into WatchlistExpiryWidget Bug: T259053 Bug: T260434 Change-Id: I1e11f0e129c53b405a2ffa8cd1e0793aec8eb126
* Translate expiry period in pop-up message for watchlist expiryhmonroy2020-07-311-2/+3
| | | | | | | | Translate the selected watchlist expiry period in the watchlist pop-up success message. Bug: T259009 Change-Id: I4d2fb01cf7a15558100077d6cc8aac2fddd01246
* Ensure cursor is pointer for watch-star notificationSam Wilson2020-07-301-0/+6
| | | | | | | Add cursor:pointer to labels in the notification toast. Bug: T258751 Change-Id: If79015db5f77d72f36944eb4097a6ed74a5de51e
* Display remaining watch period in watchstarsuecarmol2020-07-181-5/+4
| | | | | | | | | Add a new tooltip message that displays the remaining watch period of a page, if it is being watched temporarily. The tooltip message remains the same if it is being watched indefinitely. Bug: T250215 Change-Id: Ic9d1301427d477de71fb6f63fe77554a33684cd1
* Implement ability to select and save watch temporarily.hmonroy2020-07-172-4/+100
| | | | | | | | | | Add functionality that allows users to select a watch period via a drop-down in the pop-up that shows up when a user watches a page via star. Update the expiry dropdown when user is in a page edit-form. Bug: T249262 Change-Id: I9a7dfcaf84be8083e0319789dc95f2d15cee245a
* Replace toast with OOUI popup on watchlist messagesuecarmol2020-05-061-0/+25
When watching a page, a toast appears with a message to confirm it has been watched/unwatched successfully. This replaces the toast with a OOUI popup. Bug: T249259 Change-Id: Ib1b8e31ce8e6fe271cb0d6e5fbaf80bc65360da1