Page MenuHomePhabricator

Clarify what the successor to OOUI is
Closed, ResolvedPublic

Description

Background

On https://en.wikipedia.org/wiki/Wikipedia:Village_pump_(technical)#Switcher_gadget:_please_take_a_quick_look Nardog said:

OOUI is not only a big library but one WMF is moving away from.

??? Big news to me.

But https://www.mediawiki.org/wiki/OOUI doesn't mention anything like that, nor what developers should be using.

https://www.mediawiki.org/wiki/ResourceLoader/Core_modules#mediawiki.ui still says "(deprecated in 1.29) Please use OOUI instead. See the OOUI module names. "

Documentation/wiki should be updated to indicate how developers should implement UI elements and what the status of OOUI is.

Edit (29 August 2023): another reference to this is this JS warning:

This page is using the deprecated ResourceLoader module "jquery.ui".
Please use OOUI instead.

Acceptance criteria

Event Timeline

(For the records, I once created T279421: Update Vue and Codex documentation for WMF staff and community developers about the insufficient documentation and communication at that time.) Its original title was Document and communicate status of Vue things (Codex) and future of OOUI, WVUI, etc.

(For the records, I once created T279421: Update Vue and Codex documentation for WMF staff and community developers about the insufficient documentation and communication at that time.) Its original title was Document and communicate status of Vue things (Codex) and future of OOUI, WVUI, etc.

I'm sorry to say I learned a lot of OOUI in the past 2 years and in all this time I have not once heard anyone mention "Codex". The only Codex I knew is the warez group.

Searching user JS on English Wikipedia for "cdx-dialog" confirms I'm not crazy as there are only two results, both from the same WMF developer: https://en.wikipedia.org/w/index.php?search=intitle%3Ajs+insource%3A%22cdx-dialog%22&title=Special:Search&profile=advanced&fulltext=1&ns2=1

For comparison, searching for "OO.ui.alert" returns 38 results from various (also non-WMF) users: https://en.wikipedia.org/w/index.php?search=intitle%3Ajs+insource%3A%22OO.ui.alert%22&title=Special:Search&profile=advanced&fulltext=1&ns2=1 still not a ton, but at least some script authors use it. Granted OOUI has been around much longer, but this is a disappointing result after 2 years anyway.

And frankly, the documentation seems to be lacking something. I may not be a professional, far from it, but I'm not a complete idiot either. I made EditNoticesOnMobile, LuckyRename and Factotum which may have some flaws, but at least I have some experience with this stuff. Certainly more than someone who's new to this.

I just banged my head against the wall for 2 hours looking at https://doc.wikimedia.org/codex/latest/components/demos/dialog.html and failed to create a "Hello world" dialog using Codex. And I have no idea what the problem is. I can't really cheat off of Jdlrobson's script on enwiki either because that script also confuses me.

The equivalent of:

mw.loader.using(['oojs-ui-core','oojs-ui-windows']).then(function(){
	OO.ui.alert('This is a popup');
});

I can't do it in Codex. I feel like if I could, I'd be able to figure out much more through https://doc.wikimedia.org/codex/latest/, but I'm stuck at the gate. I doubt I'd be alone in this. I'm not surprised nobody but a lone WMF-developer uses this in user scripts. And until I figure it out, if I ever do, I can't contribute to any instructions/documentation either.

Edit: apparently, T313945.

Even more relevant: T330350

The state of information about this use case is downright pathetic at the moment. Just having a completely basic "This is how a Gadget can display a Hello World dialog using Codex" example would be a dramatic improvement.

I wholeheartedly agree.

Hi @AlexisJazz – Codex is still a fairly new project. The Design Systems Team (which develops and maintains the library) is interested in supporting Gadget and Userscript authors who want to use it, but there are still some technical hurdles (many of which are listed in T313945) that need to be addressed before this is feasible.

The Codex MediaWiki page is a good starting point if you want to know more about the project in general. Codex is based on Vue.js so the MediaWiki Vue.js page may also be useful. There is also a documentation site that you've already found. The component examples in the docs site do include some MW-flavored code snippets (per T324375), and eventually we'd like to provide some on-wiki Gadget/Userscript-specific documentation when T313945 is resolved.

For now Codex is a better fit for features housed inside MediaWiki skins and extensions, or for stand-alone projects like Toolforge apps. This is part of the reason why there has not been a ton of on-wiki promotion of the new library yet. OOUI will be around for the forseeable future and there is no need to worry about migrating Gadgets or Userscripts off of it at this point.


As far as the equivalent for the code sample you posted, as I mentioned there is still more we need to do before the process is streamlined enough to recommend generally, but you can use Codex components now by doing something like the following:

mw.loader.using('@wikimedia/codex').then(function( require ){
    var Vue = require( 'vue' );
    var Codex = require( '@wikimedia/codex' );
    
    Vue.createApp( {
        data: function () {
            return {
                count: 0;
            }
        },
        template: "<cdx-button @click='onClick'>click me</cdx-button><p>You've clicked {{ count }} times.</p>",
        methods: {
            onClick: function () {
                this.count++;
            }
        }
    } )
    .component( 'cdx-button', Codex.CdxButton )  // register the component
    .mount( '#my-app' );  // assumes that you have an element with an ID of "my-app" somewhere on the page
});

