-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JS to TS: src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts #425
base: main
Are you sure you want to change the base?
JS to TS: src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts #425
Conversation
WalkthroughThe changes involve migrating the keyboard shortcut management functionality from a JavaScript implementation to a TypeScript implementation. The new version introduces type definitions and interfaces to enhance type safety and provide more structured shortcut management. The core functionality remains similar, with methods for adding, removing, and managing keyboard shortcuts, but now with improved type annotations and more explicit type checking. Changes
Sequence DiagramsequenceDiagram
participant User
participant ShortcutManager
participant EventListener
User->>ShortcutManager: Define shortcut
ShortcutManager->>EventListener: Attach event listener
User->>EventListener: Trigger key combination
EventListener->>ShortcutManager: Validate shortcut
alt Shortcut matches
ShortcutManager->>User: Execute callback
else Shortcut does not match
EventListener->>User: No action
end
Poem
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
❌ Deploy Preview for circuitverse failed.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (5)
src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts (5)
1-18
: Add TypeScript-specific documentation.While the existing documentation covers usage restrictions well, consider adding:
- Type information for key parameters
- Examples of valid shortcut combinations using TypeScript
- Return type documentation
19-25
: Improve type safety for target property.Instead of using
string
for the target property, consider using a more specific type likeHTMLElement['id']
to ensure only valid element IDs are passed.- target?: Document | string + target?: Document | HTMLElement['id']
52-55
: Replace type assertion with type guard.Instead of using type assertion, implement a type guard for better type safety.
-let ele: Document | HTMLElement = options.target as Document | HTMLElement -if (typeof options.target === 'string') { - ele = document.getElementById(options.target) || document -} +const isDocumentTarget = (target: ShortcutOptions['target']): target is Document => + target instanceof Document + +let ele: Document | HTMLElement +if (typeof options.target === 'string') { + ele = document.getElementById(options.target) || document +} else { + ele = isDocumentTarget(options.target) ? options.target : document +}
164-170
: Modernize event listener attachment.The code uses older event attachment methods for compatibility. Consider modernizing this with a proper fallback strategy.
- if (ele.addEventListener) { - ele.addEventListener(options.type || 'keydown', func, false) - } else if ((ele as any).attachEvent) { - (ele as any).attachEvent('on' + (options.type || 'keydown'), func) - } else { - (ele as any)['on' + (options.type || 'keydown')] = func - } + const eventType = options.type || 'keydown' + try { + ele.addEventListener(eventType, func, false) + } catch (error) { + console.warn(`Failed to attach event listener: ${error}`) + // Fallback for older browsers + try { + (ele as any).attachEvent?.('on' + eventType, func) + } catch (fallbackError) { + console.error(`Event listener attachment failed: ${fallbackError}`) + } + }
38-40
: Consider adding cleanup method for memory management.The
all_shortcuts
object could grow indefinitely. Consider adding a method to clean up unused shortcuts and prevent memory leaks.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/simulator/src/hotkey_binder/model/shortcuts.plugin.js
(0 hunks)src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts
(1 hunks)
💤 Files with no reviewable changes (1)
- src/simulator/src/hotkey_binder/model/shortcuts.plugin.js
let element = e.target as HTMLElement | ||
if (element.nodeType === 3) element = element.parentNode as HTMLElement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add null check for element.parentNode.
The parentNode access could potentially be null, which should be handled.
-if (element.nodeType === 3) element = element.parentNode as HTMLElement
+if (element.nodeType === 3 && element.parentNode) {
+ element = element.parentNode as HTMLElement
+} else if (element.nodeType === 3) {
+ return
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
let element = e.target as HTMLElement | |
if (element.nodeType === 3) element = element.parentNode as HTMLElement | |
let element = e.target as HTMLElement | |
if (element.nodeType === 3 && element.parentNode) { | |
element = element.parentNode as HTMLElement | |
} else if (element.nodeType === 3) { | |
return | |
} |
removeAll: function (): void { | ||
Object.keys(this.all_shortcuts).forEach(x => { | ||
this.remove(x) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling to removeAll method.
The removeAll method should continue removing shortcuts even if one fails.
removeAll: function (): void {
- Object.keys(this.all_shortcuts).forEach(x => {
- this.remove(x)
- })
+ const failures: string[] = []
+ Object.keys(this.all_shortcuts).forEach(shortcut => {
+ try {
+ this.remove(shortcut)
+ } catch (error) {
+ failures.push(shortcut)
+ console.error(`Failed to remove shortcut ${shortcut}: ${error}`)
+ }
+ })
+ if (failures.length > 0) {
+ console.warn(`Failed to remove ${failures.length} shortcuts: ${failures.join(', ')}`)
+ }
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
removeAll: function (): void { | |
Object.keys(this.all_shortcuts).forEach(x => { | |
this.remove(x) | |
}) | |
} | |
removeAll: function (): void { | |
const failures: string[] = [] | |
Object.keys(this.all_shortcuts).forEach(shortcut => { | |
try { | |
this.remove(shortcut) | |
} catch (error) { | |
failures.push(shortcut) | |
console.error(`Failed to remove shortcut ${shortcut}: ${error}`) | |
} | |
}) | |
if (failures.length > 0) { | |
console.warn(`Failed to remove ${failures.length} shortcuts: ${failures.join(', ')}`) | |
} | |
} |
remove: function (shortcut_combination: string): void { | ||
shortcut_combination = shortcut_combination.toLowerCase() | ||
const binding = this.all_shortcuts[shortcut_combination] | ||
|
||
if (binding) { | ||
const { target, callback, event } = binding | ||
|
||
if (target.removeEventListener) { | ||
target.removeEventListener(event, callback) | ||
} else if ((target as any).detachEvent) { | ||
(target as any).detachEvent('on' + event, callback) | ||
} else { | ||
(target as any)['on' + event] = null | ||
} | ||
|
||
delete this.all_shortcuts[shortcut_combination] | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling to remove method.
The remove method should handle cases where the binding doesn't exist gracefully.
remove: function (shortcut_combination: string): void {
shortcut_combination = shortcut_combination.toLowerCase()
const binding = this.all_shortcuts[shortcut_combination]
if (binding) {
const { target, callback, event } = binding
+ try {
if (target.removeEventListener) {
target.removeEventListener(event, callback)
} else if ((target as any).detachEvent) {
(target as any).detachEvent('on' + event, callback)
} else {
(target as any)['on' + event] = null
}
+ } catch (error) {
+ console.warn(`Failed to remove event listener: ${error}`)
+ }
delete this.all_shortcuts[shortcut_combination]
+ } else {
+ console.warn(`No binding found for shortcut: ${shortcut_combination}`)
}
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
remove: function (shortcut_combination: string): void { | |
shortcut_combination = shortcut_combination.toLowerCase() | |
const binding = this.all_shortcuts[shortcut_combination] | |
if (binding) { | |
const { target, callback, event } = binding | |
if (target.removeEventListener) { | |
target.removeEventListener(event, callback) | |
} else if ((target as any).detachEvent) { | |
(target as any).detachEvent('on' + event, callback) | |
} else { | |
(target as any)['on' + event] = null | |
} | |
delete this.all_shortcuts[shortcut_combination] | |
} | |
}, | |
remove: function (shortcut_combination: string): void { | |
shortcut_combination = shortcut_combination.toLowerCase() | |
const binding = this.all_shortcuts[shortcut_combination] | |
if (binding) { | |
const { target, callback, event } = binding | |
try { | |
if (target.removeEventListener) { | |
target.removeEventListener(event, callback) | |
} else if ((target as any).detachEvent) { | |
(target as any).detachEvent('on' + event, callback) | |
} else { | |
(target as any)['on' + event] = null | |
} | |
} catch (error) { | |
console.warn(`Failed to remove event listener: ${error}`) | |
} | |
delete this.all_shortcuts[shortcut_combination] | |
} else { | |
console.warn(`No binding found for shortcut: ${shortcut_combination}`) | |
} | |
}, |
Fixes #414
@niladrix719 @JoshVarga @Arnabdaz @devartstar
Summary by CodeRabbit
Refactor
Documentation