Page MenuHomePhabricator

Document jQuery plugins as modules
Closed, ResolvedPublicBUG REPORT

Description

If you look at https://doc.wikimedia.org/mediawiki-core/master/js/jQueryPlugins.html it makes it look like all jQuery plugins are automatically installed. We should document all the plugins to note which modules are needed to use them.

Event Timeline

apaskulin renamed this task from Document where things come from to Document which modules are needed to use jQuery plugins.Dec 20 2023, 4:49 PM

Can you add an example of a plugin and which modules are needed for it? Is there a way to get this info from the code?

Sure.
If you go to https://doc.wikimedia.org/mediawiki-core/master/js/jQueryPlugins.html and look at the cookie method you'll see the example requires loading mediawiki.cookie

Screenshot 2024-02-02 at 2.48.04 PM.png (366×1 px, 48 KB)

The documentation however doesn't assert this.

In the case of the method codePointLimit this requires the jquery.lengthLimit module, however there is no mention of this in the documentation and no example.

So this ticket is a reminder at the end to go through every method and make sure it's clear how to load each of these plugins.

Does this make sense?

I see broadly three appoaches to this.

  1. Global namespace (current experiment).
  2. Modules.
  3. Mixins.

1. Global name

This is what the first iteration toward JSDoc did, and what we have on doc.wikimedia.org today for the MediaWiki JS master branch. By tagging each method directly into a single namespace, we lose JSDoc's ability to attribute things to a source or provide any module awareness. If we keep this approach, one solution could be to ad-hoc describe things in the extended description of each method to say in prose which module it belongs to. Is there another way within this approach?

Downside:

  • Error-prone - easy to forget each time a method is documented.
  • We lack a page to list the methods that a module provides, this impedes discovery of related methods, and means people are more likely to use suboptimal combinations of code that are dependent on more modules than needed ("The docs made it seem like that's the right thing to do. They were right next to each other!").
  • We lack a space to write explainers and usage examples, about the module as a whole. This important information is harder to discover, never written, or tucked away in a non-obvious individual method, with incentive to repeate this multiple times "just in case".
  • Identifier does not reflect how to use it. There is no real jQueryPlugins class or jQueryPlugins.byteLimit method. This is hard to overcome with usage examples since the example would have to show how to load it first, and we generally don't do that in the same code snippet as calling the code (i.e. extension.json, Resources.php, Gadgets-definition, or mw.loader.using(); it varies where you declare dependencies).

2. Modules

We can declare the modules that define jQuery plugins as... modules! This solves most of the downsides I believe. It naturally shows which module to load, since it would be truthfully documented as such. It offers a natural place to explain the module as a whole. And, gives a dedicated page to each module, listing its methods.

For the use case of a reverse lookup (i.e. If you see existing code using a jQuery method, and are wondering: Which dependency provides this?), the search feature should return it correctly as the first (or only) result for a given method namem like byteLimit, regardless of how we define it.

