Skip to content

Commit 197a5ad

Browse files
committed
refactor(skills): Phase 2.1 - Extract ui5-best-practices references
Extracted 3 largest sections to progressive disclosure references: 1. test-starter-guide.md (115 lines) - Modern test setup patterns (UI5 >= 1.113.0) - testsuite.qunit.html/js structure - QUnit 2+ configuration - Istanbul code coverage 2. csp-directive-reference.md (89 lines) - Complete CSP directive table - Library-specific requirements - Report-Only testing workflow - Compliance checklist 3. xml-event-handling-guide.md (87 lines) - core:require module loading - Parameter passing patterns - Special models ($parameters, $source, $event, $controller) - "this" context control with .call() Main skill file: - Before: 862 lines - After: 663 lines - Reduction: -199 lines (-23%) All sections replaced with: - Essential pattern examples - Quick reference tables - Links to complete guides Tests: ✅ All structure tests passing
1 parent 744acae commit 197a5ad

4 files changed

Lines changed: 342 additions & 250 deletions

File tree

plugins/ui5-guidelines/skills/ui5-best-practices/SKILL.md

Lines changed: 51 additions & 250 deletions
Original file line numberDiff line numberDiff line change
@@ -402,89 +402,29 @@ const oButton = new Button({
402402

403403
## 11. XML Event Handling Patterns
404404

405-
### Event Handler Addressing
405+
**Overview**: UI5 XML views support sophisticated event handler binding with parameter passing, special named models ($parameters, $source, $event, $controller), and context control.
406406

407-
**Dot Notation (Controller Methods)**
408-
```xml
409-
<!-- ✅ Relative to controller -->
410-
<Button text="Save" press=".onSave"/>
411-
```
412-
The leading dot means: `attachPress(oController["onSave"], oController)`
413-
414-
**core:require Modules**
415-
```xml
416-
<Button core:require="{Util: 'my/app/util/Util'}"
417-
text="Process"
418-
press="Util.handleProcess"/>
419-
```
420-
421-
**AVOID**: Global function names (legacy, not recommended)
422-
423-
### Passing Parameters to Event Handlers
424-
425-
**JavaScript Literals**
426-
```xml
427-
<Button press=".doSomething('string', 0, 5.5, {key1: 'value1'}, ['val1', 'val2'])"/>
428-
```
429-
430-
**Model Property Access**
431-
```xml
432-
<!-- Binding syntax: ${...} -->
433-
<Button press=".onItemClick(${products>unitPrice})"/>
434-
```
435-
436-
**Expression Binding**
437-
```xml
438-
<Button press=".doCheck(${products>type} === 'Laptop')"/>
439-
<Button press=".format(10 * ${products>unitPrice})"/>
440-
<Button press=".onPrice(${path: 'price', formatter: '.formatPrice'})"/>
441-
```
442-
443-
### Special Named Models
407+
### Essential Patterns
444408

445-
#### $parameters - Event Parameters
409+
**Dot Notation for Controller Methods**:
446410
```xml
447-
<Select change=".onChange(${$parameters>/selectedItem})"/>
448-
```
449-
Access event parameters without the event object.
450-
451-
#### $source - Control Firing Event
452-
```xml
453-
<Button press=".onPress(${$source>/text})"/>
454-
```
455-
Wraps the control as a `ManagedObjectModel`.
456-
457-
#### $event - Original Event Object
458-
```xml
459-
<Button press=".onPress($event)"/>
411+
<Button text="Save" press=".onSave"/>
460412
```
461-
Explicitly pass event object when parameters are specified.
462413

463-
#### $controller - Controller Reference
414+
**Parameter Passing**:
464415
```xml
465-
<!-- For handlers NOT in controller -->
466-
<Button core:require="{Helper: 'my/app/Helper'}"
467-
press="Helper.doSomething($controller)"/>
416+
<Button press=".doSomething(${/productId}, ${view>/mode}, $event)"/>
468417
```
469418

470-
### The "this" Context Rules
419+
**Special Models**:
420+
- `$parameters` - Access event parameters
421+
- `$source` - Access the event source control
422+
- `$event` - Reference the event object
423+
- `$controller` - Access controller properties
471424

472-
**Without parameters**: `this` is always the controller
473-
```xml
474-
<Button press=".doSomething"/> <!-- this = controller -->
475-
```
425+
### Complete Guide
476426

477-
**With parameters**: `this` is the object owning the handler
478-
```xml
479-
<Button press=".doSomething('param')"/> <!-- this = controller -->
480-
<Button core:require="{Util: 'util'}" press="Util.handle('p')"/> <!-- this = Util -->
481-
```
482-
483-
**Override context with .call()**
484-
```xml
485-
<Button core:require="{Helper: 'helper'}"
486-
press="Helper.doSomething.call($controller, 'Hello')"/>
487-
```
427+
For comprehensive XML event patterns including core:require, JavaScript literals, model property access, "this" context control with .call(), and complex examples, see [references/xml-event-handling-guide.md](references/xml-event-handling-guide.md).
488428

489429
## 12. Component Metadata for UI5 Version Detection
490430

@@ -571,205 +511,66 @@ public static metadata = {
571511

572512
## 13. Content Security Policy (CSP) - Directive Reference
573513

574-
### Required CSP Directives for UI5 (Version 1.136.7)
575-
576-
**Minimal Restrictive Policy**
577-
```
578-
Content-Security-Policy:
579-
script-src 'self' <ui5-cdn>;
580-
style-src 'self' <ui5-cdn>;
581-
img-src 'self' data: blob: <ui5-cdn>;
582-
font-src 'self' data: <ui5-cdn>;
583-
connect-src 'self' <backend-api>;
584-
frame-src 'self' data: blob:;
585-
worker-src 'self' data: blob:;
586-
```
587-
588-
### Directive Breakdown
589-
590-
#### script-src
591-
- **'self'** - Application resources
592-
- **&lt;ui5-cdn&gt;** - UI5 framework source
593-
- **'unsafe-eval'** - Required ONLY for:
594-
- Synchronous loading (deprecated, avoid)
595-
- Legacy libraries: `sap.ca.ui`, `sap.makit`, `sap.me`, `sap.ui.commons`, `sap.ui.ux3`, `sap.uiext.inbox`, `sap.viz.*`, `sap.zen.*`
596-
- Partially required: `sap.apf`, `sap.ovp`, `sap.ushell`, `sap.rules.ui`
597-
598-
#### style-src
599-
- **'self'** - Application styles
600-
- **&lt;ui5-cdn&gt;** - UI5 themes
601-
- **'unsafe-inline'** - Required for:
602-
- Same legacy libraries as script-src
603-
- Controls with inline styles: `sap.m.FormattedText`, `sap.ui.core.HTML`
604-
- Partially required: `sap.gantt`, `sap.ui.vk`, `sap.ushell`
605-
606-
#### img-src, font-src
607-
- **data:** - Inline images/fonts (UI5 features)
608-
- **blob:** - Dynamically generated content
514+
**Overview**: CSP protects against XSS by controlling resource sources. UI5 applications must configure specific directives for framework libraries.
609515

610-
#### worker-src / child-src
611-
- Required for UI5 web workers
612-
- **blob:** may be needed for specific functionality
516+
### Essential Directives
613517

614-
#### connect-src
615-
- **'self'** - Application APIs
616-
- **&lt;backend-api&gt;** - OData services, REST endpoints
617-
- **wss:** - WebSocket connections (specific features)
518+
| Directive | Purpose | Required Values |
519+
|-----------|---------|----------------|
520+
| `script-src` | JavaScript sources | `'self'`, `'unsafe-eval'` (for some libs) |
521+
| `style-src` | CSS sources | `'self'`, `'unsafe-inline'` (for theming) |
522+
| `font-src` | Font sources | `'self'`, `data:` |
523+
| `img-src` | Image sources | `'self'`, `https:`, `data:` |
618524

619-
### Testing CSP Policies
525+
### Quick Example
620526

621-
**Report-Only Mode** (Recommended for testing)
622-
```
623-
Content-Security-Policy-Report-Only:
624-
script-src 'self';
625-
style-src 'self';
626-
report-uri /csp-violation-report;
527+
```html
528+
<meta http-equiv="Content-Security-Policy"
529+
content="default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'">
627530
```
628531

629-
1. Start with most restrictive policy
630-
2. Monitor violation reports
631-
3. Add required sources iteratively
632-
4. Switch to enforce mode once stable
633-
634-
### CSP Compliance Dos and Don'ts
635-
636-
**DO**:
637-
- ✅ Use external stylesheets (no inline styles)
638-
- ✅ Use async loading (`data-sap-ui-async="true"`)
639-
- ✅ Leverage library preloads
640-
- ✅ Use `ComponentSupport` for initialization
641-
642-
**DON'T**:
643-
- ❌ Use `<script>` with inline code
644-
- ❌ Use inline event handlers (`onclick="..."`)
645-
- ❌ Use `javascript:` URLs
646-
- ❌ Use `document.write()` or `createElement('script')` for inline scripts
647-
- ❌ Use `eval()`, `new Function()`, `setTimeout(<string>)`
532+
### Complete Reference
648533

649-
### Library-Specific CSP Issues
650-
651-
**sap.ui.richtexteditor**
652-
- Requires `script-src 'unsafe-inline'` for plugins: `linkchecker`, `preview`
653-
654-
**sap.ui.core (Hyphenation)**
655-
- Requires `script-src 'wasm-unsafe-eval'` for WebAssembly
656-
657-
**sap.ushell**
658-
- Requires `script-src 'unsafe-eval'` for App Finder and custom tiles
534+
For the full directive table, library-specific requirements (sap.ui.richtexteditor, sap.ushell), Report-Only testing workflow, and compliance checklist, see [references/csp-directive-reference.md](references/csp-directive-reference.md).
659535

660536
## 14. Modern Test Setup (Test Starter)
661537

662-
### Overview
538+
**Overview**: Test Starter (UI5 >= 1.113.0) provides a modern test orchestration pattern with testsuite.qunit.html/js, individual test files, and optional code coverage.
663539

664-
UI5 Test Starter simplifies QUnit/OPA5 test orchestration for UI5 1.136.7+:
665-
666-
**Benefits**:
667-
- Reduces boilerplate code
668-
- Ensures async loading of testing frameworks
669-
- CSP-compliant test setup
670-
- Centralized configuration
540+
### Essential Structure
671541

672-
### Test Suite Structure
673-
674-
**testsuite.qunit.html**
675-
```html
676-
<!DOCTYPE html>
677-
<html>
678-
<head>
679-
<title>Test Suite for my.app</title>
680-
<script src="../resources/sap/ui/qunit/qunit-redirect.js"></script>
681-
</head>
682-
<body></body>
683-
</html>
684542
```
685-
686-
**testsuite.qunit.js**
687-
```javascript
688-
window.suite = function() {
689-
const suite = new parent.jsUnitTestSuite();
690-
const contextPath = location.pathname.substring(0, location.pathname.lastIndexOf("/") + 1);
691-
692-
suite.addTestPage(contextPath + "unit/unitTests.qunit.html");
693-
suite.addTestPage(contextPath + "integration/opaTests.qunit.html");
694-
695-
return suite;
696-
};
543+
webapp/test/
544+
├── testsuite.qunit.html # Entry point
545+
├── testsuite.qunit.js # Test suite configuration
546+
└── unit/
547+
├── AllTests.js # Test registry
548+
└── controller/
549+
└── Main.controller.test.js
697550
```
698551

699-
### Individual Test Files
552+
### Quick Example (testsuite.qunit.js)
700553

701-
**unit/unitTests.qunit.html**
702-
```html
703-
<!DOCTYPE html>
704-
<html>
705-
<head>
706-
<meta charset="utf-8">
707-
<title>Unit Tests</title>
708-
<script
709-
id="sap-ui-bootstrap"
710-
src="../../resources/sap-ui-core.js"
711-
data-sap-ui-resource-roots='{"my.app": "../../"}'
712-
data-sap-ui-async="true">
713-
</script>
714-
<script src="unitTests.qunit.js"></script>
715-
</head>
716-
<body><div id="qunit"></div></body>
717-
</html>
718-
```
719-
720-
**unit/unitTests.qunit.js**
721554
```javascript
722-
sap.ui.require([
723-
"sap/ui/test/Opa5",
724-
"sap/ui/qunit/utils/createAndAppendDiv",
725-
"my/app/test/unit/model/formatter"
726-
], function(Opa5, createAndAppendDiv) {
555+
sap.ui.define(function() {
727556
"use strict";
728-
729-
createAndAppendDiv("content");
730-
731-
QUnit.start();
557+
return {
558+
name: "QUnit test suite",
559+
defaults: {
560+
page: "ui5://test-resources/{name}.qunit.html"
561+
},
562+
tests: {
563+
"unit/AllTests": {
564+
title: "Unit Tests"
565+
}
566+
}
567+
};
732568
});
733569
```
734570

735-
### Configuration Options
736-
737-
**QUnit Version**
738-
```javascript
739-
// In test HTML
740-
<script src="../../resources/sap/ui/thirdparty/qunit-2.js"></script>
741-
```
742-
743-
**Sinon.JS Version**
744-
```javascript
745-
// In test HTML
746-
<script src="../../resources/sap/ui/thirdparty/sinon-4.js"></script>
747-
```
571+
### Complete Guide
748572

749-
**Coverage (Istanbul)**
750-
```javascript
751-
// In test HTML (UI5 >= 1.113)
752-
<script src="../../resources/sap/ui/qunit/qunit-coverage-istanbul.js"></script>
753-
```
754-
755-
### Migration from Legacy Setup
756-
757-
**Before (Legacy)**
758-
```javascript
759-
jQuery.sap.require("sap.ui.qunit.qunit-css");
760-
jQuery.sap.require("sap.ui.thirdparty.qunit");
761-
jQuery.sap.require("sap.ui.qunit.qunit-junit");
762-
```
763-
764-
**After (Test Starter)**
765-
```javascript
766-
// No manual requires - handled by test starter
767-
sap.ui.require([
768-
"my/app/test/unit/AllTests"
769-
], function() {
770-
QUnit.start();
771-
});
772-
```
573+
For full Test Starter patterns, QUnit 2+ configuration, Istanbul code coverage setup (UI5 >= 1.113.0), and migration from legacy test setup, see [references/test-starter-guide.md](references/test-starter-guide.md).
773574

774575
## 15. Validation Checklist
775576

0 commit comments

Comments
 (0)