[483] | 1 | define(["require", "module"], function(require, module){ |
---|
| 2 | // module: |
---|
| 3 | // dojo/has |
---|
| 4 | // summary: |
---|
| 5 | // Defines the has.js API and several feature tests used by dojo. |
---|
| 6 | // description: |
---|
| 7 | // This module defines the has API as described by the project has.js with the following additional features: |
---|
| 8 | // |
---|
| 9 | // - the has test cache is exposed at has.cache. |
---|
| 10 | // - the method has.add includes a forth parameter that controls whether or not existing tests are replaced |
---|
| 11 | // - the loader's has cache may be optionally copied into this module's has cahce. |
---|
| 12 | // |
---|
| 13 | // This module adopted from https://github.com/phiggins42/has.js; thanks has.js team! |
---|
| 14 | |
---|
| 15 | // try to pull the has implementation from the loader; both the dojo loader and bdLoad provide one |
---|
| 16 | // if using a foreign loader, then the has cache may be initialized via the config object for this module |
---|
| 17 | // WARNING: if a foreign loader defines require.has to be something other than the has.js API, then this implementation fail |
---|
| 18 | var has = require.has || function(){}; |
---|
| 19 | if(!has("dojo-has-api")){ |
---|
| 20 | var |
---|
| 21 | isBrowser = |
---|
| 22 | // the most fundamental decision: are we in the browser? |
---|
| 23 | typeof window != "undefined" && |
---|
| 24 | typeof location != "undefined" && |
---|
| 25 | typeof document != "undefined" && |
---|
| 26 | window.location == location && window.document == document, |
---|
| 27 | |
---|
| 28 | // has API variables |
---|
| 29 | global = this, |
---|
| 30 | doc = isBrowser && document, |
---|
| 31 | element = doc && doc.createElement("DiV"), |
---|
| 32 | cache = (module.config && module.config()) || {}; |
---|
| 33 | |
---|
| 34 | has = function(name){ |
---|
| 35 | // summary: |
---|
| 36 | // Return the current value of the named feature. |
---|
| 37 | // |
---|
| 38 | // name: String|Integer |
---|
| 39 | // The name (if a string) or identifier (if an integer) of the feature to test. |
---|
| 40 | // |
---|
| 41 | // description: |
---|
| 42 | // Returns the value of the feature named by name. The feature must have been |
---|
| 43 | // previously added to the cache by has.add. |
---|
| 44 | |
---|
| 45 | return typeof cache[name] == "function" ? (cache[name] = cache[name](global, doc, element)) : cache[name]; // Boolean |
---|
| 46 | }; |
---|
| 47 | |
---|
| 48 | has.cache = cache; |
---|
| 49 | |
---|
| 50 | has.add = function(name, test, now, force){ |
---|
| 51 | // summary: |
---|
| 52 | // Register a new feature test for some named feature. |
---|
| 53 | // name: String|Integer |
---|
| 54 | // The name (if a string) or identifier (if an integer) of the feature to test. |
---|
| 55 | // test: Function |
---|
| 56 | // A test function to register. If a function, queued for testing until actually |
---|
| 57 | // needed. The test function should return a boolean indicating |
---|
| 58 | // the presence of a feature or bug. |
---|
| 59 | // now: Boolean? |
---|
| 60 | // Optional. Omit if `test` is not a function. Provides a way to immediately |
---|
| 61 | // run the test and cache the result. |
---|
| 62 | // force: Boolean? |
---|
| 63 | // Optional. If the test already exists and force is truthy, then the existing |
---|
| 64 | // test will be replaced; otherwise, add does not replace an existing test (that |
---|
| 65 | // is, by default, the first test advice wins). |
---|
| 66 | // example: |
---|
| 67 | // A redundant test, testFn with immediate execution: |
---|
| 68 | // | has.add("javascript", function(){ return true; }, true); |
---|
| 69 | // |
---|
| 70 | // example: |
---|
| 71 | // Again with the redundantness. You can do this in your tests, but we should |
---|
| 72 | // not be doing this in any internal has.js tests |
---|
| 73 | // | has.add("javascript", true); |
---|
| 74 | // |
---|
| 75 | // example: |
---|
| 76 | // Three things are passed to the testFunction. `global`, `document`, and a generic element |
---|
| 77 | // from which to work your test should the need arise. |
---|
| 78 | // | has.add("bug-byid", function(g, d, el){ |
---|
| 79 | // | // g == global, typically window, yadda yadda |
---|
| 80 | // | // d == document object |
---|
| 81 | // | // el == the generic element. a `has` element. |
---|
| 82 | // | return false; // fake test, byid-when-form-has-name-matching-an-id is slightly longer |
---|
| 83 | // | }); |
---|
| 84 | |
---|
| 85 | (typeof cache[name]=="undefined" || force) && (cache[name]= test); |
---|
| 86 | return now && has(name); |
---|
| 87 | }; |
---|
| 88 | |
---|
| 89 | // since we're operating under a loader that doesn't provide a has API, we must explicitly initialize |
---|
| 90 | // has as it would have otherwise been initialized by the dojo loader; use has.add to the builder |
---|
| 91 | // can optimize these away iff desired |
---|
| 92 | has.add("host-browser", isBrowser); |
---|
| 93 | has.add("host-node", (typeof process == "object" && process.versions && process.versions.node && process.versions.v8)); |
---|
| 94 | has.add("host-rhino", (typeof load == "function" && (typeof Packages == "function" || typeof Packages == "object"))); |
---|
| 95 | has.add("dom", isBrowser); |
---|
| 96 | has.add("dojo-dom-ready-api", 1); |
---|
| 97 | has.add("dojo-sniff", 1); |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | if(has("host-browser")){ |
---|
| 101 | // Common application level tests |
---|
| 102 | has.add("dom-addeventlistener", !!document.addEventListener); |
---|
| 103 | has.add("touch", "ontouchstart" in document || window.navigator.msMaxTouchPoints > 0); |
---|
| 104 | // I don't know if any of these tests are really correct, just a rough guess |
---|
| 105 | has.add("device-width", screen.availWidth || innerWidth); |
---|
| 106 | |
---|
| 107 | // Tests for DOMNode.attributes[] behavior: |
---|
| 108 | // - dom-attributes-explicit - attributes[] only lists explicitly user specified attributes |
---|
| 109 | // - dom-attributes-specified-flag (IE8) - need to check attr.specified flag to skip attributes user didn't specify |
---|
| 110 | // - Otherwise, in IE6-7. attributes[] will list hundreds of values, so need to do outerHTML to get attrs instead. |
---|
| 111 | var form = document.createElement("form"); |
---|
| 112 | has.add("dom-attributes-explicit", form.attributes.length == 0); // W3C |
---|
| 113 | has.add("dom-attributes-specified-flag", form.attributes.length > 0 && form.attributes.length < 40); // IE8 |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | has.clearElement = function(element){ |
---|
| 117 | // summary: |
---|
| 118 | // Deletes the contents of the element passed to test functions. |
---|
| 119 | element.innerHTML= ""; |
---|
| 120 | return element; |
---|
| 121 | }; |
---|
| 122 | |
---|
| 123 | has.normalize = function(id, toAbsMid){ |
---|
| 124 | // summary: |
---|
| 125 | // Resolves id into a module id based on possibly-nested tenary expression that branches on has feature test value(s). |
---|
| 126 | // |
---|
| 127 | // toAbsMid: Function |
---|
| 128 | // Resolves a relative module id into an absolute module id |
---|
| 129 | var |
---|
| 130 | tokens = id.match(/[\?:]|[^:\?]*/g), i = 0, |
---|
| 131 | get = function(skip){ |
---|
| 132 | var term = tokens[i++]; |
---|
| 133 | if(term == ":"){ |
---|
| 134 | // empty string module name, resolves to 0 |
---|
| 135 | return 0; |
---|
| 136 | }else{ |
---|
| 137 | // postfixed with a ? means it is a feature to branch on, the term is the name of the feature |
---|
| 138 | if(tokens[i++] == "?"){ |
---|
| 139 | if(!skip && has(term)){ |
---|
| 140 | // matched the feature, get the first value from the options |
---|
| 141 | return get(); |
---|
| 142 | }else{ |
---|
| 143 | // did not match, get the second value, passing over the first |
---|
| 144 | get(true); |
---|
| 145 | return get(skip); |
---|
| 146 | } |
---|
| 147 | } |
---|
| 148 | // a module |
---|
| 149 | return term || 0; |
---|
| 150 | } |
---|
| 151 | }; |
---|
| 152 | id = get(); |
---|
| 153 | return id && toAbsMid(id); |
---|
| 154 | }; |
---|
| 155 | |
---|
| 156 | has.load = function(id, parentRequire, loaded){ |
---|
| 157 | // summary: |
---|
| 158 | // Conditional loading of AMD modules based on a has feature test value. |
---|
| 159 | // id: String |
---|
| 160 | // Gives the resolved module id to load. |
---|
| 161 | // parentRequire: Function |
---|
| 162 | // The loader require function with respect to the module that contained the plugin resource in it's |
---|
| 163 | // dependency list. |
---|
| 164 | // loaded: Function |
---|
| 165 | // Callback to loader that consumes result of plugin demand. |
---|
| 166 | |
---|
| 167 | if(id){ |
---|
| 168 | parentRequire([id], loaded); |
---|
| 169 | }else{ |
---|
| 170 | loaded(); |
---|
| 171 | } |
---|
| 172 | }; |
---|
| 173 | |
---|
| 174 | return has; |
---|
| 175 | }); |
---|