Skip to content

Commit 9255893

Browse files
committed
Enhance documentation for JavaScript Patterns and Tab Pages with best practices on selector scoping, menu placement, and initialization timing to prevent conflicts when adding tabs to existing Unraid pages.
1 parent a004fd4 commit 9255893

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

docs/ui/javascript-patterns.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,46 @@ $(document).on('keydown.mymodal', function(e) {
577577

578578
## Best Practices
579579

580+
### Scope Your Selectors
581+
582+
When your plugin adds a tab to an existing Unraid page (like adding a tab to the Docker menu), your JavaScript runs in the same context as that page's JavaScript. Unscoped selectors can accidentally target elements from the parent page, causing visual glitches or broken functionality.
583+
584+
Common classes like `.auto_start`, `.advanced`, `.basic`, and `.updatecolumn` are used by multiple Unraid pages. jQuery plugins like `switchButton` should never be re-initialized on elements that are already set up.
585+
586+
```javascript
587+
// BAD - Selects ALL .auto_start elements on the page
588+
// If Docker tab already initialized these, you'll break them
589+
$('.auto_start').switchButton({labels_placement:'right', on_label:'On', off_label:'Off'});
590+
591+
// BAD - Toggles ALL .advanced elements, including Docker tab's columns
592+
$('.advanced').toggle();
593+
594+
// GOOD - Scope to your plugin's container
595+
$('#myplugin_table .auto_start').switchButton({labels_placement:'right', on_label:'On', off_label:'Off'});
596+
597+
// GOOD - Only affect your plugin's elements
598+
$('#myplugin_table .advanced').toggle();
599+
$('#myplugin_table .basic').toggle();
600+
```
601+
602+
For elements added to shared areas (like the tab bar), use plugin-specific class names:
603+
604+
```javascript
605+
// BAD - 'advancedview' class may conflict with Docker tab's toggle
606+
$(".tabs").append('<span class="status"><input type="checkbox" class="advancedview"></span>');
607+
$('.advancedview').switchButton({...});
608+
609+
// GOOD - unique class name prevents conflicts
610+
$(".tabs").append('<span class="status"><input type="checkbox" class="myplugin-advancedview"></span>');
611+
$('.myplugin-advancedview').switchButton({...});
612+
$('.myplugin-advancedview').change(function(){
613+
// Only toggle your plugin's elements
614+
$('#myplugin_table .advanced').toggle();
615+
});
616+
```
617+
618+
See [Tab Pages - Adding Tabs to Existing Pages](tab-pages.md#adding-tabs-to-existing-pages) for more details.
619+
580620
### Namespace Your Timers
581621

582622
Unraid's core JavaScript uses a global `timers` object to manage intervals and timeouts. If your plugin declares `var timers = {}`, you'll overwrite Unraid's object and break functionality like auto-refresh and status polling. Always use a plugin-specific name like `myPluginTimers` to avoid this collision.

docs/ui/tab-pages.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,81 @@ TODO: Document the Menu numbering system for related pages
190190
- Consider user workflow when ordering tabs
191191
- Save tab state for better UX
192192

193+
## Adding Tabs to Existing Pages
194+
195+
Plugins can add new tabs to existing Unraid pages (like the Docker page) using the `Menu` header in `.page` files. This creates a seamless integrated experience but requires careful attention to avoid conflicts.
196+
197+
### Menu Placement
198+
199+
To add a tab to an existing menu, use the menu name with an optional sort order:
200+
201+
```
202+
# Add to Docker page as second tab
203+
Menu="Docker:2"
204+
Title="Compose"
205+
Type="php"
206+
```
207+
208+
### Selector Scoping
209+
210+
{: .warning }
211+
> When your plugin adds a tab to an existing Unraid page, your JavaScript will run in the same context as the parent page's JavaScript. You **must** scope your CSS selectors to avoid conflicts.
212+
213+
Common classes like `.auto_start`, `.advanced`, `.basic`, and `.updatecolumn` are used by multiple Unraid pages. If your plugin uses these same classes and initializes jQuery plugins on them (like `switchButton`), you'll inadvertently reinitialize or modify elements that belong to the parent page.
214+
215+
**Problem - Unscoped selectors:**
216+
217+
```javascript
218+
// BAD - This selects ALL .auto_start on the page, including Docker tab's checkboxes
219+
$('.auto_start').switchButton({labels_placement:'right'});
220+
221+
// BAD - This toggles ALL .advanced elements, affecting Docker tab too
222+
$('.advanced').toggle();
223+
```
224+
225+
**Solution - Scope to your container:**
226+
227+
```javascript
228+
// GOOD - Only select checkboxes within your plugin's table
229+
$('#my_plugin_table .auto_start').switchButton({labels_placement:'right'});
230+
231+
// GOOD - Only toggle your plugin's advanced columns
232+
$('#my_plugin_table .advanced').toggle();
233+
```
234+
235+
### Use Unique Class Names
236+
237+
For elements that need to be globally unique (like an Advanced View toggle in the tab bar), use plugin-specific class names:
238+
239+
```javascript
240+
// BAD - may conflict with Docker tab's advancedview toggle
241+
$(".tabs").append('<span class="status"><input type="checkbox" class="advancedview"></span>');
242+
$('.advancedview').switchButton({...});
243+
244+
// GOOD - unique class name avoids conflicts
245+
$(".tabs").append('<span class="status myplugin-view-toggle"><input type="checkbox" class="myplugin-advancedview"></span>');
246+
$('.myplugin-advancedview').switchButton({...});
247+
```
248+
249+
### Initialization Timing
250+
251+
When adding a tab to an existing page, that page's JavaScript typically runs first and initializes its own UI components. Your plugin's async content loading can conflict if not properly scoped:
252+
253+
```javascript
254+
// Load content asynchronously, then initialize
255+
function loadMyPluginContent() {
256+
$.get('/plugins/myplugin/content.php', function(data) {
257+
$('#myplugin_content').html(data);
258+
259+
// Initialize ONLY your plugin's elements
260+
$('#myplugin_content .auto_start').switchButton({...});
261+
$('#myplugin_content .auto_start').change(function(){
262+
// Handle change
263+
});
264+
});
265+
}
266+
```
267+
193268
## Related Topics
194269

195270
- [Page Files]({% link docs/page-files.md %})

0 commit comments

Comments
 (0)