As mentioned above, this is not really the ergonomic way to use Vue or Codex (single-file components are much nicer to work with, and we support them in skins and extensions). Right now the gadget syntax checker doesn't even let you write ES6, which means you can't even use template literals (something that makes defining non-trivial component templates much easier). So I would not yet recommend that people do this in Gadgets or Userscripts.

Eventually we hope to provide modern JS and Vue SFC support in gadgets - that would make things much more intuitive IMO.

Right now the gadget syntax checker doesn't even let you write ES6

A minor point, but this is not true. requiresES6 can be set in the gadget definition which allows ES6 syntax (basically by turning validation off entirely right now and leaving it to the author to ensure their software is void of error).

As far as the equivalent for the code sample you posted, as I mentioned there is still more we need to do before the process is streamlined enough to recommend generally, but you can use Codex components now by doing something like the following:

mw.loader.using('@wikimedia/codex').then(function( require ){
    var Vue = require( 'vue' );
    var Codex = require( '@wikimedia/codex' );
    
    Vue.createApp( {
        data: function () {
            return {
                count: 0;
            }
        },
        template: "<cdx-button @click='onClick'>click me</cdx-button><p>You've clicked {{ count }} times.</p>",
        methods: {
            onClick: function () {
                count++;
            }
        }
    } )
    .component( 'cdx-button', Codex.CdxButton )  // register the component
    .mount( '#my-app' );  // assumes that you have an element with an ID of "my-app" somewhere on the page
});

I tested it out in my sandbox and common.js and it doesn't quite work, I get a "count is not defined" error. :-(

If I figure it out I'll post back, but I too would greatly appreciate a working "Hello world" example for user scripts and gadgets, to start experimenting.

It looks like I forgot a this in my earlier code snippet – I've corrected the example above.

@Sophivorus I've published a working userscript example here: https://en.wikipedia.org/wiki/User:EGardner_(WMF)/codex-hello-world.js - feel free to fork this as a starting point. This example does the following:

  • Adds a custom portlet and portlet link in the main menu
  • "soft-requires" Vue and Codex from ResourceLoader, then sets up a Vue app which does the following:
    • Creates an app using Vue.createMwApp (our MediaWiki-specific wrapper around Vue.createApp()) – this automatically ensures that Dialog elements play nicely with other modal elements on the page, among other things
    • on mounted – adds an event listener to the portlet link defined above which opens the dialog; this listener is removed on unMounted
    • Defines a Vue app which contains a Dialog and some buttons that can increase/decrease a reactive count value (the use of ES6 template literals makes this much easier to read)
    • Registers the necessary Codex components

Here is the full source code for this widget:

// Add a "Codex Widgets" portlet to the main menu
mw.util.addPortlet( 'p-codex', 'Codex Widgets', '#p-interaction' );
const dialogTrigger = mw.util.addPortletLink( 'p-codex', '#', 'Example Dialog Widget', 'p-codex-dialog' );

// Define our Vue app
mw.loader.using( '@wikimedia/codex' ).then( function( require ) {
	const Vue = require( 'vue' );
	const Codex = require( '@wikimedia/codex' );
	const mountPoint = document.body.appendChild( document.createElement( 'div' ) );
	
	Vue.createMwApp( {
		data: function() {
			return {
				showDialog: false,
				count: 0,
				codexLink: 'https://doc.wikimedia.org/codex/latest/'
			};
		},
		template: `
			<cdx-dialog v-model:open="showDialog"
				title="Hello from Codex"
				close-button-label="Close"
				:default-action="defaultAction"
				@default="open = false"
			>
				<p>This Dialog component comes from Codex, the new design system for Wikimedia.</p>
				<p>To learn more about Codex, check out the documentation <a :href="codexLink" target="_blank">here.</a></p>
				<hr />
				<p>Click these buttons to update the reactive count value:</p>
				<p>Count: {{ count }}</p>
				<p>
					<cdx-button action="destructive" @click="decrement">Decrease</cdx-button>
					<cdx-button action="progressive" @click="increment">Increase</cdx-button>
				</p>
			</cdx-dialog>
		`,
		methods: {
			openDialog () {
				this.showDialog = true;
			},
			increment() {
				this.count++;
			},
			decrement() {
				this.count--;
			}
		},
		mounted() {
			dialogTrigger.addEventListener( 'click', this.openDialog );
		},
		unMounted() {
			dialogTrigger.removeEventListener( this.openDialog );
		}
	} )
	.component( 'cdx-button', Codex.CdxButton )
	.component( 'cdx-dialog', Codex.CdxDialog )
	.mount( mountPoint );
} );

Let me know if you encounter other issues – I hope this helps!

@egardner Thanks! That was VERY useful and I'm already well and away into creating my first tool with Codex.