From b0d82d49d12e1cb43cc634ac0ef872b873c97a44 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Fri, 18 Aug 2023 15:49:13 +0800 Subject: [PATCH] [docs] Update information about modal instantiation (MDL-78324) --- docs/devupdate.md | 98 ++++++++++++++++++ docs/guides/javascript/modal/index.md | 143 +++++++++++++++++++++++--- 2 files changed, 229 insertions(+), 12 deletions(-) diff --git a/docs/devupdate.md b/docs/devupdate.md index ba93608ebe..00f2345120 100644 --- a/docs/devupdate.md +++ b/docs/devupdate.md @@ -255,6 +255,104 @@ export default class MyModal extends Modal { +### Instantiation and deprecation of `core/modal_factory` + + + +Moodle 4.3 introduces a new way to instantiate modals which is significantly simpler than earlier versions. Rather than calling the `create` method on the `modal_factory`, it can now be called on the class that you are instantiating. + +In addition, a new `configure` method is introduced which allows you to override configuration options, provide your own, and more. + +Modals which are instantiated using the new method *do not* need to be registered if they are not consumed using the modal factory. + +This change will increase encapsulation and allow modals to handle common actions such as showing on creation, and removing on close much more easily. + +:::note Compatibility with Moodle 4.2 and older + +If your code is intended to work with Moodle 4.2 and older, then you must continue to use the existing `core/modal_factory`, and you must continue to register your modal. This legacy method will be maintained until Moodle 4.6. + +::: + + + + + +The legacy registration will continue to work and should be used if your plugin will be used in Moodle 4.2, or earlier. + +```js title="mod/example/amd/src/mymodal.js" +export default class MyModal extends Modal { + static TYPE = 'mod_example/myModal'; + static TEMPLATE = 'mod_example/my_modal'; + + myCustomSetter(value) { + this.value = value; + } +} +let registered = false; +if (!registered) { + ModalRegistry.register(MyModal.TYPE, MyModal, 'mod_example/my_modal'); + registered = true; +} +``` + +```js title="mod/example/amd/src/consumer.js" +import MyModal from './mymodal'; +import ModalFactory from 'core/modal_factory'; + +// ... +ModalFactory.create({ + TYPE: MyModal.TYPE, +}).then((modal) => { + modal.show(); + modal.myCustomSetter('someValue'); + + return modal; +}) +``` + + + + + + + +```js title="mod/example/amd/src/mymodal.js" +export default class MyModal extends Modal { + static TYPE = 'mod_example/myModal'; + static TEMPLATE = 'mod_example/my_modal'; + + configure(modalConfig) { + // Specify any defaults you like here. + modalConfig.show = true; + super.configure(modalConfig); + + this.myCustomSetter(modalConfig.myCustomValue); + } + + myCustomSetter(value) { + this.value = value; + } +} +``` + +```js title="mod/example/amd/src/consumer.js" +import MyModal from './mymodal'; + +// ... +MyModal.create({ + myCustomValue: 'someValue', + show: true, +}); +``` + + + + + ### Registration helper diff --git a/docs/guides/javascript/modal/index.md b/docs/guides/javascript/modal/index.md index d53dda6d01..3f2daef807 100644 --- a/docs/guides/javascript/modal/index.md +++ b/docs/guides/javascript/modal/index.md @@ -8,7 +8,7 @@ tags: -import { CodeBlock, CodeExample, InvalidExample, ValidExample, Since } from '@site/src/components'; +import { CodeBlock, CodeExample, InvalidExample, ValidExample, Since, DeprecatedSince } from '@site/src/components'; The use of modal modules provides a simplified developer experience for creating modal dialogues within Moodle. @@ -20,6 +20,36 @@ Moodle ships with several standard modal types for you to re-use including a sim ## Creating a basic modal + + +Modals can be created by calling the static `create` method on the modal type you wish to create, for example: + +```javascript title="Creating a stadard modal" +import Modal from 'core/modal'; + +export const init = async () => { + const modal = await Modal.create({ + title: 'Test title', + body: '

Example body content

', + footer: 'An example footer content', + show: true, + removeOnClose: true, + }); +} +``` + +Other standard options are described in the JS Documentation for [the MoodleConfig type](https://jsdoc.moodledev.io/master/module-core_modal.html#~MoodleConfig). + +:::note Support for earlier versions + +If you are supporting an earlier version of Moodle, then you must use the Modal Factory and register your modal. + +::: + +### Modal Factory + + + The Modal Factory can be used to instantiate a new Modal. The factory provides a `create` function, accepting some configuration which is used to create the modal instance, and an optional _trigger element_. The `create` function returns a Promise that is resolved with the created modal. The configuration is provided as an object with key/value pairs. The options are: @@ -65,7 +95,9 @@ export const init = async () => { }; ``` -### Using the 'trigger' +#### Using the 'trigger' + + Moodle Modals created using the Modal Factory support an optional _trigger_ element. Whilst this is available, it is no longer recommended and support for it will likely be removed in Moodle 4.3. @@ -93,6 +125,59 @@ A number of commonly used modals are available as standard, these include: - a Save / Cancel modal - a Cancel modal +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +:::note + +If you are developing code for use in Moodle 4.2, or earlier, then you must continue to follow the 4.2 guidelines. + +::: + +To use these modals you can call the `create` method on the relevant Modal Class. + +```javascript title="Creating a save/cancel modal" +import ModalSaveCancel from 'core/modal_save_cancel'; +import {get_string as getString} from 'core/str'; + +export const init = async () => { + const modal = await ModalSaveCancel.create({ + title: 'test title', + body: getString('confirmchange', 'mod_example'), + }); + + // ... +}; +``` + +Each type of modal may fire additional events to allow your code to handle the new functionality being offered -- for example, if you wanted to have a save/cancel modal that you did some form validation on before saving you could do something like the example below. + +```javascript title="Listening to a Save event" +import ModalSaveCancel from 'core/modal_save_cancel'; +import ModalEvents from 'core/modal_events'; +import {get_string as getString} from 'core/str'; + +export const init = async () => { + const modal = await ModalSaveCancel.create({ + title: 'test title', + body: getString('confirmchange', 'mod_example'), + }); + + modal.getRoot().on(ModalEvents.save, (e) => { + // ... + }) + + // ... +}; +``` + + + + To use these modals you can provide the `type` argument to the `ModalFactory.create` method. This argument takes a string value and values can be found for these modals in `ModalFactory.TYPES`. ```javascript title="Creating a save/cancel modal" @@ -132,6 +217,9 @@ export const init = async () => { }; ``` + + + ## Creating a custom modal type In some situations it is desirable to write a brand new modal. @@ -141,19 +229,21 @@ There are two parts to this: - a new Modal class which extends the `core/modal` class; and - a template -Creating the Modal class is as simple as extending the `core/modal` class, providing a `TYPE` property, a `TEMPLATE` property, and registering the modal with the modal factory. +:::important Custom modals in Moodle 4.2 and earlier + +Since Moodle 4.3, creating the Modal class is as simple as extending the `core/modal` class, and providing a `TYPE` property, and `TEMPLATE` property. + +For older versions of Moodle, refer to the [Moodle 4.2 documentation](/versioned_docs/version-4.2/guides/javascript/modal/index.md#creating-a-custom-modal-type). + +::: ```javascript title="mod/example/amd/src/my_modal.js" import Modal from 'core/modal'; -import ModalFactory from 'core/modal_factory'; export default MyModal extends Modal { static TYPE = "mod_example/my_modal"; static TEMPLATE = "mod_example/my_modal"; } - -// Modal Registration process for Moodle 4.3 onwards. -MyModal.registerModalType(); ``` The template should extend the `core/modal` core template and can override any of the title, body, or footer regions, for example: @@ -186,18 +276,47 @@ The template should extend the `core/modal` core template and can override any o {{/ core/modal }} ``` -Once defined, the new modal can be instantiated using the Modal Factory, for example: +Once defined, the new modal can be instantiated using the standard `create` method, for example: ```javascript title="Instantiating a custom modal" -import ModalFactory from 'core/modal_factory'; import MyModal from 'mod_example/my_modal'; export default const init = async() => { // ... - const modal = await ModalFactory.create({ - type: MyModal.TYPE, - }); + const modal = await MyModal.create({}); modal.show(); } ``` + +### Overriding default configuration + +When creating your own modal type, you may wish to override the standard configuration. This can be achieved by overriding the `configure` class and providing your own options, for example: + +```javascript title="Overriding standard options" +import Modal from 'core/modal'; + +export default MyModal extends Modal { + static TYPE = "mod_example/my_modal"; + static TEMPLATE = "mod_example/my_modal"; + + configure(modalConfig) { + // Show this modal on instantiation. + modalConfig.show = true; + + // Remove from the DOM on close. + modalConfig.removeOnClose = true; + + super.configure(modalConfig); + + // Accept our own custom arguments too. + if (modalConfig.someValue) { + this.setSomeValue(someValue); + } + } + + setSomeValue(value) { + this.someValue = value; + } +} +```