Skip to content

feat: added functionality to remove saved user preferences#472

Merged
sergeleger merged 12 commits into
mainfrom
dev.swl/462-clear-user-preferences
Nov 21, 2025
Merged

feat: added functionality to remove saved user preferences#472
sergeleger merged 12 commits into
mainfrom
dev.swl/462-clear-user-preferences

Conversation

@sergeleger

@sergeleger sergeleger commented Nov 14, 2025

Copy link
Copy Markdown
Collaborator

PR Goal?

Removing stored user preferences required:

to clear browsing data for the site, in which case you also lose your privacy opt-out or opt-in setting for analytics.

this PR adds a "Reset" button to the settings panel that will reset all configurations (including deleting the stored settings).

Fixes?

#462

Feedback sought?

  • implementation works as intended.
  • feedback on UI elements in the settings page (new Reset button, and new location of "save preferences" button)
  • feedback on new En / Fr / Sp messages in i18n/ folder.

Also, additional minor improvements to the settings modal window:

  • version paragraph had a cursor pointer (giving the impression that it could be clicked) - removed
  • added dark mode CSS for the language select box, the previous implementation had very low contrast (black text on blue background)
  • the escape key did not always close the settings window.
    • a quick test: click on an empty section of the settings window: escape would not work
  • language names in select box are now displayed in their native language (English, Francais, Espanol) regardless of the user's current language choice.

Priority?

Medium, non blocker.

Tests added?

Yes

How to test?

Documented steps from the issue #472:

Other:

  • Reset can be used even if no settings have been saved, an easy way to set the defaults.

Confidence?

High.

Version change?

@semanticdiff-com

semanticdiff-com Bot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor
PR Preview Action v1.6.3
Preview removed because the pull request was closed.
2025-11-21 11:16 UTC

@joanise joanise left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well when I test it.
I have some questions, see below.

I didn't dig enough to understand why most instances of this.X had to be replaced by this.userPreferences.X but it works.

I didn't test if we can still change settings in the html as attributes to the read-along element and have them reflected when you load a readalong. Did you exercise that?

Finally, I'm leaving comments but I'm not confident enough to really review, @deltork I'm hoping you'll do a code review too.

Comment thread packages/web-component/src/i18n/messages.spa.json Outdated
Comment thread packages/web-component/src/components/read-along-component/read-along.tsx Outdated
*/
@Prop({ mutable: true, reflect: true }) scrollBehaviour: ScrollBehaviour =
"smooth";
@Prop() scrollBehaviour: ScrollBehaviour = "smooth";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a while to figure out why this was still used -- it appears to just be the thing that sets the default. Is this also what gets modified if you set it in the HTML?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it contains the value passed in the HTML <read-along scroll-behaviour="..." />, if this attribute (or property) is not used, it defaults to "smooth".

