Skip to content

Commit 15931cf

Browse files
committed
recurse into (template)layout looking for unused containers
1 parent 818cac9 commit 15931cf

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

src/plot_api/template_api.js

+35-10
Original file line numberDiff line numberDiff line change
@@ -307,20 +307,45 @@ exports.validateTemplate = function(figureIn, template) {
307307
var fullLayout = figure._fullLayout;
308308
var fullData = figure._fullData;
309309

310+
var layoutPaths = {};
311+
function crawlLayoutForContainers(obj, paths) {
312+
for(var key in obj) {
313+
if(key.charAt(0) !== '_' && isPlainObject(obj[key])) {
314+
var baseKey = getBaseKey(key);
315+
var nextPaths = [];
316+
var i;
317+
for(i = 0; i < paths.length; i++) {
318+
nextPaths.push(getNextPath(obj, key, paths[i]));
319+
if(baseKey !== key) nextPaths.push(getNextPath(obj, baseKey, paths[i]));
320+
}
321+
for(i = 0; i < nextPaths.length; i++) {
322+
layoutPaths[nextPaths[i]] = 1;
323+
}
324+
crawlLayoutForContainers(obj[key], nextPaths);
325+
}
326+
}
327+
}
328+
329+
function crawlLayoutTemplateForContainers(obj, path) {
330+
for(var key in obj) {
331+
if(key.indexOf('defaults') === -1 && isPlainObject(obj[key])) {
332+
var nextPath = getNextPath(obj, key, path);
333+
if(layoutPaths[nextPath]) {
334+
crawlLayoutTemplateForContainers(obj[key], nextPath);
335+
}
336+
else {
337+
errorList.push({code: 'unused', path: nextPath});
338+
}
339+
}
340+
}
341+
}
342+
310343
if(!isPlainObject(layoutTemplate)) {
311344
errorList.push({code: 'layout'});
312345
}
313346
else {
314-
// TODO: any need to look deeper than the first level of layout?
315-
// I don't think so, that gets all the subplot types which should be
316-
// sufficient.
317-
for(var key in layoutTemplate) {
318-
if(key.indexOf('defaults') === -1 && isPlainObject(layoutTemplate[key]) &&
319-
!hasMatchingKey(fullLayout, key)
320-
) {
321-
errorList.push({code: 'unused', path: 'layout.' + key});
322-
}
323-
}
347+
crawlLayoutForContainers(fullLayout, ['layout']);
348+
crawlLayoutTemplateForContainers(layoutTemplate, 'layout');
324349
}
325350

326351
if(!isPlainObject(dataTemplate)) {

test/jasmine/tests/template_test.js

+11
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,20 @@ describe('validateTemplate', function() {
268268
messyMock.data.push({type: 'box', x0: 1, y: [1, 2, 3]});
269269
messyMock.layout.template.layout.geo = {projection: {type: 'orthographic'}};
270270
messyMock.layout.template.layout.xaxis3 = {nticks: 50};
271+
messyMock.layout.template.layout.xaxis.rangeslider = {yaxis3: {rangemode: 'fixed'}};
272+
messyMock.layout.xaxis = {rangeslider: {}};
273+
messyMock.layout.template.layout.xaxis2.rangeslider = {bgcolor: '#CCC'};
271274
messyMock.layout.template.data.violin = [{fillcolor: '#000'}];
272275

273276
checkValidate(messyMock, [{
277+
code: 'unused',
278+
path: 'layout.xaxis.rangeslider.yaxis3',
279+
msg: 'The template item at layout.xaxis.rangeslider.yaxis3 was not used in constructing the plot.'
280+
}, {
281+
code: 'unused',
282+
path: 'layout.xaxis2.rangeslider',
283+
msg: 'The template item at layout.xaxis2.rangeslider was not used in constructing the plot.'
284+
}, {
274285
code: 'unused',
275286
path: 'layout.geo',
276287
msg: 'The template item at layout.geo was not used in constructing the plot.'

0 commit comments

Comments
 (0)