|
1 YUI.add('features', function (Y, NAME) { |
|
2 |
|
3 var feature_tests = {}; |
|
4 |
|
5 /** |
|
6 Contains the core of YUI's feature test architecture. |
|
7 @module features |
|
8 */ |
|
9 |
|
10 /** |
|
11 * Feature detection |
|
12 * @class Features |
|
13 * @static |
|
14 */ |
|
15 |
|
16 Y.mix(Y.namespace('Features'), { |
|
17 |
|
18 /** |
|
19 * Object hash of all registered feature tests |
|
20 * @property tests |
|
21 * @type Object |
|
22 */ |
|
23 tests: feature_tests, |
|
24 |
|
25 /** |
|
26 * Add a test to the system |
|
27 * |
|
28 * ``` |
|
29 * Y.Features.add("load", "1", {}); |
|
30 * ``` |
|
31 * |
|
32 * @method add |
|
33 * @param {String} cat The category, right now only 'load' is supported |
|
34 * @param {String} name The number sequence of the test, how it's reported in the URL or config: 1, 2, 3 |
|
35 * @param {Object} o Object containing test properties |
|
36 * @param {String} o.name The name of the test |
|
37 * @param {Function} o.test The test function to execute, the only argument to the function is the `Y` instance |
|
38 * @param {String} o.trigger The module that triggers this test. |
|
39 */ |
|
40 add: function(cat, name, o) { |
|
41 feature_tests[cat] = feature_tests[cat] || {}; |
|
42 feature_tests[cat][name] = o; |
|
43 }, |
|
44 /** |
|
45 * Execute all tests of a given category and return the serialized results |
|
46 * |
|
47 * ``` |
|
48 * caps=1:1;2:1;3:0 |
|
49 * ``` |
|
50 * @method all |
|
51 * @param {String} cat The category to execute |
|
52 * @param {Array} args The arguments to pass to the test function |
|
53 * @return {String} A semi-colon separated string of tests and their success/failure: 1:1;2:1;3:0 |
|
54 */ |
|
55 all: function(cat, args) { |
|
56 var cat_o = feature_tests[cat], |
|
57 // results = {}; |
|
58 result = []; |
|
59 if (cat_o) { |
|
60 Y.Object.each(cat_o, function(v, k) { |
|
61 result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0)); |
|
62 }); |
|
63 } |
|
64 |
|
65 return (result.length) ? result.join(';') : ''; |
|
66 }, |
|
67 /** |
|
68 * Run a sepecific test and return a Boolean response. |
|
69 * |
|
70 * ``` |
|
71 * Y.Features.test("load", "1"); |
|
72 * ``` |
|
73 * |
|
74 * @method test |
|
75 * @param {String} cat The category of the test to run |
|
76 * @param {String} name The name of the test to run |
|
77 * @param {Array} args The arguments to pass to the test function |
|
78 * @return {Boolean} True or false if the test passed/failed. |
|
79 */ |
|
80 test: function(cat, name, args) { |
|
81 args = args || []; |
|
82 var result, ua, test, |
|
83 cat_o = feature_tests[cat], |
|
84 feature = cat_o && cat_o[name]; |
|
85 |
|
86 if (!feature) { |
|
87 Y.log('Feature test ' + cat + ', ' + name + ' not found'); |
|
88 } else { |
|
89 |
|
90 result = feature.result; |
|
91 |
|
92 if (Y.Lang.isUndefined(result)) { |
|
93 |
|
94 ua = feature.ua; |
|
95 if (ua) { |
|
96 result = (Y.UA[ua]); |
|
97 } |
|
98 |
|
99 test = feature.test; |
|
100 if (test && ((!ua) || result)) { |
|
101 result = test.apply(Y, args); |
|
102 } |
|
103 |
|
104 feature.result = result; |
|
105 } |
|
106 } |
|
107 |
|
108 return result; |
|
109 } |
|
110 }); |
|
111 |
|
112 // Y.Features.add("load", "1", {}); |
|
113 // Y.Features.test("load", "1"); |
|
114 // caps=1:1;2:0;3:1; |
|
115 |
|
116 /* This file is auto-generated by (yogi loader --yes --mix --start ../) */ |
|
117 /*jshint maxlen:900, eqeqeq: false */ |
|
118 var add = Y.Features.add; |
|
119 // app-transitions-native |
|
120 add('load', '0', { |
|
121 "name": "app-transitions-native", |
|
122 "test": function (Y) { |
|
123 var doc = Y.config.doc, |
|
124 node = doc ? doc.documentElement : null; |
|
125 |
|
126 if (node && node.style) { |
|
127 return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style); |
|
128 } |
|
129 |
|
130 return false; |
|
131 }, |
|
132 "trigger": "app-transitions" |
|
133 }); |
|
134 // autocomplete-list-keys |
|
135 add('load', '1', { |
|
136 "name": "autocomplete-list-keys", |
|
137 "test": function (Y) { |
|
138 // Only add keyboard support to autocomplete-list if this doesn't appear to |
|
139 // be an iOS or Android-based mobile device. |
|
140 // |
|
141 // There's currently no feasible way to actually detect whether a device has |
|
142 // a hardware keyboard, so this sniff will have to do. It can easily be |
|
143 // overridden by manually loading the autocomplete-list-keys module. |
|
144 // |
|
145 // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari |
|
146 // doesn't fire the keyboard events used by AutoCompleteList, so there's |
|
147 // no point loading the -keys module even when a bluetooth keyboard may be |
|
148 // available. |
|
149 return !(Y.UA.ios || Y.UA.android); |
|
150 }, |
|
151 "trigger": "autocomplete-list" |
|
152 }); |
|
153 // dd-gestures |
|
154 add('load', '2', { |
|
155 "name": "dd-gestures", |
|
156 "trigger": "dd-drag", |
|
157 "ua": "touchEnabled" |
|
158 }); |
|
159 // dom-style-ie |
|
160 add('load', '3', { |
|
161 "name": "dom-style-ie", |
|
162 "test": function (Y) { |
|
163 |
|
164 var testFeature = Y.Features.test, |
|
165 addFeature = Y.Features.add, |
|
166 WINDOW = Y.config.win, |
|
167 DOCUMENT = Y.config.doc, |
|
168 DOCUMENT_ELEMENT = 'documentElement', |
|
169 ret = false; |
|
170 |
|
171 addFeature('style', 'computedStyle', { |
|
172 test: function() { |
|
173 return WINDOW && 'getComputedStyle' in WINDOW; |
|
174 } |
|
175 }); |
|
176 |
|
177 addFeature('style', 'opacity', { |
|
178 test: function() { |
|
179 return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style; |
|
180 } |
|
181 }); |
|
182 |
|
183 ret = (!testFeature('style', 'opacity') && |
|
184 !testFeature('style', 'computedStyle')); |
|
185 |
|
186 return ret; |
|
187 }, |
|
188 "trigger": "dom-style" |
|
189 }); |
|
190 // editor-para-ie |
|
191 add('load', '4', { |
|
192 "name": "editor-para-ie", |
|
193 "trigger": "editor-para", |
|
194 "ua": "ie", |
|
195 "when": "instead" |
|
196 }); |
|
197 // event-base-ie |
|
198 add('load', '5', { |
|
199 "name": "event-base-ie", |
|
200 "test": function(Y) { |
|
201 var imp = Y.config.doc && Y.config.doc.implementation; |
|
202 return (imp && (!imp.hasFeature('Events', '2.0'))); |
|
203 }, |
|
204 "trigger": "node-base" |
|
205 }); |
|
206 // graphics-canvas |
|
207 add('load', '6', { |
|
208 "name": "graphics-canvas", |
|
209 "test": function(Y) { |
|
210 var DOCUMENT = Y.config.doc, |
|
211 useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas", |
|
212 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), |
|
213 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); |
|
214 return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d")); |
|
215 }, |
|
216 "trigger": "graphics" |
|
217 }); |
|
218 // graphics-canvas-default |
|
219 add('load', '7', { |
|
220 "name": "graphics-canvas-default", |
|
221 "test": function(Y) { |
|
222 var DOCUMENT = Y.config.doc, |
|
223 useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas", |
|
224 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), |
|
225 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); |
|
226 return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d")); |
|
227 }, |
|
228 "trigger": "graphics" |
|
229 }); |
|
230 // graphics-svg |
|
231 add('load', '8', { |
|
232 "name": "graphics-svg", |
|
233 "test": function(Y) { |
|
234 var DOCUMENT = Y.config.doc, |
|
235 useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas", |
|
236 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), |
|
237 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); |
|
238 |
|
239 return svg && (useSVG || !canvas); |
|
240 }, |
|
241 "trigger": "graphics" |
|
242 }); |
|
243 // graphics-svg-default |
|
244 add('load', '9', { |
|
245 "name": "graphics-svg-default", |
|
246 "test": function(Y) { |
|
247 var DOCUMENT = Y.config.doc, |
|
248 useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas", |
|
249 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), |
|
250 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); |
|
251 |
|
252 return svg && (useSVG || !canvas); |
|
253 }, |
|
254 "trigger": "graphics" |
|
255 }); |
|
256 // graphics-vml |
|
257 add('load', '10', { |
|
258 "name": "graphics-vml", |
|
259 "test": function(Y) { |
|
260 var DOCUMENT = Y.config.doc, |
|
261 canvas = DOCUMENT && DOCUMENT.createElement("canvas"); |
|
262 return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d"))); |
|
263 }, |
|
264 "trigger": "graphics" |
|
265 }); |
|
266 // graphics-vml-default |
|
267 add('load', '11', { |
|
268 "name": "graphics-vml-default", |
|
269 "test": function(Y) { |
|
270 var DOCUMENT = Y.config.doc, |
|
271 canvas = DOCUMENT && DOCUMENT.createElement("canvas"); |
|
272 return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d"))); |
|
273 }, |
|
274 "trigger": "graphics" |
|
275 }); |
|
276 // history-hash-ie |
|
277 add('load', '12', { |
|
278 "name": "history-hash-ie", |
|
279 "test": function (Y) { |
|
280 var docMode = Y.config.doc && Y.config.doc.documentMode; |
|
281 |
|
282 return Y.UA.ie && (!('onhashchange' in Y.config.win) || |
|
283 !docMode || docMode < 8); |
|
284 }, |
|
285 "trigger": "history-hash" |
|
286 }); |
|
287 // io-nodejs |
|
288 add('load', '13', { |
|
289 "name": "io-nodejs", |
|
290 "trigger": "io-base", |
|
291 "ua": "nodejs" |
|
292 }); |
|
293 // json-parse-shim |
|
294 add('load', '14', { |
|
295 "name": "json-parse-shim", |
|
296 "test": function (Y) { |
|
297 var _JSON = Y.config.global.JSON, |
|
298 Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON, |
|
299 nativeSupport = Y.config.useNativeJSONParse !== false && !!Native; |
|
300 |
|
301 function workingNative( k, v ) { |
|
302 return k === "ok" ? true : v; |
|
303 } |
|
304 |
|
305 // Double check basic functionality. This is mainly to catch early broken |
|
306 // implementations of the JSON API in Firefox 3.1 beta1 and beta2 |
|
307 if ( nativeSupport ) { |
|
308 try { |
|
309 nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok; |
|
310 } |
|
311 catch ( e ) { |
|
312 nativeSupport = false; |
|
313 } |
|
314 } |
|
315 |
|
316 return !nativeSupport; |
|
317 }, |
|
318 "trigger": "json-parse" |
|
319 }); |
|
320 // json-stringify-shim |
|
321 add('load', '15', { |
|
322 "name": "json-stringify-shim", |
|
323 "test": function (Y) { |
|
324 var _JSON = Y.config.global.JSON, |
|
325 Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON, |
|
326 nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native; |
|
327 |
|
328 // Double check basic native functionality. This is primarily to catch broken |
|
329 // early JSON API implementations in Firefox 3.1 beta1 and beta2. |
|
330 if ( nativeSupport ) { |
|
331 try { |
|
332 nativeSupport = ( '0' === Native.stringify(0) ); |
|
333 } catch ( e ) { |
|
334 nativeSupport = false; |
|
335 } |
|
336 } |
|
337 |
|
338 |
|
339 return !nativeSupport; |
|
340 }, |
|
341 "trigger": "json-stringify" |
|
342 }); |
|
343 // scrollview-base-ie |
|
344 add('load', '16', { |
|
345 "name": "scrollview-base-ie", |
|
346 "trigger": "scrollview-base", |
|
347 "ua": "ie" |
|
348 }); |
|
349 // selector-css2 |
|
350 add('load', '17', { |
|
351 "name": "selector-css2", |
|
352 "test": function (Y) { |
|
353 var DOCUMENT = Y.config.doc, |
|
354 ret = DOCUMENT && !('querySelectorAll' in DOCUMENT); |
|
355 |
|
356 return ret; |
|
357 }, |
|
358 "trigger": "selector" |
|
359 }); |
|
360 // transition-timer |
|
361 add('load', '18', { |
|
362 "name": "transition-timer", |
|
363 "test": function (Y) { |
|
364 var DOCUMENT = Y.config.doc, |
|
365 node = (DOCUMENT) ? DOCUMENT.documentElement: null, |
|
366 ret = true; |
|
367 |
|
368 if (node && node.style) { |
|
369 ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style); |
|
370 } |
|
371 |
|
372 return ret; |
|
373 }, |
|
374 "trigger": "transition" |
|
375 }); |
|
376 // widget-base-ie |
|
377 add('load', '19', { |
|
378 "name": "widget-base-ie", |
|
379 "trigger": "widget-base", |
|
380 "ua": "ie" |
|
381 }); |
|
382 // yql-jsonp |
|
383 add('load', '20', { |
|
384 "name": "yql-jsonp", |
|
385 "test": function (Y) { |
|
386 /* Only load the JSONP module when not in nodejs or winjs |
|
387 TODO Make the winjs module a CORS module |
|
388 */ |
|
389 return (!Y.UA.nodejs && !Y.UA.winjs); |
|
390 }, |
|
391 "trigger": "yql", |
|
392 "when": "after" |
|
393 }); |
|
394 // yql-nodejs |
|
395 add('load', '21', { |
|
396 "name": "yql-nodejs", |
|
397 "trigger": "yql", |
|
398 "ua": "nodejs", |
|
399 "when": "after" |
|
400 }); |
|
401 // yql-winjs |
|
402 add('load', '22', { |
|
403 "name": "yql-winjs", |
|
404 "trigger": "yql", |
|
405 "ua": "winjs", |
|
406 "when": "after" |
|
407 }); |
|
408 |
|
409 }, '@VERSION@', {"requires": ["yui-base"]}); |