|
9 | 9 | */ |
10 | 10 |
|
11 | 11 | // Characters [].:/ are reserved for track binding syntax. |
12 | | -var RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; |
| 12 | +var _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; |
| 13 | + |
| 14 | +var _reservedRe; |
| 15 | +var _trackRe, _supportedObjectNames; |
13 | 16 |
|
14 | 17 | function Composite( targetGroup, path, optionalParsedPath ) { |
15 | 18 |
|
@@ -109,101 +112,101 @@ Object.assign( PropertyBinding, { |
109 | 112 | * @param {string} name Node name to be sanitized. |
110 | 113 | * @return {string} |
111 | 114 | */ |
112 | | - sanitizeNodeName: ( function () { |
| 115 | + sanitizeNodeName: function ( name ) { |
113 | 116 |
|
114 | | - var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' ); |
| 117 | + if ( _reservedRe === undefined ) { |
115 | 118 |
|
116 | | - return function sanitizeNodeName( name ) { |
| 119 | + _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); |
117 | 120 |
|
118 | | - return name.replace( /\s/g, '_' ).replace( reservedRe, '' ); |
| 121 | + } |
119 | 122 |
|
120 | | - }; |
| 123 | + return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); |
121 | 124 |
|
122 | | - }() ), |
| 125 | + }, |
123 | 126 |
|
124 | | - parseTrackName: function () { |
| 127 | + parseTrackName: function ( trackName ) { |
125 | 128 |
|
126 | | - // Attempts to allow node names from any language. ES5's `\w` regexp matches |
127 | | - // only latin characters, and the unicode \p{L} is not yet supported. So |
128 | | - // instead, we exclude reserved characters and match everything else. |
129 | | - var wordChar = '[^' + RESERVED_CHARS_RE + ']'; |
130 | | - var wordCharOrDot = '[^' + RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; |
| 129 | + if ( _supportedObjectNames === undefined ) { |
131 | 130 |
|
132 | | - // Parent directories, delimited by '/' or ':'. Currently unused, but must |
133 | | - // be matched to parse the rest of the track name. |
134 | | - var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar ); |
| 131 | + // Attempts to allow node names from any language. ES5's `\w` regexp matches |
| 132 | + // only latin characters, and the unicode \p{L} is not yet supported. So |
| 133 | + // instead, we exclude reserved characters and match everything else. |
| 134 | + var wordChar = '[^' + _RESERVED_CHARS_RE + ']'; |
| 135 | + var wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; |
135 | 136 |
|
136 | | - // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. |
137 | | - var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot ); |
| 137 | + // Parent directories, delimited by '/' or ':'. Currently unused, but must |
| 138 | + // be matched to parse the rest of the track name. |
| 139 | + var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar ); |
138 | 140 |
|
139 | | - // Object on target node, and accessor. May not contain reserved |
140 | | - // characters. Accessor may contain any character except closing bracket. |
141 | | - var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar ); |
| 141 | + // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. |
| 142 | + var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot ); |
142 | 143 |
|
143 | | - // Property and accessor. May not contain reserved characters. Accessor may |
144 | | - // contain any non-bracket characters. |
145 | | - var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar ); |
| 144 | + // Object on target node, and accessor. May not contain reserved |
| 145 | + // characters. Accessor may contain any character except closing bracket. |
| 146 | + var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar ); |
146 | 147 |
|
147 | | - var trackRe = new RegExp( '' |
148 | | - + '^' |
149 | | - + directoryRe |
150 | | - + nodeRe |
151 | | - + objectRe |
152 | | - + propertyRe |
153 | | - + '$' |
154 | | - ); |
| 148 | + // Property and accessor. May not contain reserved characters. Accessor may |
| 149 | + // contain any non-bracket characters. |
| 150 | + var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar ); |
155 | 151 |
|
156 | | - var supportedObjectNames = [ 'material', 'materials', 'bones' ]; |
| 152 | + _trackRe = new RegExp( '' |
| 153 | + + '^' |
| 154 | + + directoryRe |
| 155 | + + nodeRe |
| 156 | + + objectRe |
| 157 | + + propertyRe |
| 158 | + + '$' |
| 159 | + ); |
157 | 160 |
|
158 | | - return function parseTrackName( trackName ) { |
| 161 | + _supportedObjectNames = [ 'material', 'materials', 'bones' ]; |
159 | 162 |
|
160 | | - var matches = trackRe.exec( trackName ); |
| 163 | + } |
161 | 164 |
|
162 | | - if ( ! matches ) { |
| 165 | + var matches = _trackRe.exec( trackName ); |
163 | 166 |
|
164 | | - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); |
| 167 | + if ( ! matches ) { |
165 | 168 |
|
166 | | - } |
| 169 | + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); |
167 | 170 |
|
168 | | - var results = { |
169 | | - // directoryName: matches[ 1 ], // (tschw) currently unused |
170 | | - nodeName: matches[ 2 ], |
171 | | - objectName: matches[ 3 ], |
172 | | - objectIndex: matches[ 4 ], |
173 | | - propertyName: matches[ 5 ], // required |
174 | | - propertyIndex: matches[ 6 ] |
175 | | - }; |
| 171 | + } |
176 | 172 |
|
177 | | - var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); |
| 173 | + var results = { |
| 174 | + // directoryName: matches[ 1 ], // (tschw) currently unused |
| 175 | + nodeName: matches[ 2 ], |
| 176 | + objectName: matches[ 3 ], |
| 177 | + objectIndex: matches[ 4 ], |
| 178 | + propertyName: matches[ 5 ], // required |
| 179 | + propertyIndex: matches[ 6 ] |
| 180 | + }; |
178 | 181 |
|
179 | | - if ( lastDot !== undefined && lastDot !== - 1 ) { |
| 182 | + var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); |
180 | 183 |
|
181 | | - var objectName = results.nodeName.substring( lastDot + 1 ); |
| 184 | + if ( lastDot !== undefined && lastDot !== - 1 ) { |
182 | 185 |
|
183 | | - // Object names must be checked against a whitelist. Otherwise, there |
184 | | - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but |
185 | | - // 'bar' could be the objectName, or part of a nodeName (which can |
186 | | - // include '.' characters). |
187 | | - if ( supportedObjectNames.indexOf( objectName ) !== - 1 ) { |
| 186 | + var objectName = results.nodeName.substring( lastDot + 1 ); |
188 | 187 |
|
189 | | - results.nodeName = results.nodeName.substring( 0, lastDot ); |
190 | | - results.objectName = objectName; |
| 188 | + // Object names must be checked against a whitelist. Otherwise, there |
| 189 | + // is no way to parse 'foo.bar.baz': 'baz' must be a property, but |
| 190 | + // 'bar' could be the objectName, or part of a nodeName (which can |
| 191 | + // include '.' characters). |
| 192 | + if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { |
191 | 193 |
|
192 | | - } |
| 194 | + results.nodeName = results.nodeName.substring( 0, lastDot ); |
| 195 | + results.objectName = objectName; |
193 | 196 |
|
194 | 197 | } |
195 | 198 |
|
196 | | - if ( results.propertyName === null || results.propertyName.length === 0 ) { |
| 199 | + } |
197 | 200 |
|
198 | | - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); |
| 201 | + if ( results.propertyName === null || results.propertyName.length === 0 ) { |
199 | 202 |
|
200 | | - } |
| 203 | + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); |
201 | 204 |
|
202 | | - return results; |
| 205 | + } |
203 | 206 |
|
204 | | - }; |
| 207 | + return results; |
205 | 208 |
|
206 | | - }(), |
| 209 | + }, |
207 | 210 |
|
208 | 211 | findNode: function ( root, nodeName ) { |
209 | 212 |
|
|
0 commit comments