Skip to content

Commit c82fde2

Browse files
committed
Non destructive class assignments for styling registry
1 parent 2714e0d commit c82fde2

File tree

12 files changed

+180
-168
lines changed

12 files changed

+180
-168
lines changed

src/core/styling.registry.ts

Lines changed: 87 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ export type ClassNames = string[] | ((...args: any[]) => string[]);
66
* A style associates a name with a list of CSS class names.
77
*/
88
export interface Style {
9-
name: string;
10-
classNames: ClassNames;
9+
name: string;
10+
classNames: ClassNames;
1111
}
1212

1313
/**
@@ -17,103 +17,103 @@ export interface Style {
1717
*/
1818
export interface StylingRegistry {
1919

20-
/**
21-
* Register a style.
22-
* If a style with the given name already exists, it will be overwritten.
23-
*
24-
* @param styleName the name of the style
25-
* @param classNames CSS class names to be applied
26-
*/
27-
register(styleName: string, classNames: string[]): void;
28-
29-
/**
30-
* Register a style.
31-
* If a style with the given name already exists, it will be overwritten.
32-
*
33-
* @param style the style to be registered
34-
*/
35-
register(style: Style): void;
36-
37-
/**
38-
* Register multiple styles at once.
39-
*
40-
* @param styles an array of styles to be registered
41-
*/
42-
registerMany(styles: Style[]): void;
43-
44-
/**
45-
* Deregister a style.
46-
*
47-
* @param styleName the name of the style to be un-registered
48-
*/
49-
deregister(styleName: string): void;
50-
51-
/**
52-
* Obtain the CSS class name associated with the given style name.
53-
* @param styleName the name whose CSS class names should be obtained
54-
* @return {Array<String>} an array containing the CSS class names,
55-
* if the style exists, an empty array otherwise
56-
*/
57-
get(styleName: string, ...args: any[]): string[];
58-
59-
/**
60-
* Obtain the CSS class name associated with the given style name.
61-
* @param styleName the name whose CSS class names should be obtained
62-
* @return a string containing the CSS class name separated by whitespace, if the style exists,
63-
* empty string otherwise
64-
*/
65-
getAsClassName(styleName: string, ...args: any[]): string;
20+
/**
21+
* Register a style.
22+
* If a style with the given name already exists, it will be overwritten.
23+
*
24+
* @param styleName the name of the style
25+
* @param classNames CSS class names to be applied
26+
*/
27+
register(styleName: string, classNames: string[]): void;
28+
29+
/**
30+
* Register a style.
31+
* If a style with the given name already exists, it will be overwritten.
32+
*
33+
* @param style the style to be registered
34+
*/
35+
register(style: Style): void;
36+
37+
/**
38+
* Register multiple styles at once.
39+
*
40+
* @param styles an array of styles to be registered
41+
*/
42+
registerMany(styles: Style[]): void;
43+
44+
/**
45+
* Deregister a style.
46+
*
47+
* @param styleName the name of the style to be un-registered
48+
*/
49+
deregister(styleName: string): void;
50+
51+
/**
52+
* Add a style to the given HTML element. A style is association with a list of CSS classes
53+
* to be assigned to the given HTML element
54+
*
55+
* @param {HTMLElement} html the element to which a style should be applied
56+
* @param {string} styleName the style name to be applied
57+
* @param args any additional arguments necessary for calculating a list of CSS classes to be applied
58+
* @returns {this} the styling registry for convenience reasons
59+
*/
60+
addStyle(html: Element, styleName: string, ...args: any[]): StylingRegistry;
6661
}
6762

