discourse/docs/CHANGELOG-JAVASCRIPT-PLUGIN...

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

320 lines
13 KiB
Markdown
Raw Permalink Normal View History

# Changelog
All notable changes to the Discourse JavaScript plugin API located at
app/assets/javascripts/discourse/app/lib/plugin-api.js will be described
in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.39.2] - 2024-12-19
- Removed the deprecation of `includePostAttributes` for now.
## [1.39.1] - 2024-12-18
- Renamed `addTrackedPostProperty` to `addTrackedPostProperties` to allow plugins/TCs to add multiple new tracked properties to the post model.
- Deprecated `includePostAttributes` in favor of `addTrackedPostProperties`.
## [1.39.0] - 2024-11-27
- Added `addTrackedPostProperty` which allows plugins/TCs to add a new tracked property to the post model.
## [1.38.0] - 2024-10-30
- Added `registerMoreTopicsTab` and "more-topics-tabs" value transformer that allows to add or remove new tabs to the "more topics" (suggested/related) area.
## [1.37.3] - 2024-10-24
- Added `disableDefaultKeyboardShortcuts` which allows plugins/TCs to disable default keyboard shortcuts.
## [1.37.2] - 2024-10-02
- Fixed comments and text references to Font Awesome 5 in favor of the more generic Font Awesome due to core now having the latest version and no longer needing to specify version 5.
## [1.37.1] - 2024-08-21
- Added support for `shortcut` in `addComposerToolbarPopupMenuOption` which allows to add a keyboard shortcut to the popup menu option.
## [1.37.0] - 2024-08-19
- Added `addAboutPageActivity` which allows plugins/TCs to register a custom site activity item in the new /about page. Requires the server-side `register_stat` plugin API.
## [1.36.0] - 2024-08-06
- Added `addLogSearchLinkClickedCallbacks` which allows plugins/TCs to register a callback when a search link is clicked and before a search log is created
DEV: Add behavior transformers (#27409) This commit introduces the `behaviorTransformer` API to safely override behaviors defined in Discourse. Two new plugin APIs are introduced: - `addBehaviorTransformerName` which allows plugins and theme-components to add a new valid transformer name if they want to provide overridable behaviors; - `registerBehaviorTransformer` to register a transformer to override behaviors. It also introduces the function `applyBehaviorTransformer` which can be imported from `discourse/lib/transformer`. This is used to mark a callback containing the desired behavior as overridable and applies the transformer logic. How does it work? ## Marking a behavior as overridable: To mark a behavior as overridable, in Discourse core, first the transformer name must be added to `app/assets/javascripts/discourse/app/lib/transformer/registry.js`. For plugins and theme-components, use the plugin API `addBehaviorTransformerName` instead. Then, in your component or class, use the function `applyBehaviorTransformer` to mark the Behavior as overridable and handle the logic: - example: ```js ... @action loadMore() { applyBehaviorTransformer( "discovery-topic-list-load-more", () => { this.documentTitle.updateContextCount(0); return this.model .loadMore() .then(({ moreTopicsUrl, newTopics } = {}) => { if ( newTopics && newTopics.length && this.bulkSelectHelper?.bulkSelectEnabled ) { this.bulkSelectHelper.addTopics(newTopics); } if (moreTopicsUrl && $(window).height() >= $(document).height()) { this.send("loadMore"); } }); }, { model: this.model } ); }, ... ``` ## Overriding a behavior in plugins or themes To override a behavior in plugins, themes, or TCs use the plugin API `registerBehaviorTransformer`: - Example: ```js withPluginApi("1.35.0", (api) => { api.registerBehaviorTransformer("example-transformer", ({ context, next }) => { console.log('we can introduce new behavior here instead', context); next(); // call next to execute the expected behavior }); }); ```
2024-07-31 15:39:22 -04:00
## [1.35.0] - 2024-07-30
- Added `registerBehaviorTransformer` which allows registering a transformer callback to override behavior defined in Discourse modules
- Added `addBehaviorTransformerName` which allows plugins/TCs to register a new transformer to override behavior defined in their modules
DEV: Introduce a value transformer front-end plugin API (#27090) This commit introduces the `valueTransformer`API to safely override values defined in Discourse. Two new plugin APIs are introduced: - `addValueTransformerName` which allows plugins and theme-components to add a new valid transformer name if they want to provide overridable values; - `registerValueTransformer` to register a transformer to override values. It also introduces the function `applyValueTransformer` which can be imported from `discourse/lib/transformer`. This function marks the desired value as overridable and applies the transformer logic. How does it work? ## Marking a value as overridable: To mark a value as overridable, in Discourse core, first the transformer name must be added to `app/assets/javascripts/discourse/app/lib/transformer/registry.js`. For plugins and theme-components, use the plugin API `addValueTransformerName` instead. Then, in your component or class, use the function `applyValueTransformer` to mark the value as overridable and handle the logic: - example: ```js export default class HomeLogo extends Component { @service session; @service site; ... get href() { return applyValueTransformer("home-logo-href", getURL("/")); } ``` ## Overriding a value in plugins or themes To override a value in plugins, themes, or TCs use the plugin API `registerValueTransformer`: - Example: ```js withPluginApi("1.34.0", (api) => { api.registerValueTransformer("example-transformer", ({ value }) => { return "new-value"; }); }); ```
2024-06-12 14:21:52 -04:00
## [1.34.0] - 2024-06-06
- Added `registerValueTransformer` which allows registering a transformer callback to override values defined in Discourse modules
- Added `addValueTransformerName` which allows plugins/TCs to register a new transformer to override values defined in their modules
## [1.33.0] - 2024-06-06
- Added `addCustomUserFieldValidationCallback` which allows to set a callback to change the validation and user facing message when attempting to save the signup form.
## [1.32.0] - 2024-05-16
2024-06-04 09:16:24 -04:00
- Added `registerHomeLogoHrefCallback` which allows to set a callback to change the home logo URL.
## [1.31.0] - 2024-04-22
2024-06-04 09:16:24 -04:00
- Added `addTopicAdminMenuButton` which allows to register a new button in the topic admin menu.
## [1.30.0] - 2024-03-20
- Added `addAdminPluginConfigurationNav`, which defines a list of links used in the adminPlugins.show page for a specific plugin, and displays them either in an inner sidebar or in a top horizontal nav.
## [1.29.0] - 2024-03-05
2024-06-04 09:16:24 -04:00
- Added `headerButtons` which allows for manipulation of the header buttons. This includes, adding, removing, or modifying the order of buttons.
## [1.28.0] - 2024-02-21
2024-06-04 09:16:24 -04:00
- Added `headerIcons` which allows for manipulation of the header icons. This includes, adding, removing, or modifying the order of icons.
DEV: Convert header to glimmer (#25214) Here is a breakdown of the changes that will be implemented in this PR. # Widgets -> Glimmer Obviously, the intention of the todo here is to convert the header from widgets to glimmer. This PR splits the respective widgets as so: ### widgets/site-header.js ```mermaid height=200 flowchart TB A[widgets/site-header.js] A-->B[components/glimmer-site-header.gjs] ``` ### widgets/header.js and children ```mermaid height=200 flowchart TB A[widgets/header.js] A-->B[components/glimmer-header.gjs] B-->C[glimmer-header/contents.gjs] C-->D[./auth-buttons.gjs] C-->E[./icons.gjs] C-->F[./user-menu-wrapper.gjs] C-->G[./hamburger-dropdown-wrapper.gjs] C-->H[./user-menu-wrapper.gjs] C-->I[./sidebar-toggle.gjs] C-->J[./topic/info.gjs] ``` There are additional components rendered within the `glimmer-header/*` components, but I will leave those out for now. From this view you can see that we split apart the logic of `widgets/header.js` into 10+ components. Breaking apart these mega files has many benefits (readability, etc). # Services I have introduced a [header](https://github.com/discourse/discourse/blob/cdb42caa04ebcd1cf395dbe0cea96a13ce007099/app/assets/javascripts/discourse/app/services/header.js) service. This simplifies how we pass around data in the header, as well as fixes a bug we have with "swiping" menu panels. # Modifiers Added a [close-on-click-outside](https://github.com/discourse/discourse/blob/cdb42caa04ebcd1cf395dbe0cea96a13ce007099/app/assets/javascripts/discourse/app/modifiers/close-on-click-outside.js) modifier that is built upon the [close-on-click-outside modifier](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/float-kit/addon/modifiers/close-on-click-outside.js) that @jjaffeux built for float-kit. I think we could replace float-kit's implementation with mine and have it in a centralized location as they are extremely similar. # Tests Rewrote the existing header tests ([1](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/tests/integration/components/widgets/header-test.js), [2](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js)) as system tests. # Other - Converted `widgets/user-status-bubble.js` to a gjs component - Converted `widgets/sidebar-toggle.js` to a gjs component - Converted `topicFeaturedLinkNode()` to a gjs component - Deprecated the [docking mixin](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/mixins/docking.js)
2024-02-23 13:08:15 -05:00
## [1.27.0] - 2024-02-21
2024-06-04 09:16:24 -04:00
- Deprecated `addToHeaderIcons` in favor of `headerIcons`
DEV: Convert header to glimmer (#25214) Here is a breakdown of the changes that will be implemented in this PR. # Widgets -> Glimmer Obviously, the intention of the todo here is to convert the header from widgets to glimmer. This PR splits the respective widgets as so: ### widgets/site-header.js ```mermaid height=200 flowchart TB A[widgets/site-header.js] A-->B[components/glimmer-site-header.gjs] ``` ### widgets/header.js and children ```mermaid height=200 flowchart TB A[widgets/header.js] A-->B[components/glimmer-header.gjs] B-->C[glimmer-header/contents.gjs] C-->D[./auth-buttons.gjs] C-->E[./icons.gjs] C-->F[./user-menu-wrapper.gjs] C-->G[./hamburger-dropdown-wrapper.gjs] C-->H[./user-menu-wrapper.gjs] C-->I[./sidebar-toggle.gjs] C-->J[./topic/info.gjs] ``` There are additional components rendered within the `glimmer-header/*` components, but I will leave those out for now. From this view you can see that we split apart the logic of `widgets/header.js` into 10+ components. Breaking apart these mega files has many benefits (readability, etc). # Services I have introduced a [header](https://github.com/discourse/discourse/blob/cdb42caa04ebcd1cf395dbe0cea96a13ce007099/app/assets/javascripts/discourse/app/services/header.js) service. This simplifies how we pass around data in the header, as well as fixes a bug we have with "swiping" menu panels. # Modifiers Added a [close-on-click-outside](https://github.com/discourse/discourse/blob/cdb42caa04ebcd1cf395dbe0cea96a13ce007099/app/assets/javascripts/discourse/app/modifiers/close-on-click-outside.js) modifier that is built upon the [close-on-click-outside modifier](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/float-kit/addon/modifiers/close-on-click-outside.js) that @jjaffeux built for float-kit. I think we could replace float-kit's implementation with mine and have it in a centralized location as they are extremely similar. # Tests Rewrote the existing header tests ([1](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/tests/integration/components/widgets/header-test.js), [2](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js)) as system tests. # Other - Converted `widgets/user-status-bubble.js` to a gjs component - Converted `widgets/sidebar-toggle.js` to a gjs component - Converted `topicFeaturedLinkNode()` to a gjs component - Deprecated the [docking mixin](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/mixins/docking.js)
2024-02-23 13:08:15 -05:00
FEATURE: Add automatic `before` and `after` outlets to wrapper plugin outlets (#24254) Recently, Discourse introduced the concept of wrapper plugin outlets, which enables plugins and theme-components lo replace the wrapped content: ``` <PluginOutlet @name="wrapper-outlet-example" @outletArgs={{hash model=@model}}> <div>Overridable content</div> </PluginOutlet> ``` This commit adds automatic outlets that are placed `before` and `after wrapper plugin outlets. Connectors them can leverage these new automatic outlets to mount content at these positions, which greatly enhances the use case of the wrapper outlets. These new auto outlets can be used in two ways: - Using the standard folder base structure: the folder name that identifies the outlet in which the connector must be mounted must add the suffixes `__before`or `__after` to the outlet name. For the outlet in the example above, the connector should be placed into the `.../connectors/wrapper-outlet-example__before`or `.../connectors/wrapper-outlet-example__after`folders. - Using API calls: this commit also introduces two new plugin APIs, `api.renderBeforeWrapperOutlet` and `renderAfterWrapperOutlet`. These new APIs can be used in the same way as `api.renderInOutlet`but will only work for wrapper outlets. For the outlet above when using these new APIs alongside the gjs file format, one could define a component to be placed before the content of the outlet like: ``` api.renderBeforeWrapperOutlet('wrapper-outlet-example', <template>Hello from before the content</template>); ``` or after: ``` api.renderAfterWrapperOutlet('wrapper-outlet-example', <template>Hello from after the content</template>); ```
2024-02-22 13:25:34 -05:00
## [1.26.0] - 2024-02-21
2024-06-04 09:16:24 -04:00
- Added `renderBeforeWrapperOutlet` which is used for rendering components before the content of wrapper plugin outlets
- Added `renderAfterWrapperOutlet` which is used for rendering components after the content of wrapper plugin outlets
FEATURE: Add automatic `before` and `after` outlets to wrapper plugin outlets (#24254) Recently, Discourse introduced the concept of wrapper plugin outlets, which enables plugins and theme-components lo replace the wrapped content: ``` <PluginOutlet @name="wrapper-outlet-example" @outletArgs={{hash model=@model}}> <div>Overridable content</div> </PluginOutlet> ``` This commit adds automatic outlets that are placed `before` and `after wrapper plugin outlets. Connectors them can leverage these new automatic outlets to mount content at these positions, which greatly enhances the use case of the wrapper outlets. These new auto outlets can be used in two ways: - Using the standard folder base structure: the folder name that identifies the outlet in which the connector must be mounted must add the suffixes `__before`or `__after` to the outlet name. For the outlet in the example above, the connector should be placed into the `.../connectors/wrapper-outlet-example__before`or `.../connectors/wrapper-outlet-example__after`folders. - Using API calls: this commit also introduces two new plugin APIs, `api.renderBeforeWrapperOutlet` and `renderAfterWrapperOutlet`. These new APIs can be used in the same way as `api.renderInOutlet`but will only work for wrapper outlets. For the outlet above when using these new APIs alongside the gjs file format, one could define a component to be placed before the content of the outlet like: ``` api.renderBeforeWrapperOutlet('wrapper-outlet-example', <template>Hello from before the content</template>); ``` or after: ``` api.renderAfterWrapperOutlet('wrapper-outlet-example', <template>Hello from after the content</template>); ```
2024-02-22 13:25:34 -05:00
## [1.25.0] - 2024-02-05
- Added `addComposerImageWrapperButton` which is used to add a custom button to the composer preview's image wrapper that appears on hover of an uploaded image.
## [1.24.0] - 2024-01-08
- Added `addAdminSidebarSectionLink` which is used to add a link to a specific admin sidebar section, as a replacement for the `admin-menu` plugin outlet. This only has an effect if the `admin_sidebar_enabled_groups` site setting is in use, which enables the new admin nav sidebar.
## [1.23.0] - 2024-01-03
### Added
- Added `setUserMenuNotificationsLimit` function which is used to specify a new limit for the notifications query when the user menu is opened.
## [1.21.0] - 2023-12-22
### Added
- Added `includeUserFieldPropertiesOnSave` function, which includes the passed user field properties in the user field save request. This is useful for plugins that are adding additional columns to the user field model and want to save the new property values alongside the default user field properties (all under the same save call).
## [1.20.0] - 2023-12-20
### Added
- Added `addSearchMenuAssistantSelectCallback` function, which is used to override the behavior of clicking a search menu assistant item. If any callback returns false, the core behavior will not be executed.
## [1.19.0] - 2023-12-13
### Added
- Added `setNotificationsLimit` function, which sets a new limit for how many notifications are loaded for the user notifications route
- Added `addBeforeLoadMoreNotificationsCallback` function, which takes a function as the argument. All added callbacks are evaluated before `loadMore` is triggered for user notifications. If any callback returns false, notifications will not be loaded.
## [1.18.0] - 2023-12-1
### Added
- Added `setDesktopTopicTimelineScrollAreaHeight` function, which takes an object with min/max key value pairs as an argument. This is used to adjust the height of the topic timeline on desktop without CSS hacks that break the functionality of the topic timeline.
## [1.17.0] - 2023-11-30
### Added
- Introduces `forceDropdownAnimationForMenuPanels` API for forcing one or many Menu Panels (search-menu, user-menu, etc) to be rendered as a dropdown. This can be useful for plugins as the default behavior is to add a 'slide-in' behavior to a menu panel if you are viewing on a small screen. eg. mobile.
## [1.16.0] - 2023-11-17
### Added
- Added `recurrenceRule` option to `downloadCalendar`, this can be used to set recurring events in the calendar. Rule syntax can be found at https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.10.
DEV: Add new experimental admin UI route and sidebar (#23952) This commit adds a new admin UI under the route `/admin-revamp`, which is only accessible if the user is in a group defined by the new `enable_experimental_admin_ui_groups` site setting. It also adds a special `admin` sidebar panel that is shown instead of the `main` forum one when the admin is in this area. ![image](https://github.com/discourse/discourse/assets/920448/fa0f25e1-e178-4d94-aa5f-472fd3efd787) We also add an "Admin Revamp" sidebar link to the community section, which will only appear if the user is in the setting group: ![image](https://github.com/discourse/discourse/assets/920448/ec05ca8b-5a54-442b-ba89-6af35695c104) Within this there are subroutes defined like `/admin-revamp/config/:area`, these areas could contain any UI imaginable, this is just laying down an initial idea of the structure and how the sidebar will work. Sidebar links are currently hardcoded. Some other changes: * Changed the `main` and `chat` panels sidebar panel keys to use exported const values for reuse * Allowed custom sidebar sections to hide their headers with the `hideSectionHeader` option * Add a `groupSettingArray` setting on `this.siteSettings` in JS, which accepts a group site setting name and splits it by `|` then converts the items in the array to integers, similar to the `_map` magic for ruby group site settings * Adds a `hidden` option for sidebar panels which prevents them from showing in separated mode and prevents the switch button from being shown --------- Co-authored-by: Krzysztof Kotlarek <kotlarek.krzysztof@gmail.com>
2023-10-19 00:23:41 -04:00
## [1.15.0] - 2023-10-18
### Added
- Added `hidden` option to `addSidebarPanel`, this can be used to remove the panel from combined sidebar mode as well as hiding its switch button. Useful for cases where only one sidebar should be shown at a time regardless of other panels.
- Added `getSidebarPanel` function, which returns the current sidebar panel object for comparison.
## [1.14.0] - 2023-10-06
### Added
- Added `addComposerToolbarPopupMenuOption` as a replacement for `addToolbarPopupMenuOptionsCallback` with new changes
introduced to the method's signature.
### Changed
- Deprecate `addToolbarPopupMenuOptionsCallback` in favor of `addComposerToolbarPopupMenuOption`.
## [1.13.0] - 2023-10-05
### Added
- Introduces `renderInOutlet` API for rendering components into plugin outlets
DEV: FloatKit (#23650) This PR introduces three new concepts to Discourse codebase through an addon called "FloatKit": - menu - tooltip - toast ## Tooltips ### Component Simple cases can be express with an API similar to DButton: ```hbs <DTooltip @Label={{i18n "foo.bar"}} @ICON="check" @content="Something" /> ``` More complex cases can use blocks: ```hbs <DTooltip> <:trigger> {{d-icon "check"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> Something </:content> </DTooltip> ``` ### Service You can manually show a tooltip using the `tooltip` service: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it tooltipInstance.close(); tooltipInstance.destroy(); // you can also just close any open tooltip through the service this.tooltip.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const tooltipInstance = this.tooltip.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners tooltipInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Menus Menus are very similar to tooltips and provide the same kind of APIs: ### Component ```hbs <DMenu @ICON="plus" @Label={{i18n "foo.bar"}}> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </DMenu> ``` They also support blocks: ```hbs <DMenu> <:trigger> {{d-icon "plus"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </:content> </DMenu> ``` ### Service You can manually show a menu using the `menu` service: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it menuInstance.close(); menuInstance.destroy(); // you can also just close any open tooltip through the service this.menu.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const menuInstance = this.menu.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners menuInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Toasts Interacting with toasts is made only through the `toasts` service. A default component is provided (DDefaultToast) and can be used through dedicated service methods: - this.toasts.success({ ... }); - this.toasts.warning({ ... }); - this.toasts.info({ ... }); - this.toasts.error({ ... }); - this.toasts.default({ ... }); ```javascript this.toasts.success({ data: { title: "Foo", message: "Bar", actions: [ { label: "Ok", class: "btn-primary", action: (componentArgs) => { // eslint-disable-next-line no-alert alert("Closing toast:" + componentArgs.data.title); componentArgs.close(); }, } ] }, }); ``` You can also provide your own component: ```javascript this.toasts.show(MyComponent, { autoClose: false, class: "foo", data: { baz: 1 }, }) ``` Co-authored-by: Martin Brennan <mjrbrennan@gmail.com> Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Co-authored-by: David Taylor <david@taylorhq.com> Co-authored-by: Jarek Radosz <jradosz@gmail.com>
2023-09-26 07:39:52 -04:00
## [1.12.0] - 2023-09-06
### Added
- Adds `addPostAdminMenuButton` which allows to register a new button in the post admin menu.
## [1.11.0] - 2023-08-30
### Added
DEV: FloatKit (#23650) This PR introduces three new concepts to Discourse codebase through an addon called "FloatKit": - menu - tooltip - toast ## Tooltips ### Component Simple cases can be express with an API similar to DButton: ```hbs <DTooltip @Label={{i18n "foo.bar"}} @ICON="check" @content="Something" /> ``` More complex cases can use blocks: ```hbs <DTooltip> <:trigger> {{d-icon "check"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> Something </:content> </DTooltip> ``` ### Service You can manually show a tooltip using the `tooltip` service: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it tooltipInstance.close(); tooltipInstance.destroy(); // you can also just close any open tooltip through the service this.tooltip.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const tooltipInstance = this.tooltip.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners tooltipInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Menus Menus are very similar to tooltips and provide the same kind of APIs: ### Component ```hbs <DMenu @ICON="plus" @Label={{i18n "foo.bar"}}> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </DMenu> ``` They also support blocks: ```hbs <DMenu> <:trigger> {{d-icon "plus"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </:content> </DMenu> ``` ### Service You can manually show a menu using the `menu` service: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it menuInstance.close(); menuInstance.destroy(); // you can also just close any open tooltip through the service this.menu.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const menuInstance = this.menu.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners menuInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Toasts Interacting with toasts is made only through the `toasts` service. A default component is provided (DDefaultToast) and can be used through dedicated service methods: - this.toasts.success({ ... }); - this.toasts.warning({ ... }); - this.toasts.info({ ... }); - this.toasts.error({ ... }); - this.toasts.default({ ... }); ```javascript this.toasts.success({ data: { title: "Foo", message: "Bar", actions: [ { label: "Ok", class: "btn-primary", action: (componentArgs) => { // eslint-disable-next-line no-alert alert("Closing toast:" + componentArgs.data.title); componentArgs.close(); }, } ] }, }); ``` You can also provide your own component: ```javascript this.toasts.show(MyComponent, { autoClose: false, class: "foo", data: { baz: 1 }, }) ``` Co-authored-by: Martin Brennan <mjrbrennan@gmail.com> Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Co-authored-by: David Taylor <david@taylorhq.com> Co-authored-by: Jarek Radosz <jradosz@gmail.com>
2023-09-26 07:39:52 -04:00
- Adds `addBeforeAuthCompleteCallback` which allows plugins and themes to add functions to be
evaluated before the auth-complete logic is run. If any of these callbacks return false, the
auth-complete logic will be aborted.
## [1.10.0] - 2023-08-25
### Added
- Adds `registerReviewableActionModal` which allows core and plugins to register a modal component class
which is used to show a modal for certain reviewable actions.
## [1.9.0] - 2023-08-09
### Added
- Adds `showSidebarSwitchPanelButtons` which is experimental, and allows plugins to show sidebar switch panel buttons in separated mode
- Adds `hideSidebarSwitchPanelButtons` which is experimental, and allows plugins to hide sidebar switch panel buttons in separated mode
## [1.8.1] - 2023-08-08
### Added
- Adds `replacePostMenuButton` which allows plugins to replace a post menu button with a widget.
## [1.8.0] - 2023-07-18
### Added
DEV: FloatKit (#23650) This PR introduces three new concepts to Discourse codebase through an addon called "FloatKit": - menu - tooltip - toast ## Tooltips ### Component Simple cases can be express with an API similar to DButton: ```hbs <DTooltip @Label={{i18n "foo.bar"}} @ICON="check" @content="Something" /> ``` More complex cases can use blocks: ```hbs <DTooltip> <:trigger> {{d-icon "check"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> Something </:content> </DTooltip> ``` ### Service You can manually show a tooltip using the `tooltip` service: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it tooltipInstance.close(); tooltipInstance.destroy(); // you can also just close any open tooltip through the service this.tooltip.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const tooltipInstance = this.tooltip.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners tooltipInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Menus Menus are very similar to tooltips and provide the same kind of APIs: ### Component ```hbs <DMenu @ICON="plus" @Label={{i18n "foo.bar"}}> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </DMenu> ``` They also support blocks: ```hbs <DMenu> <:trigger> {{d-icon "plus"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </:content> </DMenu> ``` ### Service You can manually show a menu using the `menu` service: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it menuInstance.close(); menuInstance.destroy(); // you can also just close any open tooltip through the service this.menu.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const menuInstance = this.menu.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners menuInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Toasts Interacting with toasts is made only through the `toasts` service. A default component is provided (DDefaultToast) and can be used through dedicated service methods: - this.toasts.success({ ... }); - this.toasts.warning({ ... }); - this.toasts.info({ ... }); - this.toasts.error({ ... }); - this.toasts.default({ ... }); ```javascript this.toasts.success({ data: { title: "Foo", message: "Bar", actions: [ { label: "Ok", class: "btn-primary", action: (componentArgs) => { // eslint-disable-next-line no-alert alert("Closing toast:" + componentArgs.data.title); componentArgs.close(); }, } ] }, }); ``` You can also provide your own component: ```javascript this.toasts.show(MyComponent, { autoClose: false, class: "foo", data: { baz: 1 }, }) ``` Co-authored-by: Martin Brennan <mjrbrennan@gmail.com> Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Co-authored-by: David Taylor <david@taylorhq.com> Co-authored-by: Jarek Radosz <jradosz@gmail.com>
2023-09-26 07:39:52 -04:00
- Adds `addSidebarPanel` which is experimental, and adds a Sidebar panel by returning a class which extends from the
BaseCustomSidebarPanel class.
- Adds `setSidebarPanel` which is experimental, and sets the current sidebar panel.
## [1.7.1] - 2023-07-18
### Added
- Adds `addBulkActionButton` which adds actions to the Bulk Topic modal
## [1.7.0] - 2023-07-17
### Added
- Adds `addCommunitySectionLink` which allows plugins to add a navigation link to the Sidebar community section under
the "More..." links drawer.
- Adds `registerUserCategorySectionLinkCountable` which allows plugins to register a new countable for section links
under Sidebar Categories section on top of the default countables of unread topics count and new topics count.
- Adds `registerCustomCategorySectionLinkLockIcon` which allows plugins to change the lock icon used for a sidebar
category section link to indicate that a category is read restricted.
- Adds `registerCustomCategorySectionLinkPrefix` which allows plugins to register a custom prefix for a sidebar category
section link.
- Adds `registerCustomTagSectionLinkPrefixValue` which allows plugins to register a custom prefix for a sidebar tag
section link.
- Adds `refreshUserSidebarCategoriesSectionCounts` which allows plugins to trigger a refresh of the counts for all
category section links under the categories section for a logged in user.
- Adds `addSidebarSection` which allows plugins to add a Sidebar section.
- Adds `registerNotificationTypeRenderer` which allows plugins to register a custom renderer for a notification type
or override the renderer of an existing type. See lib/notification-types/base.js for documentation and the default
renderer.
- Adds `registerModelTransformer` which allows plugins to apply transformation using a callback on a list of model
instances of a specific type. Currently, this API only works on lists rendered in the user menu such as notifications,
bookmarks and topics (i.e. messages), but it may be extended to other lists in other parts of the app.
- Adds `addUserMessagesNavigationDropdownRow` which allows plugins to add a row to the dropdown used on the
`userPrivateMessages` route used to navigate between the different user messages pages.
## [1.6.0] - 2022-12-13
### Added
- Adds `addPostSmallActionClassesCallback`, which allows users to register a custom
function that adds a class to small action posts (pins, closing topics, etc)
## [1.5.0] - 2022-11-21
### Added
- Adds `addComposerSaveErrorCallback`, which allows users to register custom error handling
for server-side errors when submitting on the composer.
## [1.4.0] - 2022-09-27
### Added
- Adds `registerHighlightJSPlugin`, which allows users to register custom
HighlightJS plugins. See https://highlightjs.readthedocs.io/en/latest/plugin-api.html
for documentation.
## [1.3.0] - 2022-05-29
### Added
- N/A - Mistakenly bumped.
## [1.2.0] - 2022-03-18
### Added
- Adds `registerCustomLastUnreadUrlCallback`, which allows users to register a custom
function that returns a last unread url for a topic list item. When multiple callbacks
are registered, the first non-null value that is returned will be used.
## [1.1.0] - 2021-12-15
### Added
- Adds `addPosterIcons`, which allows users to add multiple icons to a poster. The
addition of this function also makes the existing `addPosterIcon` now an alias to this
function. Users may now just use `addPosterIcons` for both one or many icons. This
function allows users to now return many icons depending on an `attrs`.
## [1.0.0] - 2021-11-25
### Removed
- Removes the `addComposerUploadProcessor` function, which is no longer used in
favour of `addComposerUploadPreProcessor`. The former was used to add preprocessors
for client side uploads via jQuery file uploader (described at
https://github.com/blueimp/jQuery-File-Upload/wiki/Options#file-processing-options).
The new `addComposerUploadPreProcessor` adds preprocessors for client side
uploads in the form of an Uppy plugin. See https://uppy.io/docs/writing-plugins/
for the Uppy documentation, but other examples of preprocessors in core can be found
in the UppyMediaOptimization and UppyChecksum classes. This has been done because
of the overarching move towards Uppy in the Discourse codebase rather than
jQuery fileupload, which will eventually be removed altogether as a broader effort
to remove jQuery from the codebase.
### Changed
- Changes `addComposerUploadHandler`'s behaviour. Instead of being only usable
for single files at a time, now multiple files are sent to the upload handler
at once. These multiple files are sent based on the groups in which they are
added (e.g. multiple files selected from the system upload dialog, or multiple
files dropped in to the composer). Files will be sent in buckets to the handlers
they match.