Answering the question about this.X vs this.userPreferences.X here also: this.X contains the initial state of the component, either the hard-coded value or the attribute value passed in <read-along />. The previous implementation directly modified this.X overwriting the component's initial state. This refactor makes this.X read-only and it is used only for setting the component's initial state and clearing the users's preferences (see: defaultUserPreferences() where this.X is used) .

} else if (this.language.match("es") !== null) {
this.language = "spa";
if (prefs.language.length < 3) {
if (prefs.language.match("fr") != null) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird code. Why not prefs.language !== "fr"? @deltork ? Is this case insensitive?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows the app to support both ISO 639-3 and ISO 639-1 ("fra" and "fr") for maximum compatibility.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it case insensitive

Suggested change
if (prefs.language.match("fr") != null) {
if (prefs.language.match(/fr/i) != null) {

@sergeleger

Copy link
Copy Markdown
Collaborator Author

I didn't test if we can still change settings in the html as attributes to the read-along element and have them reflected when you load a readalong. Did you exercise that?

If I'm understanding the use-case correctly something along the lines of?

const el = document.getElementById("readalongInstance");
el.scrollBehaviour = "auto";

Currently would not work. Neither would this:

const el = document.getElementById("readalongInstance");
if(el.scrollBehaviour == "auto") {
...
}

In the first case it would take effect only when/if the user performs a "Reset". In the second, the value returned would always reflect the component's initial state and not the current user defined preference. Both can be addressed.

Is there an example of this or a test?

@sergeleger sergeleger force-pushed the dev.swl/462-clear-user-preferences branch from c03c9c8 to acf6526 Compare November 17, 2025 13:07
@joanise

joanise commented Nov 17, 2025

Copy link
Copy Markdown
Member

What I meant by "setting the attributes" is right in the HTML itself, someone publishing a readalongs could set language="fra" or the scrolling parameter etc. I think all the use cases are covered by examples in packages/web-component/test-data/ej-fra/*.html so I suppose if CI exercises those, then they're already tested.

@joanise

joanise commented Nov 17, 2025

Copy link
Copy Markdown
Member

Thanks for the changes. Looks good to me, but I'll let Del approve once he's done his review.

@sergeleger

Copy link
Copy Markdown
Collaborator Author

Yes, that has been implemented and manually tested. Values passed in HTML become the component's default values when "Reset" is used.

@sergeleger sergeleger force-pushed the dev.swl/462-clear-user-preferences branch from 5a7bd60 to 4e5b399 Compare November 18, 2025 11:58
@deltork

deltork commented Nov 18, 2025

Copy link
Copy Markdown
Collaborator

I have a minor tweak for the settings UI. see #475.
Otherwise everything looks good to me.

@deltork deltork left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review and merge #475 into this

} else if (this.language.match("es") !== null) {
this.language = "spa";
if (prefs.language.length < 3) {
if (prefs.language.match("fr") != null) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows the app to support both ISO 639-3 and ISO 639-1 ("fra" and "fr") for maximum compatibility.

} else if (this.language.match("es") !== null) {
this.language = "spa";
if (prefs.language.length < 3) {
if (prefs.language.match("fr") != null) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it case insensitive

Suggested change
if (prefs.language.match("fr") != null) {
if (prefs.language.match(/fr/i) != null) {

if (prefs.language.length < 3) {
if (prefs.language.match("fr") != null) {
prefs.language = "fra";
} else if (prefs.language.match("es") !== null) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if (prefs.language.match("es") !== null) {
} else if (prefs.language.match(/es/i) !== null) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some != with just one equal in there, should they not all be !==?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we convert this to a data structure? Regex feels like an over kill and in this case not specific enough (abc_fr_abc would be accepted for French):

const acceptedLanguages = {
"en": "eng",
"eng": "eng",
"fr": "fra",
"fra": "fra",
"es": "spa",
"spa": "spa",
}
prefs.language = acceptedLanguages[prefs.language.toLowerCase()]||"eng";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not quite accurate since the code is in a if block where len<3... which also points to overkill. :)

I like your map, though, seems like a good idea. In Python, [] with an unfound value would raise an exception, here would that return a falsy result instead?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some != with just one equal in there, should they not all be !==?

yeh they should be !==

@sergeleger sergeleger Nov 20, 2025

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not quite accurate since the code is in a if block where len<3... which also points to overkill. :)

Oops, I assumed there was an else clause hiding in all the short diff blocks. Since there are none, there's no 3-character language validation either. But getI18nString handles the bad language input.

I like your map, though, seems like a good idea. In Python, [] with an unfound value would raise an exception, here would that return a falsy result instead?

That's correct, and the || "eng" returns English in those cases (it does not throw an exception).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update the language validation code after Del merges PR #475 (which I've just accepted).

@sergeleger sergeleger force-pushed the dev.swl/462-clear-user-preferences branch from 8902cd5 to 21491d1 Compare November 20, 2025 17:51

@deltork deltork left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

@sergeleger sergeleger merged commit 8768407 into main Nov 21, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants