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