This might soon become a first class feature in Discourse core in the
short term so marking it as experimental for now to bridge
certain Discourse own-ed plugins and themes.
This commit adds the experimental `registerCustomCategorySectionLinkPrefix` client side
plugin API that allows themes or plugins to override the prefix of a
category section link.
This is marked experimental because we might be introducing a core
feature where category icons are supported. This is currently use as a
bridge for the https://github.com/discourse/discourse-category-icons
theme component.
* FIX: Fix for Default to subcategory when parent category does not allow posting
* added tests for edge case scenario
* implemented correct behaviour when parent category doesn't have subcategories
* implemented new fabricator for categories and suggested changes
New client side plugin API that allows plugins or themes to customize
the fontawesome 5 icon used to indicate that a category is locked/read
restricted.
The welcome topic user tip was for admins only, but in general, user
tips should be used for guiding new users through the features that
Discourse offers. For this reason, we decided to remove the user tip.
This commit also includes a few more copy tweaks to the welcome topic.
What is the problem?
This is a follow up to 4cca7de22d. In the
commit, CSS was used to disable the collapsing of sections in the header
dropdown navigation menu when the `navigation_menu` site setting is set
to `header dropdown`. However, using CSS is not the correct approach as
the underlying code is still marking the section as collapsable which
means that the sections will still be displayed as collapsed with no way
to "uncollapse" if the local store has already marked the section as
collapsed.
What is the fix?
This commit removes the usage of CSS to hide the collapsabe button and
instead correctly marks the section as not collapsable in the code.
Context of the problem
When viewing the topic list for either the personal inbox or the group
PM inbox, we store a cache of the topic list if the user has loaded more
topics in the topic list. This cache is used to improve the experience
for users so that navigating to a topic and then back would not make
them lose their "last read" position in the topic list. Without this
cache, users will have to start from the top of the topic list each time
they navigate back after reading a topic.
What is the problem?
After archiving a PM, the user is redirected to either the personal
inbox or the group PM inbox. The problem is that if a topic list cache
exists, we will render the topic list using the cache. However, this
means that the archived PM will still appear in the list leading to
confusion for our users.
What is the fix?
To fix this, we will simply clear the topic list cache after a user
archives a topic.
It wasn't possible (at least in any reasonable way) to pass params like `tags`. Also removes the export and inlines the function as that was used only to test the function and the test is gone.
This test was passing, but the environment it was testing was incorrect.
The `image-controls` markdown rule allowlists several svgs when previewing.
But since `previewing: true` is only set on the parent `ComposerEditor`
component, the test in `DEditor` wasn't aware of that, so the output was
ignoring the `previewing` option.
This moves the test one level higher, to `ComposerEditor`, and because
now `previewing: true` is correctly used, it updates the test to show
that the svg element is present, but an `onload` attributes is stripped.
We have been struggling lately finding site settings due to 30 setting limit
This was introduced for performance reasons a while back but is no longer as
needed given that ember is faster.
Additionally searching is hard, so allow people to use fuzzy search against
setting name.
What is the problem?
Previously the `sections` getter was initializing duplicate `lib/sidebar/(community-)section` instances every time it was evaluated. This change in identity was causing Ember's `{{#each` helper to totally rerender every section whenever the getter was evaluated.
What is the fix?
This commit refactors things to lean on Ember's components for state/lifecycle management. The `{{#each` loop is done over the source data, which is guaranteed to only change identity when there is a real config change. Individual section components are initialized for each section, and are responsible for constructing and tearing down their own `lib/sidebar/(community-)section` instances.
This commit also updates `lib/sidebar/(community-)section` to support service injection rather than passing service references around.
Co-authored-by: David Taylor <david@taylorhq.com>
We use the `:empty` css selector on `#modal-alert`, so we need to strip any whitespace from the contents to ensure the selector functions correctly. Followup to ad431ab03a
* FIX: Displaying the wrong number of minimum tags in the composer
When the minimum number of tags set for the category is larger than the minimum number of tags
set in the category tag-groups, the composer was displaying the wrong value.
This commit fixes the value displayed in the composer to show the max value between the required
for the category and the tag-groups set for the category.
This bug was reported on Meta in https://meta.discourse.org/t/tags-from-multiple-tag-groups-required-only-suggest-select-at-least-one-tag/263817
* FIX: Limiting tags in categories not working as expected
When a category was restricted to a tag group A, which was set to only allow
one tag from the group per topic, selecting a tag belonging only to A returned
other tags from A that also belonged to other group/s (if any).
Example:
Tag group A: alpha, beta, gamma, epsilon, delta
Tag group B: alpha, beta, gamma
Both tag groups set to only allow one tag from the group per topic.
If Category 1 was set to only allow tags from the tag group A, and the first tag
selected was epsilon, then, because they also belonged to tag group B, the tags
alpha, beta, and gamma were still returned as valid options when they should not be.
This commit ensures that once a tag from a tag group that restricts its tags to
one per topic is selected, no other tag from this group is returned.
This bug was reported on Meta in https://meta.discourse.org/t/limiting-tags-to-categories-not-working-as-expected/263143.
* FIX: Moving topics does not prompt to add required tag for new category
When a topic moved from a category to another, the tag requirements
of the new category were not being checked.
This allowed a topic to be created and moved to a category:
- that limited the tags to a tag group, with the topic containing tags
not allowed.
- that required N tags from a tag group, with the topic not containing
the required tags.
This bug was reported on Meta in https://meta.discourse.org/t/moving-tagged-topics-does-not-prompt-to-add-required-tag-for-new-category/264138.
* FIX: Editing topics with tag groups from parents allows incorrect tagging
When there was a combination between parent tags defined in a tag group
set to allow only one tag from the group per topic, and other tag groups
relying on this restriction to combine the children tag types with the
parent tag, editing a topic could allow the user to insert an invalid
combination of these tags.
Example:
Automakers tag group: landhover, toyota
- group set to limit one tag from the group per topic
Toyota models group: land-cruiser, hilux, corolla
Landhover models group: evoque, defender, discovery
If a topic was initially set up with the tags toyota, land-cruiser it was
possible to edit it by removing the tag toyota and adding the tag landhover
and other landhover model tags like evoque for example.
In this case, the topic would end up with the tags toyota, land-cruiser,
landhover, evoque because Discourse will automatically insert the
missing parent tag toyota when it detects the tag land-cruiser.
This combination of tags would violate the restriction specified in
the Automakers tag group resulting in an invalid combination of tags.
This commit enforces that the "one tag from the group per topic"
restriction is verified before updating the topic tags and also
make sure the verification checks the compatibility of parent tags that
would be automatically inserted.
After the changes, the user will receive an error similar to:
The tags land-cruiser, landhover cannot be used simultaneously.
Please include only one of them.
Moving all control of 'hidden' into Ember will resolve issues we're seeing with Ember fighting against manual DOM manipulation (both vanilla JS and JQuery).
Looking up `controller:modal` from components is not ideal. However, the next step in the refactoring is to create a modal 'service' which will be able to injected into components cleanly.
Having these things configured at the invocation of showModal is a strange API, and means that any changes to the modal require updating the call sites. It makes much more sense for these to be defined as part of the modal's own template. This was already supported for many of the properties. This commit adds support for the `modalClass` and `titleAriaElementId` config to be passed to DModalBody.
For now there is no deprecation message. Support for passing these things to `showModal` will be dropped as part of an upcoming conversion of modals from controllers to components.
Watched words were converted to regular expressions containing \W, which
handled only ASCII characters. Using [^[:word]] instead ensures that
UTF-8 characters are also handled correctly.
What is the problem?
The main problem here is that we were incorrectly registering the same `onStateChange` callback with `TopicTrackingState`
each time a user reads a post. When a user reads a post, the state in `TopicTrackingState` is updated and it triggers all
the `onStateChange` callbacks which have been registered. In the `CommunitySection` class, we register a callback which
would then call the `onTopicTrackingStateChange` method for each link in the class. For the `EverythingSectionLink` class,
this would lookup the state in `TopicTrackingState` to get a new count of unread/new topics and update the `totalUnread` and
`totalNew` properties which are tracked. For some reason that I have yet to figure out, updating the either of the tracked properties
would result in Ember rerendering the entire `{{#each this.sections as |section|}}` in `component/sidebar/user/custom-sections.hbs`
template. Note that `this.sections` refers to a `@cached` getter in the `SidebarUserCustomSections` class. The problem is that
the `sections` getter is initializing a new bunch of sidebar sections related classes without calling the teardown function.
As a result, we end up registering new `onStateChange` callbacks in `TopicTrackingState` in `CommunitySection` without
removing the old ones. Over time, the number of callbacks build up and we end up slowing down the application. While we do
not know the reason why defining a getter for the `sections` is causing the entire block to re-render, I realized that
it is dangerous to use a getter for `sections` here since we have very little control on when the cached is broken.
Instead, I moved the `sections` getter to a tracked property instead where the property is updated via `appEvents`. With
this change, updating the tracked properties in `EverythingSectionLink` is no longer triggering a complete re-render of the
said block above. We also now call `teardown` on the section objects that has been initialised before updating the `sections`
property.
An extensibility point we support server side is setting meta_data
(topic / post custom fields) with the composer payload.
Previous to this change even though we had a lot of setup code we never
actually sent the payload.
This ensures that on create we send meta_data.
- Update welcome topic copy
- Edit the welcome topic automatically when the title or description changes
- Remove “Create your Welcome Topic” banner/CTA
- Add "edit welcome topic" user tip
a373bf2 updated the behavior of replace-emoji so that the input is treated as unsafe-by-default. fancy_title is already escaped, so we need to mark it as html-safe to avoid it being double-escaped.
There is no need to html-safe the result of replace-emoji - it's already done as part of the helper.
The issues fixed:
1. Previously all static pages (e.g. login-required landing page, /tos, /privacy, forgot-password) were wrapped in the faq-read-tracking component
2. All these pages shared one controller with methods that were relevant to one route
3. There were two route-generating functions: `static-route-builder` and `build-static-route` 🤣
4. They were using the deprecated `renderTemplate()` API
5. A slight misuse of Ember API (`controllerFor()`)
6. Small mark-faq-read related bugs
added site toggle functionality through site settings
added tests to implemented feature
Introduced suggested correction
renamed find_new_topic method and deleted click_new_topic_button method
Currently the /new-category url can be accessed by moderators, regardless of whether the Site Setting for moderators_manage_categories_and_groups is true or false.
On top of this, non authorized users can also access this page but shows errors (no 404 loaded).
Since the 404 redirect happens within Ember, we need to allow the site setting value to be accessed within JS.
After this change all non admin users will see a 404 for this route, the exception being moderators if the moderators_manage_categories_and_groups setting has a value of true.
/t/73360
The problem
When selecting text and clicking the "Edit" button that pops up, this opens up the Fast Edit dialog.
The fast edit feature doesn't work well with non standard characters (non-ascii). If the user selects a string of text that contains non-ascii characters, sometimes they won't save. It is non-obvious to the user why this is happening. This issue occurs more frequently when editing content that is written in non-english languages, as fast-edit doesn't work well with non-ascii characters. We currently do a global replace on a couple of the more obvious quotation marks when the fast edit dialog attempts to save, but there are too many edge cases for foreign language content.
The solution
We can fix this issue by using a catch-all approach for non-ascii characters before the user clicks the edit button to bring up the fast edit dialog. Then we can fallback to the full composer to edit their text, which has much better support for non-ascii characters.
What does this regex do?
The regex used matches any character that is not within the ASCII range of 0x00 to 0x7F, which includes all control characters and non-ASCII characters.
This regex pattern can be used to match any character that is not a standard ASCII character, such as accented characters, non-Latin characters, and special symbols.
This improves keyboard navigation in and out of select-kit components.
The improvements include:
- `Tab` will now dismiss the dropdown once the active element is outside
the select-kit element
- pressing `Escape` will not bubble, this is most noticeable in the
composer, pressing `Esc` there now when a dropdown is expanded will not
dismiss the composer
- `Shift+Tab` will also dismiss the dropdown once focus is outside it
The problem
The fast edit feature doesn't work well with non standard characters (non-ascii). If the user selects a string of text that contains non-ascii characters, then the edit won't save.
The solution
The best solution is to catch those non-ascii characters before the user clicks the edit button to bring up the fast edit dialog. Then we can fallback to the full composer to edit their text, which has much better support for non-ascii characters.
What does this regex do?
The regex used to catch this is [^\x00-\x7F], which matches any character that is not within the ASCII range of 0x00 to 0x7F, which includes all control characters and non-ASCII characters.
This regex pattern can be used to match any character that is not a standard ASCII character, such as accented characters, non-Latin characters, and special symbols.
Ember's implicit injections feature is removed in Ember 4.x. We want to give ourselves more time to migrate to explicit injections, so this commit re-implements our implicit injections as extensions to the base framework classes.
Incremental migration to newer patterns can be achieved using the `@disableImplicitInjections` class decorator (available from `discourse/lib/implicit-injections').
This resolves and unsilences the `implicit-injections` deprecation.
Change mechanism handling `more` button for sidebar.
Before it was using HTML details tag.
To make tests more reliable, we are switching to use ember runloop.
What is the problem?
The TopicTrackingState is a service on the client side that is used to store
state of topics which is new or has unread posts for a given user. The state
is updated via various means and the one in concern here is whenever we load
a new topic list from the server. When a topic list is loaded from the server,
we sync this new topic list with the states in TopicTrackingState. There is also
a hard limit on the number of states that is stored by TopicTrackingState for
performance reasons and the limit is currently set to 4000. It was noticed that
once this limit has been reached, syncing a topic list with TopicTrackingState can
result in the registered state change callbacks to be called unnecessarily. This
is because during `TopicTrackingState#sync` we call `TopicTrackingState#removeTopic`
if the topic in question is neither new or unread to a user. However, `TopicTrackingState#removeTopic`
would call `TopicTrackingState#_afterStateChange` even if nothing was removed.
What is the fix?
This commit fixes the problem by checking that `TopicTrackingState#_afterStateChange` is only
called in `TopicTrackingState#removeTopic` when a topic is actually removed.
- Ensure changing timezones are reflected immediately in the date-time-input (the computed property was missing a dependent key)
- Ensure date-input doesn't lose timezone information (calling `toDate()` causes moment timestamps to lose timezone information)
This was created to resolve issues in the discourse-calendar plugin (https://github.com/discourse/discourse-calendar/pull/399)
In the expand table event handler, we currently rely on `event.target`
to select the table being expanded. Sometimes, the target is the svg icon
wrapped inside the button instead of the button itself. This throws
things off.
This change uses `currentTarget` which refers to the button
element even if the event originated from svg icon.
* DEV: move sidebar community section to database
Before, community section was hard-coded. In the future, we are planning to allow admins to edit it. Therefore, it has to be moved to database to `custom_sections` table.
Few steps and simplifications has to be made:
- custom section was hidden behind `enable_custom_sidebar_sections` feature flag. It has to be deleted so all forums, see community section;
- migration to add `section_type` column to sidebar section to show it is a special type;
- migration to add `segment` column to sidebar links to determine if link should be displayed in primary section or in more section;
- simplify more section to have one level only (secondary section links are merged);
- ensure that links like `everything` are correctly tracking state;
- make user an anonymous links position consistence. For example, from now on `faq` link for user and anonymous is visible in more tab;
- delete old community-section template.
This commit fixes a bug on subfolder setups where the user messages
inbox dropdown will always be blank. This is because we were comparing
URLs using values from `router.currentURL` and `router.urlFor` where
`router.currentURL` does not include `router.rootURL` while
`router.urlFor` does.
Ember's implicit injections feature is removed in Ember 4.x. We want to give ourselves more time to migrate to explicit injections, so this commit re-implements our implicit injections as extensions to the base framework classes.
Incremental migration to newer patterns can be achieved using the `@disableImplicitInjections` class decorator (available from `discourse/lib/implicit-injections').
This resolves and unsilences the `implicit-injections` deprecation.
When navigating with the keyboard, the select-kit would not close when
focus was moved to an element outside of the body. For example, when
navigating via Tab or Shift+Tab, once the end (or beginning) of the list
was reached, focus would move out of the SK element, but the SK itself
would stay visible.
Switching from a click event to a focusout event solves the issue and
covers both mouse and keyboard navigation.
Ran into an issue with these hooks preventing click events on anchors from completing (because the triggered rerender cancels the click). See:
https://github.com/discourse/discourse-header-search/pull/24
This change should have no effect on existing usage of these hooks. Current usage is limited to:
- legacy navigation (should be a no-op)
- reactions plugin (should be a no-op)
- discourse-header-search (will fix the issue!)
* FIX: Empty video thumbnails
This fix ensures that topic video thumbnail generation is completed
before the composer is allowed to submit which should prevent some bugs
around missing thumbnails on video topics.
* move callback to on upload-success
User status updates come from the server in a map where keys are user IDs.
If user.trackStatus() is called for a user model without an ID, the model
cannot identify its status updates and silently misses them. It's quite hard to
notice that a user rendered in the UI doesn't receive live status updates.
Also, it's not immediately obvious what's the reason of the problem.
A warning will be very helpful here.
Named outlets are deprecated and will be removed in Ember 4.x.
Backwards-compatibility shims are introduced so that plugin overrides to `controller:composer` are ported to `service:composer`.
After removing `TextareaTextManipulation` from `ChatComposer` and using `TextareaInteractor` as a proxy, one function has been forgotten: `paste(event)` which is not available in glimmer components anymore, and even less avaiable now that the mixin is not tied to a component anymore but a real DOM node. As a solution we now add a manual paste event listener which will call `paste(event)`.
This pull request is a full overhaul of the chat-composer and contains various improvements to the thread panel. They have been grouped in the same PR as lots of improvements/fixes to the thread panel needed an improved composer. This is meant as a first step.
### New features included in this PR
- A resizable side panel
- A clear dropzone area for uploads
- A simplified design for image uploads, this is only a first step towards more redesign of this area in the future
### Notable fixes in this PR
- Correct placeholder in thread panel
- Allows to edit the last message of a thread with arrow up
- Correctly focus composer when replying to a message
- The reply indicator is added instantly in the channel when starting a thread
- Prevents a large variety of bug where the composer could bug and prevent sending message or would clear your input while it has content
### Technical notes
To achieve this PR, three important changes have been made:
- `<ChatComposer>` has been fully rewritten and is now a glimmer component
- The chat composer now takes a `ChatMessage` as input which can directly be used in other operations, it simplifies a lot of logic as we are always working a with a `ChatMessage`
- `TextareaInteractor` has been created to wrap the existing `TextareaTextManipulation` mixin, it will make future migrations easier and allow us to have a less polluted `<ChatComposer>`
Note ".chat-live-pane" has been renamed ".chat-channel"
Design for upload dropzone is from @chapoi
Due to the order we were parsing markdown, bbcode [url] elements were not
handled properly.
`[url]https://example.com/path[/url]` was not currectly parsing cause
linkify was detecting the url as: `https://example.com/path[/url]` which is
legit.
To resolve this I swapped url to use a replace rule, and instead re-parsed
the internal payload and injected the tokens in.
This fix is complex cause we support stuff like
`[url][b]test.com[/b][/url]`
So we need to parse the content inside url `[b]test.com[/b]`
* FIX: Blank video thumbnails
On some mobile and possibly other browsers, the automatic video
thumbnail generation would create blank or all white images.
This commit addresses several different issues that was preventing image
generation from working correctly on mobile.
* fix typo
The updated user menu is the default for new sites, and will soon be enabled on older sites. This commit removes the 'EXPERIMENTAL' warning from the new `registerUserMenuTab` API, and adds a note to the `addUserMenuGlyph` documentation.
Followup to 17ba00c395.
Fix for https://meta.discourse.org/t/-/261917
This fixes a usability issue where the user couldn't switch to the user
menu when the search menu was visible and the text in the input was
selected.
Explanation: The `click` event is triggered both when clicking and when
selecting some text and clicking. This means that when selecting text in
the search input, at the end of the selection event, a click event was
triggered. And if that click event happened to be outside of the search
menu, then the menu would be dismissed.
Previously, we fixed this by checked if a current text selection was
present. But that results in a small side-effect of not switching to
other menus. This PR switches to setting a flag during `mouseDown` and
then using that flag when evaluating whether to trigger clickOutside or
not.
It's backward compatible so still supports our 3.28 ember-source.
The visible change is finally getting rid of this message:
```
WARNING: Node v18.12.0 is not tested against Ember CLI on your platform. We recommend that you use the most-recent "Active LTS" version of Node.js. See https://git.io/v7S5n for details.
```
---
`@ember/string` dependency is added for future compatibility. See: https://github.com/ember-cli/ember-cli/pull/10125
---
`tests/helpers/index.js` is unused for now, but is a nice pattern. We could move some of our test setup into local `setupApplicationTest/setupRenderingTest/setupTest` helpers.
Co-authored-by: David Taylor <david@taylorhq.com>
All supported browsers use `transitionend` event now, so this code is not necessary and makes it difficult to use that event in tests (you'd have to trigger all variants to cover the bases)
That function was used only in core (no hits in all-the*) in two places, so I think it's rather safe to just trash it without deprecating it first.
(History Corner – this helper was originally added in the initial commit of Discourse! 1839614bcc/app/assets/javascripts/discourse/components/transition_helper.js.coffee)
Following a change in e9f7262813 which prevents the notification level to be returned from the update endpoint, the model couldn't update itself. This commit makes the update manually and adds a test to prevent future regressions.
Note we could also change the backend endpoint, but this should work correctly with minimum risk.
This feature will allow sites to define which emoji are not allowed. Emoji in this list should be excluded from the set we show in the core emoji picker used in the composer for posts when emoji are enabled. And they should not be allowed to be chosen to be added to messages or as reactions in chat.
This feature prevents denied emoji from appearing in the following scenarios:
- topic title and page title
- private messages (topic title and body)
- inserting emojis into a chat
- reacting to chat messages
- using the emoji picker (composer, user status etc)
- using search within emoji picker
It also takes into account the various ways that emojis can be accessed, such as:
- emoji autocomplete suggestions
- emoji favourites (auto populates when adding to emoji deny list for example)
- emoji inline translations
- emoji skintones (ie. for certain hand gestures)
EmberObject's `reopen` feature allows changes to be made to the prototype of the class, but it does not work with native class fields. Native class field values are set on the instance in the constructor, and therefore override any values from the prototype.
This commit implements a workaround which detects possible field overrides and then sets the values during the `init()` function of the EmberObject. This isn't perfect - old field values will still be present while any constructor function is running. But in the vast majority of cases, it should provide parity with old non-native-class EmberObject properties.
This commit also adds a warning when trying to override fields on non-EmberObject classes. There is no change in behavior here - we're just warning about the fact it doesn't work.
When running `yarn install` in a yarn workspace, the lifecycle hooks in the root package.json are not triggered. https://github.com/yarnpkg/yarn/issues/5790
As a workaround, we can additionally run `patch-package` from the `javascripts/discourse/package.json` `postinstall` hook. `patch-package` is idempotent, so it doesn't matter if it is triggered multiple times.
Longer term we intend to move to pnpm, which has built-in patch support.
Fixes the unnecessary message when starting ember server:
```
Invalid watchman found, version: [2023.04.03.00] did not satisfy [>= 3.0.0].
Visit https://ember-cli.com/user-guide/#watchman for more info.
```
Moves a couple things from discourse-boot.js to a different JS file imported from app/app.js.
This is a forwards compatible technique to import and throw data on the window.
One thing to make note of, though, is that if the virtual-dom and discourse-widget-hbs/helpers were previously included in the build elsewhere, they will now become part of the app bundle.
Later, when using embroider, all bundles will be chunks, and webpack will optimize which chunk contains which modules appropriately.
When selecting the "Keep bookmark" in the user preference for what to do after a bookmark reminder is sent, it does not propagate to the drop-down in the "Create bookmark" modal. Instead it defaults to "Keep bookmark and clear reminder". All other options work fine.
We set a default ("Keep bookmark and clear reminder") if no user preference is found, However, this uses the index of the option, and the index of the first option ("Keep bookmark") is 0, which is treated as falsey in JavaScript, thus causing the default to be selected.
This change switches from logical "or" conditional `||` operator to nullish coalescing `??` operator.
Previously, public custom sections were only visible to logged-in users. In this PR, we are making them visible to anonymous as well.
The reason is that Community Section will be moved into custom section model to be easily editable by admins.