@@ -99,16 +99,14 @@ exports.valObjects = {
9999 // TODO 'values shouldn't be in there (edge case: 'dash' in Scatter)
100100 otherOpts : [ 'dflt' , 'noBlank' , 'strict' , 'arrayOk' , 'values' ] ,
101101 coerceFunction : function ( v , propOut , dflt , opts ) {
102- if ( opts . strict === true && typeof v !== 'string' ) {
103- propOut . set ( dflt ) ;
104- return ;
105- }
102+ if ( typeof v !== 'string' ) {
103+ var okToCoerce = ( typeof v === 'number' ) ;
106104
107- var s = String ( v ) ;
108- if ( v === undefined || ( opts . noBlank === true && ! s ) ) {
109- propOut . set ( dflt ) ;
105+ if ( opts . strict === true || ! okToCoerce ) propOut . set ( dflt ) ;
106+ else propOut . set ( String ( v ) ) ;
110107 }
111- else propOut . set ( s ) ;
108+ else if ( opts . noBlank && ! v ) propOut . set ( dflt ) ;
109+ else propOut . set ( v ) ;
112110 }
113111 } ,
114112 color : {
@@ -162,11 +160,11 @@ exports.valObjects = {
162160 subplotid : {
163161 description : [
164162 'An id string of a subplot type (given by dflt), optionally' ,
165- 'followed by an integer >1. e.g. if dflt=\'geo\', we can have' ,
163+ 'followed by an integer >1. e.g. if dflt=\'geo\', we can have' ,
166164 '\'geo\', \'geo2\', \'geo3\', ...'
167165 ] . join ( ' ' ) ,
168- requiredOpts : [ ] ,
169- otherOpts : [ 'dflt' ] ,
166+ requiredOpts : [ 'dflt' ] ,
167+ otherOpts : [ ] ,
170168 coerceFunction : function ( v , propOut , dflt ) {
171169 var dlen = dflt . length ;
172170 if ( typeof v === 'string' && v . substr ( 0 , dlen ) === dflt &&
@@ -175,6 +173,18 @@ exports.valObjects = {
175173 return ;
176174 }
177175 propOut . set ( dflt ) ;
176+ } ,
177+ validateFunction : function ( v , opts ) {
178+ var dflt = opts . dflt ,
179+ dlen = dflt . length ;
180+
181+ if ( v === dflt ) return true ;
182+ if ( typeof v !== 'string' ) return false ;
183+ if ( v . substr ( 0 , dlen ) === dflt && idRegex . test ( v . substr ( dlen ) ) ) {
184+ return true ;
185+ }
186+
187+ return false ;
178188 }
179189 } ,
180190 flaglist : {
@@ -239,6 +249,22 @@ exports.valObjects = {
239249 }
240250
241251 propOut . set ( vOut ) ;
252+ } ,
253+ validateFunction : function ( v , opts ) {
254+ if ( ! Array . isArray ( v ) ) return false ;
255+
256+ var items = opts . items ;
257+
258+ if ( v . length !== items . length ) return false ;
259+
260+ // valid when all items are valid
261+ for ( var i = 0 ; i < items . length ; i ++ ) {
262+ var isItemValid = exports . validate ( v [ i ] , opts . items [ i ] ) ;
263+
264+ if ( ! isItemValid ) return false ;
265+ }
266+
267+ return true ;
242268 }
243269 }
244270} ;
@@ -309,3 +335,22 @@ exports.coerceFont = function(coerce, attr, dfltObj) {
309335
310336 return out ;
311337} ;
338+
339+ exports . validate = function ( value , opts ) {
340+ var valObject = exports . valObjects [ opts . valType ] ;
341+
342+ if ( opts . arrayOk && Array . isArray ( value ) ) return true ;
343+
344+ if ( valObject . validateFunction ) {
345+ return valObject . validateFunction ( value , opts ) ;
346+ }
347+
348+ var failed = { } ,
349+ out = failed ,
350+ propMock = { set : function ( v ) { out = v ; } } ;
351+
352+ // 'failed' just something mutable that won't be === anything else
353+
354+ valObject . coerceFunction ( value , propMock , failed , opts ) ;
355+ return out !== failed ;
356+ } ;
0 commit comments