This approach correctly describe a real module, and therefore implicitly how to load/depend on it. But, by being a module, it does (if you haven't used jQuery plugins before), imply that its methods are accessible via require(). This confusion should be limited by a usage example.

3. Mixin

This is the approach we used in JSDuck until recently. We'd define each module as a real module, or dedicated namespace (i.e. not jQueryPlugins but e.g. jQuery.plugins.lengthLimit or jQuery:jquery.lengthLimit). And then declare them as mixins to the jQuery class.

The end-result should be that you both have a dedicated page and space to explain the module, but also, like today, a single page for all jQuery methods. The latter would, ideally, tell the user where the method was inherited from. JSDuck output always shows complete class definitions, including inherited and mixed in methods, and then stated next to the method as part of the automatic layout, which module or mixin the method was originally defined in.

But... it appears this is broken in JSDoc today. There is no mention of mixed in classes, and the inherited methods are not listed on the page. Not even behind a "Show inherited" or "Show private" checkbox.

For example: https://doc.wikimedia.org/oojs-ui/master/js/OO.ui.LabelWidget.html this class:

/*
 * @extends OO.ui.Widget
 * @mixes OO.ui.mixin.LabelElement
 * @mixes OO.ui.mixin.TitledElement
 */
OO.ui.LabelWidget = 

But the page only says: "Extends: OO.ui.Widget"

It does, when you expand the constructor description, show the mixins, so maybe if those are moved, the rest will be fixed too? At least right now the methods listed at https://doc.wikimedia.org/oojs-ui/master/js/OO.ui.mixin.TitledElement.html are not inherited into LabelWidget which means people have to got through several internal mixins in order to find what LabelWidget is capable of in practice. E.g. getTitle() is not listed.

Compare this to the old JSDuck at https://doc.wikimedia.org/oojs-ui/v0.44/js/#!/api/OO.ui.LabelWidget, which shows what's mixed in, and lists the inherited methods, and where they come from.

Likewise the old JSDuck output for jQuery plugins at https://doc.wikimedia.org/mediawiki-core/REL1_41/js/#!/api/jQuery, says next to each method "Defined by", and the target is clickable showing its own page with module-level description and lists its methods.

Thanks for this detailed writeup, @Krinkle! We discussed this and think that option 2: Modules sounds like a good approach.

Change #1034585 had a related patch set uploaded (by Alex Paskulin; author: Alex Paskulin):

[mediawiki/core@master] docs: Convert jquery.lengthLimit to a module

https://gerrit.wikimedia.org/r/1034585

Change #1034597 had a related patch set uploaded (by Alex Paskulin; author: Alex Paskulin):

[mediawiki/core@master] docs: Document mediawiki.cookie as a module in JSDoc

https://gerrit.wikimedia.org/r/1034597

Test wiki created on Patch demo by APaskulin (WMF) using patch(es) linked to this task:
https://patchdemo.wmflabs.org/wikis/a7605f198c/w

Change #1034585 merged by jenkins-bot:

[mediawiki/core@master] docs: Convert jquery.lengthLimit to a module

https://gerrit.wikimedia.org/r/1034585

Change #1035818 had a related patch set uploaded (by Alex Paskulin; author: Alex Paskulin):

[mediawiki/core@master] docs: Document jQuery plugins with modules under consistent name

https://gerrit.wikimedia.org/r/1035818

Change #1035818 merged by jenkins-bot:

[mediawiki/core@master] docs: Document jQuery plugins with modules under consistent name

https://gerrit.wikimedia.org/r/1035818

Change #1034597 merged by jenkins-bot:

[mediawiki/core@master] docs: Document mediawiki.cookie as a module in JSDoc

https://gerrit.wikimedia.org/r/1034597

Change #1035827 had a related patch set uploaded (by Alex Paskulin; author: Alex Paskulin):

[mediawiki/core@master] docs: Document jQuery plugins with modules

https://gerrit.wikimedia.org/r/1035827

Change #1035827 merged by jenkins-bot:

[mediawiki/core@master] docs: Document jQuery plugins with modules

https://gerrit.wikimedia.org/r/1035827

apaskulin renamed this task from Document which modules are needed to use jQuery plugins to Document jQuery plugins as modules.Mon, Jun 3, 9:40 PM

Change #1040271 had a related patch set uploaded (by Alex Paskulin; author: Alex Paskulin):

[mediawiki/core@master] docs: Document jQuery plugins with modules

https://gerrit.wikimedia.org/r/1040271

Why are we defining SpinnerOpts and TableSorterOptions as separate types? confirmable(), highlightText(), makeCollapsible(), suggestions(), etc. also accept options through an object, but they're not defined as types. As a reader I prefer the available options to be documented inside the same section as the method that accepts them rather than having to scroll back and forth.

Why are we defining SpinnerOpts and TableSorterOptions as separate types? confirmable(), highlightText(), makeCollapsible(), suggestions(), etc. also accept options through an object, but they're not defined as types. As a reader I prefer the available options to be documented inside the same section as the method that accepts them rather than having to scroll back and forth.

Good point! As long as those types aren't used by more than one method, I think it's fine to document them inside the same section as the method.

Change #1040271 merged by jenkins-bot:

[mediawiki/core@master] docs: Document jQuery plugins with modules

https://gerrit.wikimedia.org/r/1040271

jQuery plugins are now documented as modules with clear installation instructions. For example: https://doc.wikimedia.org/mediawiki-core/master/js/module-jquery.lengthLimit.html