6863
/**
6964
* Styling registry implementation.
7065
*/
7166
export class StylingRegistryImpl implements StylingRegistry {
7267

73-
constructor(protected styles: Style[] = []) {
68+
constructor(protected styles: Style[] = []) {
7469

75-
}
76-
77-
register(style: Style): void;
78-
register(name: string, classNames: ClassNames): void;
79-
register(style: string|Style, classNames?: string[]): void {
80-
if (typeof style === 'string') {
81-
this.deregister(style);
82-
this.styles.push({name: style, classNames});
83-
} else {
84-
this.deregister(style.name);
85-
this.styles.push(style);
86-
}
87-
}
88-
89-
registerMany(styles: Style[]) {
90-
styles.forEach(style => {
91-
this.register(style.name, style.classNames);
92-
});
93-
}
70+
}
9471

95-
deregister(styleName: any) {
96-
_.remove(this.styles, style => style.name === styleName);
72+
register(style: Style): void;
73+
register(name: string, classNames: ClassNames): void;
74+
register(style: string|Style, classNames?: string[]): void {
75+
if (typeof style === 'string') {
76+
this.deregister(style);
77+
this.styles.push({name: style, classNames});
78+
} else {
79+
this.deregister(style.name);
80+
this.styles.push(style);
9781
}
98-
99-
get(styleName: string, ...args: any[]): string[] {
100-
const foundStyle = _.find(this.styles, style => style.name === styleName);
101-
if (!_.isEmpty(foundStyle) && typeof foundStyle.classNames === 'function') {
102-
return foundStyle.classNames(args);
103-
} else if (!_.isEmpty(foundStyle)) {
104-
return (foundStyle.classNames as string[]);
105-
}
106-
107-
return [];
82+
}
83+
84+
registerMany(styles: Style[]) {
85+
styles.forEach(style => {
86+
this.register(style.name, style.classNames);
87+
});
88+
}
89+
90+
deregister(styleName: any) {
91+
_.remove(this.styles, style => style.name === styleName);
92+
}
93+
94+
95+
/**
96+
* Obtain the CSS class name associated with the given style name.
97+
* @param styleName the name whose CSS class names should be obtained
98+
* @param args any additional arguments necessary for calculating a list of CSS classes to be applied
99+
* @return {Array<String>} an array containing the CSS class names,
100+
* if the style exists, an empty array otherwise
101+
*/
102+
get(styleName: string, ...args: any[]): string[] {
103+
const foundStyle = _.find(this.styles, style => style.name === styleName);
104+
if (!_.isEmpty(foundStyle) && typeof foundStyle.classNames === 'function') {
105+
return foundStyle.classNames(args);
106+
} else if (!_.isEmpty(foundStyle)) {
107+
return (foundStyle.classNames as string[]);
108108
}
109109

110-
getAsClassName(styleName: string, ...args: any[]): string {
111-
const styles = this.get(styleName, args);
112-
if (_.isEmpty(styles)) {
113-
return '';
114-
}
110+
return [];
111+
}
115112

116-
return _.join(styles, ' ');
117-
}
113+
addStyle(html: Element, styleName: string, ...args: any[]): StylingRegistry {
114+
const styles = this.get(styleName, args);
115+
styles.forEach(style => html.classList.add(style));
118116

117+
return this;
118+
}
119119
}

src/json-forms.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ export class JsonFormsElement extends HTMLElement {
162162
const bestRenderer = JsonForms.rendererService
163163
.findMostApplicableRenderer(uiSchema, schema, this.dataService);
164164
this.appendChild(bestRenderer);
165-
this.className = JsonForms.stylingRegistry.getAsClassName('json-forms');
166-
165+
JsonForms.stylingRegistry.addStyle(this, 'json-forms');
167166
this.dataService.initDataChangeListeners();
168167
}
169168

src/renderers/additional/array-renderer.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,25 +88,20 @@ export class ArrayControlRenderer extends Renderer implements DataChangeListener
8888
* @inheritDoc
8989
*/
9090
render(): HTMLElement {
91-
this.className = JsonForms.stylingRegistry.getAsClassName('control');
9291
if (this.lastChild !== null) {
9392
this.removeChild(this.lastChild);
9493
}
9594
const controlElement = this.uischema as ControlElement;
9695
const div = document.createElement('fieldset');
97-
div.className = JsonForms.stylingRegistry.getAsClassName('array.layout');
98-
9996
const header = document.createElement('legend');
10097
div.appendChild(header);
10198
const label = document.createElement('label');
102-
label.className = JsonForms.stylingRegistry.getAsClassName('array.label');
10399
const labelObject = getElementLabelObject(this.dataSchema, controlElement);
104100
if (labelObject.show) {
105101
label.textContent = labelObject.text;
106102
}
107103

108104
const content = document.createElement('div');
109-
content.className = JsonForms.stylingRegistry.getAsClassName('array.children');
110105
let arrayData = this.dataService.getValue(controlElement);
111106

112107
const renderChild = (element: Object): void => {
@@ -125,7 +120,6 @@ export class ArrayControlRenderer extends Renderer implements DataChangeListener
125120
div.appendChild(content);
126121

127122
const button = document.createElement('button');
128-
button.className = JsonForms.stylingRegistry.getAsClassName('array.button');
129123
button.textContent = `+`;
130124
button.onclick = (ev: Event) => {
131125
if (arrayData === undefined) {
@@ -143,6 +137,12 @@ export class ArrayControlRenderer extends Renderer implements DataChangeListener
143137
this.appendChild(div);
144138
this.classList.add(this.convertToClassName(controlElement.scope.$ref));
145139

140+
JsonForms.stylingRegistry.addStyle(this, 'control')
141+
.addStyle(div, 'array.layout')
142+
.addStyle(label, 'array.label')
143+
.addStyle(content, 'array.children')
144+
.addStyle(button, 'array.button');
145+
146146
return this;
147147
}
148148
}

src/renderers/additional/categorization-renderer.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,17 @@ export class CategorizationRenderer extends Renderer {
8585
* @inheritDoc
8686
*/
8787
render(): HTMLElement {
88-
this.className = JsonForms.stylingRegistry.getAsClassName('categorization');
89-
9088
this.master = document.createElement('div');
91-
this.master.className = JsonForms.stylingRegistry.getAsClassName('categorization.master');
9289
this.appendChild(this.master);
9390

9491
this.detail = document.createElement('div');
95-
this.detail.className = JsonForms.stylingRegistry.getAsClassName('categorization.detail');
9692
this.appendChild(this.detail);
9793

94+
JsonForms.stylingRegistry
95+
.addStyle(this, 'categorization')
96+
.addStyle(this.master, 'categorization.master')
97+
.addStyle(this.detail, 'categorization.detail');
98+
9899
this.renderFull();
99100

100101
return this;
@@ -141,8 +142,11 @@ export class CategorizationRenderer extends Renderer {
141142
// span.innerText
142143
if (isCategorization(category)) {
143144
const innerUl = this.createCategorizationList(category);
144-
innerUl.className = JsonForms.stylingRegistry.getAsClassName('category.subcategories');
145-
li.className = JsonForms.stylingRegistry.getAsClassName('category.group');
145+
146+
JsonForms.stylingRegistry
147+
.addStyle(innerUl, 'category.subcategories')
148+
.addStyle(li, 'category.group');
149+
146150
li.appendChild(innerUl);
147151
} else {
148152
li.onclick = (ev: Event) => {

src/renderers/additional/label.renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class LabelRenderer extends Renderer {
3232
if (labelElement.text !== undefined && labelElement.text !== null) {
3333
this.textContent = labelElement.text;
3434
}
35-
this.className = JsonForms.stylingRegistry.getAsClassName('label-control');
35+
JsonForms.stylingRegistry.addStyle(this, 'label-control');
3636

3737
return this;
3838
}

src/renderers/additional/table-array.control.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,14 @@ export class TableArrayControlRenderer extends Renderer implements DataChangeLis
9191
const header = document.createElement('header');
9292
this.appendChild(header);
9393
const label = document.createElement('label');
94-
label.className = JsonForms.stylingRegistry.getAsClassName('array-table.label');
9594
const labelObject = getElementLabelObject(this.dataSchema, controlElement);
9695
if (labelObject.show) {
9796
label.textContent = labelObject.text;
9897
}
9998
header.appendChild(label);
10099

101100
const content = document.createElement('table');
102-
this.className = JsonForms.stylingRegistry.getAsClassName('array-table.table');
101+
JsonForms.stylingRegistry.addStyle(this, 'array-table.table');
103102
const head = document.createElement('thead');
104103
const headRow = document.createElement('tr');
105104
const resolvedSchema = resolveSchema(this.dataSchema, controlElement.scope.$ref + '/items');
@@ -145,7 +144,6 @@ export class TableArrayControlRenderer extends Renderer implements DataChangeLis
145144
this.appendChild(content);
146145

147146
const button = document.createElement('button');
148-
button.className = JsonForms.stylingRegistry.getAsClassName('array-table.button');
149147
button.textContent = `Add to ${labelObject.text}`;
150148
button.onclick = (ev: Event) => {
151149
if (arrayData === undefined) {
@@ -158,7 +156,11 @@ export class TableArrayControlRenderer extends Renderer implements DataChangeLis
158156
};
159157

160158
header.appendChild(button);
161-
this.className = JsonForms.stylingRegistry.getAsClassName('array-table');
159+
160+
JsonForms.stylingRegistry.addStyle(label, 'array-table.label')
161+
.addStyle(button, 'array-table.button')
162+
.addStyle(this, 'array-table');
163+
162164
this.classList.add(this.convertToClassName(controlElement.scope.$ref));
163165

164166
return this;

src/renderers/controls/base.control.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,19 @@ export abstract class BaseControl <T extends HTMLElement>
3737
render(): HTMLElement {
3838
const controlElement = this.uischema as ControlElement;
3939
this.createLabel(controlElement);
40-
this.label.className = JsonForms.stylingRegistry.getAsClassName('control.label');
4140
this.createInput(controlElement);
42-
this.input.className = JsonForms.stylingRegistry.getAsClassName('control.input');
4341
this.errorElement = document.createElement('div');
44-
this.errorElement.className = JsonForms.stylingRegistry.getAsClassName('control.validation');
4542
this.appendChild(this.label);
4643
this.appendChild(this.input);
4744
this.appendChild(this.errorElement);
48-
this.className = JsonForms.stylingRegistry.getAsClassName('control');
4945
this.classList.add(this.convertToClassName(controlElement.scope.$ref));
5046

47+
JsonForms.stylingRegistry
48+
.addStyle(this, 'control')
49+
.addStyle(this.label, 'control.label')
50+
.addStyle(this.input, 'control.input')
51+
.addStyle(this.errorElement, 'control.validation');
52+
5153
return this;
5254
}
5355

src/renderers/controls/boolean.control.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ export class BooleanControl extends BaseControl<HTMLInputElement> {
2626
const controlElement = this.uischema as ControlElement;
2727
this.createInput(controlElement);
2828
this.createLabel(controlElement);
29-
this.label.className = JsonForms.stylingRegistry.getAsClassName('control.label');
30-
this.input.className = JsonForms.stylingRegistry.getAsClassName('control.input');
3129
this.errorElement = document.createElement('div');
32-
this.errorElement.className = JsonForms.stylingRegistry.getAsClassName('control.validation');
3330
this.appendChild(this.input);
3431
this.appendChild(this.label);
3532
this.appendChild(this.errorElement);
36-
this.className = JsonForms.stylingRegistry.getAsClassName('control');
3733
this.classList.add(this.convertToClassName(controlElement.scope.$ref));
3834

35+
JsonForms.stylingRegistry
36+
.addStyle(this, 'control')
37+
.addStyle(this.label, 'control.label')
38+
.addStyle(this.input, 'control.input')
39+
.addStyle(this.errorElement, 'control.validation');
40+
3941
return this;
4042
}
4143
protected configureInput(input: HTMLInputElement): void {

0 commit comments

Comments
 (0)