pict-section-form 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example_applications/gradebook/Gradebook-Application.js +29 -12
- package/example_applications/gradebook/GradebookData.json +8 -28
- package/package.json +2 -2
- package/source/providers/dynamictemplates/Pict-DynamicTemplates-DefaultFormTemplates.js +10 -0
- package/source/providers/inputs/Pict-Provider-Input-ObjectEditor.js +8 -2
- package/source/providers/layouts/Pict-Layout-Tabular.js +8 -2
- package/test/PictSectionForm-Tabular-Features_tests.js +105 -0
|
@@ -8,10 +8,20 @@
|
|
|
8
8
|
4. The column chooser via Group.ColumnChooser — a "Columns" menu of
|
|
9
9
|
checkboxes above the table; the hidden set lives in the form data
|
|
10
10
|
(<GroupHash>_HiddenColumns) so it survives a save/reload.
|
|
11
|
+
5. ONE record set, many tabular projections. The Students roster, the Grade
|
|
12
|
+
Book, the Performance breakdown and the Commentary grid ALL bind the same
|
|
13
|
+
"Students" array (each tab is just a different column projection of it via
|
|
14
|
+
its own RecordManifest). Because pict-section-form re-renders every tabular
|
|
15
|
+
group that shares a RecordSetAddress when a row is added / removed / moved,
|
|
16
|
+
adding a student on the roster tab makes that student appear on every other
|
|
17
|
+
tab automatically — no glue code, no sync solver. This is the "tabular rows
|
|
18
|
+
automatically map to a shared array" behavior. Per-assignment grades live at
|
|
19
|
+
Students[i].Grades.<IDAssignment> and notes at Students[i].Notes.<IDAssignment>,
|
|
20
|
+
so the dynamic Assignment columns hang off the same row object.
|
|
11
21
|
|
|
12
22
|
The host code itself does nothing interesting — it just wires a TabSectionSelector
|
|
13
|
-
for navigation, then defines
|
|
14
|
-
|
|
23
|
+
for navigation, then defines five tabular sections. All the behavior comes from
|
|
24
|
+
the manifest JSON below.
|
|
15
25
|
*/
|
|
16
26
|
|
|
17
27
|
const libPictSectionForm = require('../../source/Pict-Section-Form.js');
|
|
@@ -108,7 +118,7 @@ module.exports.default_configuration.pict_configuration = (
|
|
|
108
118
|
* - Extra header row (the "Assignments" banner) above the auto super-header.
|
|
109
119
|
* - Dynamic columns: one column per row of `Assignments`, with each
|
|
110
120
|
* descriptor's Name = the assignment title and the data stored at
|
|
111
|
-
* `
|
|
121
|
+
* `Students[rowIndex].Grades.<IDAssignment>` (preserved on hide).
|
|
112
122
|
* - HeaderGroupTemplate auto-extends Headers with a topic super-header
|
|
113
123
|
* row clustering consecutive same-topic columns.
|
|
114
124
|
* - RowSelection / ColumnSelection: check a row and/or a column to
|
|
@@ -131,11 +141,12 @@ module.exports.default_configuration.pict_configuration = (
|
|
|
131
141
|
"Hash": "GradebookGrid",
|
|
132
142
|
"Name": "Grade Book",
|
|
133
143
|
"Layout": "Tabular",
|
|
134
|
-
"RecordSetAddress": "
|
|
144
|
+
"RecordSetAddress": "Students",
|
|
135
145
|
"RecordManifest": "GradeRowEditor",
|
|
136
146
|
"RowSelection": true,
|
|
137
147
|
"ColumnSelection": true,
|
|
138
148
|
"ColumnChooser": true,
|
|
149
|
+
"ColumnSorting": true,
|
|
139
150
|
"Headers":
|
|
140
151
|
[
|
|
141
152
|
[
|
|
@@ -179,7 +190,7 @@ module.exports.default_configuration.pict_configuration = (
|
|
|
179
190
|
"Hash": "PerformanceGrid",
|
|
180
191
|
"Name": "Student Performance Breakdown",
|
|
181
192
|
"Layout": "Tabular",
|
|
182
|
-
"RecordSetAddress": "
|
|
193
|
+
"RecordSetAddress": "Students",
|
|
183
194
|
"RecordManifest": "GradeRowEditor",
|
|
184
195
|
"EditingControlsPosition": "hidden",
|
|
185
196
|
// Recomputes each row's average across its grade values whenever
|
|
@@ -217,9 +228,13 @@ module.exports.default_configuration.pict_configuration = (
|
|
|
217
228
|
/*
|
|
218
229
|
* One colortabularrow() call per student row. Each reads the row's
|
|
219
230
|
* `Average` and maps it to a band color: >=85 green, >=75 amber,
|
|
220
|
-
* else red.
|
|
221
|
-
*
|
|
222
|
-
*
|
|
231
|
+
* else red. These presentational solvers are keyed by row index and
|
|
232
|
+
* cover the eight seeded students. Adding a student still makes the
|
|
233
|
+
* new row appear on every tab (the shared "Students" record set does
|
|
234
|
+
* that automatically) — it just won't be color-banded until a matching
|
|
235
|
+
* row-index solver exists. A real app would generate one per row; the
|
|
236
|
+
* example keeps them explicit so the mechanism stays visible. Out-of-
|
|
237
|
+
* range solvers are a safe no-op, so extra rows simply render unbanded.
|
|
223
238
|
*/
|
|
224
239
|
"Solvers":
|
|
225
240
|
[
|
|
@@ -235,9 +250,11 @@ module.exports.default_configuration.pict_configuration = (
|
|
|
235
250
|
},
|
|
236
251
|
|
|
237
252
|
/*
|
|
238
|
-
* Tab 5 — Teacher commentary.
|
|
239
|
-
* `
|
|
240
|
-
*
|
|
253
|
+
* Tab 5 — Teacher commentary. Another projection of the shared
|
|
254
|
+
* `Students` array; the data store is `Students[].Notes[<IDAssignment>]`.
|
|
255
|
+
* Same DynamicColumns shape as the Grade Book, different
|
|
256
|
+
* InformaryDataAddress (Notes vs Grades) so the two grids hang their
|
|
257
|
+
* per-assignment cells off the same row object without colliding.
|
|
241
258
|
*/
|
|
242
259
|
{
|
|
243
260
|
"Hash": "Commentary",
|
|
@@ -248,7 +265,7 @@ module.exports.default_configuration.pict_configuration = (
|
|
|
248
265
|
"Hash": "CommentaryGrid",
|
|
249
266
|
"Name": "Teacher Commentary",
|
|
250
267
|
"Layout": "Tabular",
|
|
251
|
-
"RecordSetAddress": "
|
|
268
|
+
"RecordSetAddress": "Students",
|
|
252
269
|
"RecordManifest": "CommentaryRowEditor",
|
|
253
270
|
"Headers":
|
|
254
271
|
[
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"GradebookTab": "Gradebook"
|
|
4
4
|
},
|
|
5
5
|
"Students": [
|
|
6
|
-
{ "Section": "A", "StudentName": "Alice Carter",
|
|
7
|
-
{ "Section": "A", "StudentName": "Brian Diaz",
|
|
8
|
-
{ "Section": "A", "StudentName": "Carla Edwards",
|
|
9
|
-
{ "Section": "B", "StudentName": "Devon Fox",
|
|
10
|
-
{ "Section": "B", "StudentName": "Erika Gomez",
|
|
11
|
-
{ "Section": "B", "StudentName": "Felix Hayes",
|
|
12
|
-
{ "Section": "C", "StudentName": "Gabriela Ingram","StudentID": "S-007" },
|
|
13
|
-
{ "Section": "C", "StudentName": "Henry Jensen",
|
|
6
|
+
{ "Section": "A", "StudentName": "Alice Carter", "StudentID": "S-001", "Average": 89.43, "Grades": { "1": 95, "2": 88, "3": 91, "4": 84, "5": 76, "6": 100, "7": 92 }, "Notes": { "1": "Strong start", "3": "Great essay" } },
|
|
7
|
+
{ "Section": "A", "StudentName": "Brian Diaz", "StudentID": "S-002", "Average": 77.57, "Grades": { "1": 72, "2": 80, "3": 65, "4": 78, "5": 88, "6": 90, "7": 70 }, "Notes": { "5": "Needs practice on plot summary" } },
|
|
8
|
+
{ "Section": "A", "StudentName": "Carla Edwards", "StudentID": "S-003", "Average": 88.71, "Grades": { "1": 88, "2": 85, "3": 92, "4": 90, "5": 95, "6": 85, "7": 86 }, "Notes": {} },
|
|
9
|
+
{ "Section": "B", "StudentName": "Devon Fox", "StudentID": "S-004", "Average": 70.00, "Grades": { "1": 60, "2": 68, "3": 70, "4": 72, "5": 65, "6": 80, "7": 75 }, "Notes": { "1": "Borderline; offer extra worksheets" } },
|
|
10
|
+
{ "Section": "B", "StudentName": "Erika Gomez", "StudentID": "S-005", "Average": 89.57, "Grades": { "1": 90, "2": 92, "3": 85, "4": 88, "5": 89, "6": 95, "7": 88 }, "Notes": {} },
|
|
11
|
+
{ "Section": "B", "StudentName": "Felix Hayes", "StudentID": "S-006", "Average": 77.14, "Grades": { "1": 75, "2": 78, "3": 80, "4": 76, "5": 82, "6": 70, "7": 79 }, "Notes": {} },
|
|
12
|
+
{ "Section": "C", "StudentName": "Gabriela Ingram", "StudentID": "S-007", "Average": 87.43, "Grades": { "1": 82, "2": 90, "3": 88, "4": 85, "5": 91, "6": 92, "7": 84 }, "Notes": { "6": "Beautiful color work" } },
|
|
13
|
+
{ "Section": "C", "StudentName": "Henry Jensen", "StudentID": "S-008", "Average": 68.86, "Grades": { "1": 70, "2": 65, "3": 60, "4": 72, "5": 68, "6": 75, "7": 72 }, "Notes": { "3": "Struggling; schedule one-on-one" } }
|
|
14
14
|
],
|
|
15
15
|
"Assignments": [
|
|
16
16
|
{ "IDAssignment": 1, "Title": "Addition", "Topic": "Math", "Points": 100, "Weight": 1.0 },
|
|
@@ -20,25 +20,5 @@
|
|
|
20
20
|
{ "IDAssignment": 5, "Title": "Reading: A Wrinkle in Time", "Topic": "Reading", "Points": 100, "Weight": 1.0 },
|
|
21
21
|
{ "IDAssignment": 6, "Title": "Watercolor Practice", "Topic": "Art", "Points": 100, "Weight": 0.5 },
|
|
22
22
|
{ "IDAssignment": 7, "Title": "Short Essay", "Topic": "Writing", "Points": 100, "Weight": 1.5 }
|
|
23
|
-
],
|
|
24
|
-
"Grades": [
|
|
25
|
-
{ "Section": "A", "StudentName": "Alice Carter", "Average": 89.43, "Grades": { "1": 95, "2": 88, "3": 91, "4": 84, "5": 76, "6": 100, "7": 92 } },
|
|
26
|
-
{ "Section": "A", "StudentName": "Brian Diaz", "Average": 77.57, "Grades": { "1": 72, "2": 80, "3": 65, "4": 78, "5": 88, "6": 90, "7": 70 } },
|
|
27
|
-
{ "Section": "A", "StudentName": "Carla Edwards", "Average": 88.71, "Grades": { "1": 88, "2": 85, "3": 92, "4": 90, "5": 95, "6": 85, "7": 86 } },
|
|
28
|
-
{ "Section": "B", "StudentName": "Devon Fox", "Average": 70.00, "Grades": { "1": 60, "2": 68, "3": 70, "4": 72, "5": 65, "6": 80, "7": 75 } },
|
|
29
|
-
{ "Section": "B", "StudentName": "Erika Gomez", "Average": 89.57, "Grades": { "1": 90, "2": 92, "3": 85, "4": 88, "5": 89, "6": 95, "7": 88 } },
|
|
30
|
-
{ "Section": "B", "StudentName": "Felix Hayes", "Average": 77.14, "Grades": { "1": 75, "2": 78, "3": 80, "4": 76, "5": 82, "6": 70, "7": 79 } },
|
|
31
|
-
{ "Section": "C", "StudentName": "Gabriela Ingram", "Average": 87.43, "Grades": { "1": 82, "2": 90, "3": 88, "4": 85, "5": 91, "6": 92, "7": 84 } },
|
|
32
|
-
{ "Section": "C", "StudentName": "Henry Jensen", "Average": 68.86, "Grades": { "1": 70, "2": 65, "3": 60, "4": 72, "5": 68, "6": 75, "7": 72 } }
|
|
33
|
-
],
|
|
34
|
-
"Commentary": [
|
|
35
|
-
{ "Section": "A", "StudentName": "Alice Carter", "Notes": { "1": "Strong start", "3": "Great essay" } },
|
|
36
|
-
{ "Section": "A", "StudentName": "Brian Diaz", "Notes": { "5": "Needs practice on plot summary" } },
|
|
37
|
-
{ "Section": "A", "StudentName": "Carla Edwards", "Notes": {} },
|
|
38
|
-
{ "Section": "B", "StudentName": "Devon Fox", "Notes": { "1": "Borderline; offer extra worksheets" } },
|
|
39
|
-
{ "Section": "B", "StudentName": "Erika Gomez", "Notes": {} },
|
|
40
|
-
{ "Section": "B", "StudentName": "Felix Hayes", "Notes": {} },
|
|
41
|
-
{ "Section": "C", "StudentName": "Gabriela Ingram", "Notes": { "6": "Beautiful color work" } },
|
|
42
|
-
{ "Section": "C", "StudentName": "Henry Jensen", "Notes": { "3": "Struggling; schedule one-on-one" } }
|
|
43
23
|
]
|
|
44
24
|
}
|
package/package.json
CHANGED
|
@@ -858,6 +858,16 @@ Glug glug glug Oo... -->
|
|
|
858
858
|
<th data-tabular-column-index="{~D:Record.PictForm.InputIndex~}">{~D:Record.Name~}</th>
|
|
859
859
|
`
|
|
860
860
|
},
|
|
861
|
+
{
|
|
862
|
+
// The column label only (no <th> wrapper). Used by the ColumnSorting
|
|
863
|
+
// header cell so the label resolves dynamically on every render -- the
|
|
864
|
+
// same way the default HeaderCell above does -- instead of being baked
|
|
865
|
+
// as a static string when the template is built. This lets DynamicColumns
|
|
866
|
+
// name changes (e.g. via refreshtabularsection) update the visible header
|
|
867
|
+
// without a full rebuildCustomTemplate.
|
|
868
|
+
"HashPostfix": "-TabularTemplate-HeaderCellLabel",
|
|
869
|
+
"Template": /*HTML*/`{~D:Record.Name~}`
|
|
870
|
+
},
|
|
861
871
|
{
|
|
862
872
|
"HashPostfix": "-TabularTemplate-RowHeader-Postfix",
|
|
863
873
|
"Template": /*HTML*/`
|
|
@@ -289,7 +289,10 @@ class PictInputObjectEditor extends libPictSectionInputExtension
|
|
|
289
289
|
{
|
|
290
290
|
RenderableHash: 'ObjectEditor-Container',
|
|
291
291
|
TemplateHash: 'ObjectEditor-Container-Template',
|
|
292
|
-
|
|
292
|
+
// pict-view resolves a renderable's destination from ContentDestinationAddress
|
|
293
|
+
// (see Pict-View.buildRenderOptions). A bare DestinationAddress is ignored, so the
|
|
294
|
+
// container template never painted into the slot and the tree had nowhere to mount.
|
|
295
|
+
ContentDestinationAddress: tmpSlotID,
|
|
293
296
|
RenderMethod: 'replace'
|
|
294
297
|
}
|
|
295
298
|
]
|
|
@@ -329,7 +332,10 @@ class PictInputObjectEditor extends libPictSectionInputExtension
|
|
|
329
332
|
|
|
330
333
|
try
|
|
331
334
|
{
|
|
332
|
-
|
|
335
|
+
// Render the container into the CURRENT slot explicitly. The host slot's RawHTMLID is
|
|
336
|
+
// regenerated on every form re-render, so a re-used view instance would otherwise paint into
|
|
337
|
+
// its original (now-removed) slot; passing the destination here re-points it every mount.
|
|
338
|
+
let tmpResult = tmpView.render('ObjectEditor-Container', tmpSlotID);
|
|
333
339
|
if (tmpResult && typeof tmpResult.then === 'function')
|
|
334
340
|
{
|
|
335
341
|
tmpResult.then(
|
|
@@ -98,8 +98,14 @@ class TabularLayout extends libPictSectionGroupLayout
|
|
|
98
98
|
tmpStateClass = 'pict-tabular-sort-desc';
|
|
99
99
|
}
|
|
100
100
|
let tmpGlyph = (typeof this.pict.icon === 'function') ? this.pict.icon(tmpIconName) : '';
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
// Resolve the column label through a metatemplate reference (not a baked
|
|
102
|
+
// literal) so it re-resolves on every render -- this keeps the sortable
|
|
103
|
+
// header in lock-step with the descriptor Name the same way the default
|
|
104
|
+
// (non-sorting) header does. The sort-control glyph/state below is baked,
|
|
105
|
+
// which is fine: it only changes on a sort click, which rebuilds anyway.
|
|
106
|
+
let tmpLabelReference = this.pict.providers.MetatemplateGenerator.getMetatemplateTemplateReference(
|
|
107
|
+
pView, `-TabularTemplate-HeaderCellLabel`, `getTabularRecordInput("${pGroup.GroupIndex}","${pColumnIndex}")`);
|
|
108
|
+
return `\n\t\t\t\t\t\t<th data-tabular-column-index="${pColumnIndex}">${tmpLabelReference} `
|
|
103
109
|
+ `<span class="pict-tabular-sort-control ${tmpStateClass}" `
|
|
104
110
|
+ `onclick="_Pict.providers['Pict-Layout-Tabular'].sortTabularColumn('${pView.Hash}', ${pGroup.GroupIndex}, ${pColumnIndex})">`
|
|
105
111
|
+ `${tmpGlyph}</span></th>\n`;
|
|
@@ -1288,6 +1288,111 @@ suite('PictSectionForm Tabular Features', () =>
|
|
|
1288
1288
|
Expect(tmpLayout._compareTabularValues(null, 'a')).to.be.lessThan(0);
|
|
1289
1289
|
}, fDone);
|
|
1290
1290
|
});
|
|
1291
|
+
|
|
1292
|
+
// Regression: a ColumnSorting header must keep its label in lock-step with the
|
|
1293
|
+
// descriptor Name. Before the fix, _buildSortableHeaderCell baked the resolved
|
|
1294
|
+
// Name as a static string, so a label change applied by a render-only refresh
|
|
1295
|
+
// (e.g. DynamicColumns recomputed via refreshtabularsection) never reached the
|
|
1296
|
+
// visible header -- only a full rebuildCustomTemplate would. The label is now a
|
|
1297
|
+
// metatemplate reference that re-resolves on every render, matching the default
|
|
1298
|
+
// (non-sorting) header.
|
|
1299
|
+
test('ColumnSorting header label is a dynamic metatemplate reference, not a baked literal', (fDone) =>
|
|
1300
|
+
{
|
|
1301
|
+
let App = makeApplication({
|
|
1302
|
+
Hash: 'Students',
|
|
1303
|
+
Layout: 'Tabular',
|
|
1304
|
+
RecordSetAddress: 'Students',
|
|
1305
|
+
RecordManifest: 'StudentEditor',
|
|
1306
|
+
ColumnSorting: true
|
|
1307
|
+
});
|
|
1308
|
+
bootstrap(App, (_Pict) =>
|
|
1309
|
+
{
|
|
1310
|
+
let tmpView = _Pict.views['PictSectionForm-Class'];
|
|
1311
|
+
let tmpGroup = tmpView.sectionDefinition.Groups[0];
|
|
1312
|
+
let tmpLayout = _Pict.providers['Pict-Layout-Tabular'];
|
|
1313
|
+
let tmpNameIndex = tmpGroup.supportingManifest.elementAddresses.indexOf('StudentName');
|
|
1314
|
+
let tmpDescriptor = tmpGroup.supportingManifest.elementDescriptors['StudentName'];
|
|
1315
|
+
Expect(tmpDescriptor.Name).to.equal('Student', 'baseline descriptor name');
|
|
1316
|
+
|
|
1317
|
+
let tmpHeaderHTML = tmpLayout._buildSortableHeaderCell(tmpView, tmpGroup, tmpDescriptor, tmpNameIndex);
|
|
1318
|
+
// The label is emitted as a metatemplate reference bound to the live descriptor...
|
|
1319
|
+
Expect(tmpHeaderHTML).to.contain('-TabularTemplate-HeaderCellLabel', 'label rendered via the dynamic label template');
|
|
1320
|
+
Expect(tmpHeaderHTML).to.contain(`getTabularRecordInput("${tmpGroup.GroupIndex}","${tmpNameIndex}")`, 'reference bound to this column descriptor');
|
|
1321
|
+
// ...NOT baked as the literal name (which is what caused the stale header).
|
|
1322
|
+
Expect(tmpHeaderHTML).to.not.contain('>Student ', 'descriptor name is not inlined as a static literal');
|
|
1323
|
+
// The sort control is still baked (it only changes on a sort click, which rebuilds).
|
|
1324
|
+
Expect(tmpHeaderHTML).to.contain('pict-tabular-sort-control', 'sort control still present');
|
|
1325
|
+
Expect(tmpHeaderHTML).to.contain('sortTabularColumn', 'sort click handler still wired');
|
|
1326
|
+
}, fDone);
|
|
1327
|
+
});
|
|
1328
|
+
|
|
1329
|
+
test('-TabularTemplate-HeaderCellLabel is registered and resolves the descriptor Name (parity with the default header)', (fDone) =>
|
|
1330
|
+
{
|
|
1331
|
+
let App = makeApplication({
|
|
1332
|
+
Hash: 'Students',
|
|
1333
|
+
Layout: 'Tabular',
|
|
1334
|
+
RecordSetAddress: 'Students',
|
|
1335
|
+
RecordManifest: 'StudentEditor',
|
|
1336
|
+
ColumnSorting: true
|
|
1337
|
+
});
|
|
1338
|
+
bootstrap(App, (_Pict) =>
|
|
1339
|
+
{
|
|
1340
|
+
let tmpView = _Pict.views['PictSectionForm-Class'];
|
|
1341
|
+
// The label template exists under the view's theme prefix and resolves the
|
|
1342
|
+
// same {~D:Record.Name~} data tag the default (non-sorting) HeaderCell uses.
|
|
1343
|
+
let tmpTemplateHash = tmpView.getThemeSpecificTemplateHash('-TabularTemplate-HeaderCellLabel');
|
|
1344
|
+
Expect(tmpTemplateHash in _Pict.TemplateProvider.templates).to.equal(true, 'label template registered');
|
|
1345
|
+
// Template entries are stored as raw template strings.
|
|
1346
|
+
Expect(_Pict.TemplateProvider.templates[tmpTemplateHash]).to.contain('{~D:Record.Name~}', 'label resolves the descriptor Name dynamically');
|
|
1347
|
+
}, fDone);
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
test('ColumnSorting header reflects a descriptor Name change on render() without a rebuildCustomTemplate', (fDone) =>
|
|
1351
|
+
{
|
|
1352
|
+
let App = makeApplication({
|
|
1353
|
+
Hash: 'Students',
|
|
1354
|
+
Layout: 'Tabular',
|
|
1355
|
+
RecordSetAddress: 'Students',
|
|
1356
|
+
RecordManifest: 'StudentEditor',
|
|
1357
|
+
ColumnSorting: true
|
|
1358
|
+
});
|
|
1359
|
+
bootstrap(App, (_Pict) =>
|
|
1360
|
+
{
|
|
1361
|
+
let tmpView = _Pict.views['PictSectionForm-Class'];
|
|
1362
|
+
let tmpGroup = tmpView.sectionDefinition.Groups[0];
|
|
1363
|
+
// Target the StudentName column specifically (the StudentEditor manifest
|
|
1364
|
+
// also has a Section column at index 0).
|
|
1365
|
+
let tmpNameIndex = tmpGroup.supportingManifest.elementAddresses.indexOf('StudentName');
|
|
1366
|
+
let tmpHeaderSelector = `th[data-tabular-column-index="${tmpNameIndex}"]`;
|
|
1367
|
+
|
|
1368
|
+
// Render the section into its real destination so we can read the baked header.
|
|
1369
|
+
let tmpContainerId = String(tmpView.sectionDefinition.DefaultDestinationAddress || '').replace('#', '');
|
|
1370
|
+
let tmpContainer = window.document.createElement('div');
|
|
1371
|
+
tmpContainer.id = tmpContainerId;
|
|
1372
|
+
window.document.body.appendChild(tmpContainer);
|
|
1373
|
+
try
|
|
1374
|
+
{
|
|
1375
|
+
tmpView.render();
|
|
1376
|
+
let tmpHeader = tmpContainer.querySelector(tmpHeaderSelector);
|
|
1377
|
+
Expect(tmpHeader).to.not.equal(null, 'a sortable header cell rendered');
|
|
1378
|
+
Expect(tmpHeader.textContent).to.contain('Student', 'header shows the original descriptor name');
|
|
1379
|
+
|
|
1380
|
+
// Simulate what a render-only refresh (refreshtabularsection / DynamicColumns
|
|
1381
|
+
// name recompute) does: the live descriptor's Name changes, then render() runs
|
|
1382
|
+
// WITHOUT rebuildCustomTemplate(). The header must follow.
|
|
1383
|
+
tmpGroup.supportingManifest.elementDescriptors['StudentName'].Name = 'Aggregate Base';
|
|
1384
|
+
tmpView.render();
|
|
1385
|
+
|
|
1386
|
+
let tmpHeaderAfter = tmpContainer.querySelector(tmpHeaderSelector);
|
|
1387
|
+
Expect(tmpHeaderAfter.textContent).to.contain('Aggregate Base', 'header updated to the new name on render alone');
|
|
1388
|
+
Expect(tmpHeaderAfter.textContent).to.not.contain('Student', 'stale label no longer shown');
|
|
1389
|
+
}
|
|
1390
|
+
finally
|
|
1391
|
+
{
|
|
1392
|
+
window.document.body.removeChild(tmpContainer);
|
|
1393
|
+
}
|
|
1394
|
+
}, fDone);
|
|
1395
|
+
});
|
|
1291
1396
|
});
|
|
1292
1397
|
|
|
1293
1398
|
suite('Tabular column chooser (ColumnChooser)', () =>
|