Skip to content
Draft
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e8fef6a
Remove entire exclusion functionality
Robbendebiene Jun 5, 2022
eccea39
Minor code adjustments
Robbendebiene Jun 5, 2022
e8ccf64
Convert JSON config files to JS modules
Robbendebiene Jun 22, 2022
470452e
Allow comma values for command font size
Robbendebiene Aug 27, 2022
82cbf78
Replace png icons with svg icon
Robbendebiene Aug 27, 2022
5009927
Redesign gesture search
Robbendebiene Jan 1, 2023
aba3162
Migrate manifest to version 3
Robbendebiene Jun 5, 2023
e0d7d40
Add deactivated icon
Robbendebiene Jun 5, 2023
9ce0764
Migrate commands to new scripting API
Robbendebiene Jun 5, 2023
31f3d81
Move data management actions to "extras" page
Robbendebiene Jun 19, 2023
f42af65
Make use of new background scripts module support
Robbendebiene Sep 2, 2023
31ad7e4
Create separate data tab in options page
Robbendebiene Oct 5, 2023
039ab36
Add initial browser action popup implementation
Robbendebiene May 23, 2024
9d00bce
Add separate exclusion service
Robbendebiene Jun 4, 2024
b061df4
Move config manager to service directory
Robbendebiene Jun 4, 2024
19300a7
Add host permission service and introduce base event listener service
Robbendebiene Jul 3, 2024
c1374b8
Display permission state in the browser action icon
Robbendebiene Jul 3, 2024
7b55b05
Update exclusion service
Robbendebiene Jul 5, 2024
27c9cfc
Improve host permission test function
Robbendebiene Jul 5, 2024
ac06d0c
Bring back exclusion functionality to content scripts
Robbendebiene Jul 5, 2024
78b2d64
Fix restricted page warning
Robbendebiene Jul 5, 2024
88194dc
Merge branch 'master' into port-to-manifest-v3
Robbendebiene Aug 4, 2024
a654ee5
Combine command functions and specification into new class format
Robbendebiene Apr 3, 2025
7294876
Add orderable custom element
Robbendebiene Apr 27, 2025
3eb04cf
Add collapsible custom element
Robbendebiene Apr 27, 2025
2394c70
Replace custom clone function with native function
Robbendebiene Sep 19, 2025
ca2ad22
Add new command stack model
Robbendebiene Sep 19, 2025
541b8a1
Improve collapsible-item custom element
Robbendebiene Sep 21, 2025
0d832e6
Proxy command class to prevent default settings override
Robbendebiene Sep 30, 2025
4ac7408
Rename collapsible-item file
Robbendebiene Nov 17, 2025
9790cce
Rename file and fix orderable-collection
Robbendebiene Nov 17, 2025
2d472a3
Add group attribute to collapsible-item
Robbendebiene Nov 17, 2025
45e5246
Add reusable element builder function
Robbendebiene Nov 17, 2025
13668b6
Add first iteration of new command picker
Robbendebiene Nov 18, 2025
8d5a0fd
Add custom element to ease localization
Robbendebiene Nov 18, 2025
dcc1e30
Replace old collapse code with new collapsible-item
Robbendebiene Nov 20, 2025
aa5b1fa
Introduce a shared theme.css file
Robbendebiene Nov 20, 2025
645652f
Migrate most px values to rem/em
Robbendebiene Nov 20, 2025
7079709
Move and simplify fetchHTMLAsFragment function
Robbendebiene Nov 20, 2025
d6de0b4
Replace legacy module path builder with built-in resolver function
Robbendebiene Nov 21, 2025
12e851b
Split code into custom pattern-preview element
Robbendebiene Nov 22, 2025
d4f4b01
Move code into a gesture card component
Robbendebiene Nov 30, 2025
0bfd48e
Fix data section functionality
Robbendebiene Dec 2, 2025
0a8c004
Multiple smaller corrections
Robbendebiene Dec 4, 2025
0e2e6c9
Move all mouse gesture controller callbacks to the end of the executi…
Robbendebiene Dec 4, 2025
2eac686
Add custom element pattern-recorder
Robbendebiene Dec 5, 2025
96d35c0
Split command picker into two separate custom elements
Robbendebiene Dec 9, 2025
3b20a70
Add form validation to custom elements
Robbendebiene Dec 10, 2025
9654b26
Reworked gesture popup
Robbendebiene Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[<img align="right" src="https://img.shields.io/github/license/robbendebiene/gesturefy.svg">](https://github.com/Robbendebiene/Gesturefy/blob/master/LICENSE)


# <sub><img src="https://github.com/Robbendebiene/Gesturefy/blob/master/src/resources/img/iconx48.png" height="38" width="38"></sub>esturefy
# <sub><img src="https://github.com/Robbendebiene/Gesturefy/blob/master/src/resources/img/icon.svg" height="38" width="38"></sub>esturefy

#### [<img height="60" align="right" src="https://blog.mozilla.org/addons/files/2020/04/get-the-addon-fx-apr-2020.svg">](https://addons.mozilla.org/firefox/addon/gesturefy/) Navigate, operate, and browse faster with mouse gestures! A customizable Firefox mouse gesture add-on with a variety of different commands.

Expand Down
296 changes: 202 additions & 94 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
"message": "Extras",
"description": "Extras"
},
"navigationExclusions": {
"message": "Exclusions",
"description": "Exclusions"
"navigationData": {
"message": "Data",
"description": "Data"
},
Comment on lines +40 to 43
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -n "navigationExclusions" --type=js --type=ts --type=json --type=html

Repository: Robbendebiene/Gesturefy

Length of output: 2102


🏁 Script executed:

rg -n "navigationData|navigationExclusions" --type=js --type=ts --type=html

Repository: Robbendebiene/Gesturefy

Length of output: 180


Navigation key rename from navigationExclusions to navigationData is incomplete—only the English locale was updated.

The code in src/views/options/index.html:48 references the new key navigationData, and src/_locales/en/messages.json has been updated accordingly. However, all 33 other locale files (de, fr, es_ES, it_IT, ja_JP, ko_KR, pt_BR, ru, zh_CN, zh_TW, etc.) still contain the old navigationExclusions key. This will cause the extension to fail for non-English locales. Update all locale files to use navigationData instead of navigationExclusions.

🤖 Prompt for AI Agents
In src/_locales/en/messages.json lines 40-43 and across the other locale files
under src/_locales/*/messages.json, the localization key was partially renamed
to navigationData (English only) while the other 33 locales still use
navigationExclusions; update each locale file to replace the
navigationExclusions key with navigationData preserving the existing "message"
and "description" values and JSON structure (i.e., rename the key only, do not
change the messages), then run a quick JSON lint or project build to ensure no
syntax errors.

"navigationAbout": {
"message": "About",
Expand Down Expand Up @@ -289,44 +289,106 @@
"description": "The minimal amount the mouse wheel must be scrolled until the gesture is triggered."
},

"exclusionsLabelInformation": {
"message": "Information:",
"description": "Information:"
"dataLabelFileBackup": {
"message": "Backup to file",
"description": "Backup to file"
},
"exclusionsTextInformation": {
"message": "Add URL match patterns to disable Gesturefy for certain websites. The match pattern allows \"*\" wildcards and must be in the form of <scheme>://<host><path>.",
"description": "Add URL match patterns to disable Gesturefy for certain websites. The match pattern allows \"*\" wildcards and must be in the form of <scheme>://<host><path>."
"dataLabelFileRestore": {
"message": "Restore from file",
"description": "Restore from file"
},
"exclusionsPlaceholderURL": {
"message": "Enter URL match pattern",
"description": "Enter URL match pattern"
"dataLabelCloudBackup": {
"message": "Backup to cloud",
"description": "Backup to cloud"
},
"exclusionsAddButton": {
"message": "Add",
"description": "Add"
"dataLabelCloudRestore": {
"message": "Restore from cloud",
"description": "Restore from cloud"
},
"exclusionsNotificationAlreadyExists": {
"message": "URL pattern already exists.",
"description": "URL pattern already exists."
"dataLabelResetConfig": {
"message": "Reset configuration",
"description": "Reset configuration"
},
"exclusionsHintNoEntries": {
"message": "No entries available",
"description": "No entries available"

"dataDescriptionFileBackup": {
"message": "Stores the settings and gestures in a config file.",
"description": "Stores the settings and gestures in a config file."
},
"dataDescriptionFileRestore": {
"message": "Loads a previously stored config file.",
"description": "Loads a previously stored config file."
},
"dataDescriptionCloudBackup": {
"message": "Stores the settings and gestures in the cloud of the browser account.",
"description": "Stores the settings and gestures in the cloud of the browser account."
},
"dataDescriptionCloudRestore": {
"message": "Loads previously uploaded settings and gestures from the cloud of the browser account.",
"description": "Loads previously uploaded settings and gestures from the cloud of the browser account."
},
"dataDescriptionResetConfig": {
"message": "Resets all settings and gestures to their defaults.",
"description": "Resets all settings and gestures to their defaults."
},

"aboutBackup": {
"dataBackup": {
"message": "Backup",
"description": "Backup"
},
"aboutRestore": {
"dataRestore": {
"message": "Restore",
"description": "Restore"
},
"aboutReset": {
"dataCloudUpload": {
"message": "Upload",
"description": "Upload"
},
"dataCloudDownload": {
"message": "Download",
"description": "Download"
},
"dataReset": {
"message": "Reset",
"description": "Reset"
},

"dataRestoreNotificationNoConfigFile": {
"message": "The selected file is not a valid Gesturefy config file.",
"description": "The selected file is not a valid Gesturefy config file."
},
"dataRestoreNotificationWrongFile": {
"message": "The selected file does not match the required file type.",
"description": "The selected file does not match the required file type."
},
"dataRestoreNotificationConfirm": {
"message": "All settings and gestures will be replaced by the selected config file.",
"description": "All settings and gestures will be replaced by the selected config file."
},
"dataRestoreNotificationSuccess": {
"message": "The selected configuration has been successfully restored.",
"description": "The selected configuration has been successfully restored."
},
"dataUploadNotificationConfirm": {
"message": "Your existing configuration in the cloud will be overridden by the current configuration.",
"description": "Your existing configuration in the cloud will be overridden by the current configuration."
},
"dataUploadNotificationSuccess": {
"message": "The current configuration has been successfully saved to the cloud storage. It will be available to other devices once the data is synced by the browser.",
"description": "The current configuration has been successfully saved to the cloud storage. It will be available to other devices once the data is synced by the browser."
},
"dataDownloadNotificationConfirm": {
"message": "All settings and gestures will be replaced with the configuration from the cloud.",
"description": "All settings and gestures will be replaced with the configuration from the cloud."
},
"dataDownloadNotificationSuccess": {
"message": "The configuration from the cloud has been successfully restored.",
"description": "The configuration from the cloud has been successfully restored."
},
"dataResetNotificationConfirm": {
"message": "All settings and gestures will be reset. This cannot be undone!",
"description": "All settings and gestures will be reset. This cannot be undone!"
},

"aboutLicense": {
"message": "License:",
"description": "License:"
Expand All @@ -348,27 +410,6 @@
"description": "Add-on page"
},

"aboutRestoreNotificationNoConfigFile": {
"message": "The selected file is not a valid Gesturefy config file.",
"description": "The selected file is not a valid Gesturefy config file."
},
"aboutRestoreNotificationWrongFile": {
"message": "The selected file does not match the required file type.",
"description": "The selected file does not match the required file type."
},
"aboutRestoreNotificationConfirm": {
"message": "All settings including gestures will be replaced by the selected config file.",
"description": "All settings including gestures will be replaced by the selected config file."
},
"aboutRestoreNotificationSuccess": {
"message": "The selected config has been successfully restored.",
"description": "The selected config has been successfully restored."
},
"aboutResetNotificationConfirm": {
"message": "All settings including gestures will be reset. This cannot be undone!",
"description": "All settings including gestures will be reset. This cannot be undone!"
},

"commandLabelToggleBookmark": {
"message": "Toggle bookmark",
"description": "Toggle bookmark"
Expand Down Expand Up @@ -1287,10 +1328,6 @@
"message": "Custom match pattern",
"description": "Custom match pattern"
},
"commandSettingLabelCommandSelection": {
"message": "Command selection",
"description": "Command selection"
},
"commandSettingLabelBrowsingDataCache": {
"message": "Cache",
"description": "Cache"
Expand Down Expand Up @@ -1452,10 +1489,6 @@
"message": "A pattern in the form of a regular expression to match a specific part of a string. If omitted an internal pattern is used.",
"description": "A pattern in the form of a regular expression to match a specific part of a string. If omitted an internal pattern is used."
},
"commandSettingDescriptionCommandSelection": {
"message": "A custom selection of multiple commands.",
"description": "A custom selection of multiple commands."
},

"commandErrorNotificationTitle": {
"message": "\"$COMMAND$\" command failed.",
Expand Down Expand Up @@ -1484,38 +1517,51 @@
"description": "Gesturefy does not have permission for incognito mode. Click here for more information."
},

"commandBarTitle": {
"message": "Command bar",
"description": "Command bar"
"commandPickerAddMainCommandButton": {
"message": "Add main command",
"description": "Add main command"
},
"commandBarSearch": {
"message": "Search",
"description": "Search"
"commandPickerAddAlternativeCommandButton": {
"message": "Add alternative command",
"description": "Add alternative command"
},
"commandPickerFilterPlaceholder": {
"message": "Filter commands",
"description": "Filter commands"
},
"commandBarAdditionalPermissionsText": {
"commandPickerNoResultsPlaceholder": {
"message": "No commands found",
"description": "No commands found"
},
"commandPickerAdditionalPermissionsText": {
"message": "This command requires additional permissions: ",
"description": "This command requires additional permissions: "
},
"commandBarAdditionalSettingsText": {
"message": "This command has additional settings.",
"description": "This command has additional settings."
"commandPickerMainCommandLabel": {
"message": "Main command",
"description": "Main command"
},
"commandBarOpenSelectionText": {
"message": "Open command selection.",
"description": "Open command selection."
"commandPickerAlternativeCommandLabel": {
"message": "Alternative command",
"description": "Alternative command"
},
"commandBarOpenSettingsText": {
"message": "Open command settings.",
"description": "Open command settings."
"commandPickerMainCommandDescription": {
"message": "This command is executed first.",
"description": "This command is executed first."
},

"commandMultiSelectAddPlaceholder": {
"message": "Add",
"description": "Add"
},
"commandMultiSelectNoResultsPlaceholder": {
"message": "No results",
"description": "No results"
"commandPickerAlternativeCommandDescription": {
"message": "\"$THIS_COMMAND$\" is executed if the previous command \"$PREVIOUS_COMMAND$\" has no effect.",
"description": "\"Close tab\" is executed if the previous command \"Scroll to the top\" has no effect.",
"placeholders": {
"this_command" : {
"content" : "$1",
"example" : "Close tab"
},
"previous_command" : {
"content" : "$2",
"example" : "Scroll to the top"
}
}
},

"gesturePopupTitleNewGesture": {
Expand Down Expand Up @@ -1548,29 +1594,21 @@
"message": "middle",
"description": "This will replace the placeholder in \"Use the $MOUSEBUTTON$ mouse button to record a new gesture.\""
},
"gesturePopupLabelCommand": {
"message": "Command",
"description": "Command"
"gesturePopupLabelMouseMovement": {
"message": "Mouse movement",
"description": "Mouse movement"
},
"gesturePopupLabelGestureDirections": {
"message": "Gesture directions",
"description": "Gesture directions"
"gesturePopupLabelCommands": {
"message": "Command(s)",
"description": "Command(s)"
},
"gesturePopupLabelOptionalLabel": {
"message": "Label (optional)",
"description": "Label (optional)"
},
"gesturePopupDescriptionCommand": {
"message": "Choose a command that should be assigned to this gesture.",
"description": "Choose a command that should be assigned to this gesture."
},
"gesturePopupDescriptionGestureDirections": {
"message": "Either use the arrow keys to enter the directions, or record them in the area next to it.",
"description": "Either use the arrow keys to enter the directions, or record them in the area next to it."
},
"gesturePopupDescriptionOptionalLabel": {
"message": "Assign a custom name that will be displayed instead of the command name.",
"description": "Assign a custom name that will be displayed instead of the command name."
"message": "Assign a custom name that will be displayed instead of the main command name.",
"description": "Assign a custom name that will be displayed instead of the main command name."
},
"gesturePopupNotificationSimilarGesture": {
"message": "This gesture is similar to the \"$GESTURE_NAME$\" gesture.",
Expand All @@ -1583,6 +1621,29 @@
}
},

"gestureFormValidationMissingGesture": {
"message": "No gesture has been recorded yet.",
"description": "No gesture has been recorded yet."
},
"gestureFormValidationInvalidGesture": {
"message": "The recorded gesture is invalid.",
"description": "The recorded gesture is invalid."
},
"gestureFormValidationMissingCommand": {
"message": "No command has been assigned yet.",
"description": "No command has been assigned yet."
},
"gestureFormValidationInvalidCommandSetting": {
"message": "A setting of the \"$COMMAND_NAME$\" command is invalid.",
"description": "A setting of the \"$COMMAND_NAME$\" command is invalid.",
"placeholders": {
"command_name" : {
"content" : "$1",
"example" : "New Tab"
}
}
},

"permissionLabelTabs": {
"message": "Tabs",
"description": "Tabs"
Expand Down Expand Up @@ -1699,5 +1760,52 @@
"welcomePageLowerSectionLearnMoreLink": {
"message": "Learn More",
"description": "Learn More"
},

"popupProhibitedPageWarning": {
"message": "Add-ons are prohibited on this page",
"description": "Add-ons are prohibited on this page"
},
"popupMissingPermissionButton": {
"message": "Gesturefy requires additional permissions",
"description": "Gesturefy requires additional permissions"
},
"popupMissingPermissionButtonTooltip": {
"message": "Click to request necessary permissions and enable Gesturefy.",
"description": "Click to request necessary permissions and enable Gesturefy."
},
"popupExclusionsToggleButton": {
"message": "Allow gestures on $DOMAIN$",
"description": "Allow gestures on $DOMAIN$",
"placeholders": {
"domain" : {
"content" : "$1",
"example" : "www.example.com"
}
}
},
"popupExclusionsToggleButtonOffTooltip": {
"message": "Click to enable Gesturefy on $DOMAIN$",
"description": "Click to enable Gesturefy on $DOMAIN$",
"placeholders": {
"domain" : {
"content" : "$1",
"example" : "www.example.com"
}
}
},
"popupExclusionsToggleButtonOnTooltip": {
"message": "Click to disable Gesturefy on $DOMAIN$",
"description": "Click to disable Gesturefy on $DOMAIN$",
"placeholders": {
"domain" : {
"content" : "$1",
"example" : "www.example.com"
}
}
},
"popupOpenSettingsButton": {
"message": "Open settings",
"description": "Open settings"
}
}
}
Loading