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