API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPCompatibility.j
Go to the documentation of this file.
1 /*
2  * CPCompatibility.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 // Browser Engines
32 
33 // Operating Systems
37 
38 // Features
40 
44 
51 
52 CPVMLFeature = 1 << 15;
53 
56 
59 
61 
62 //Internet explorer does not allow dynamically changing the type of an input element
65 
67 
68 // element.style.font can be set for an element not in the DOM.
70 
71 // Input elements have 1 px of extra padding on the left regardless of padding setting.
74 
75 // When an absolutely positioned div (CPView) with an absolutely positioned canvas in it (CPView with drawRect:) moves things on top of the canvas
76 // (subviews) don't redraw correctly. E.g. if you have a bunch of text fields in a CPBox in a sheet which animates in, some of the text fields might
77 // not be visible because the CPBox has a canvas at the bottom and the box moved form offscreen to onscreen.
78 // This bug is probably very related: https://bugs.webkit.org/show_bug.cgi?id=67203
80 
81 var USER_AGENT = "",
86 
87 // default these features to true
88 
91 
92 if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
93  USER_AGENT = window.navigator.userAgent;
94 
95 // Opera
96 if (typeof window !== "undefined" && window.opera)
97 {
99 
101 }
102 
103 // Internet Explorer
104 else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
105 {
107 
108  // Features we can only be sure of with IE (no known independent tests)
112 
114 
116 
117  // Tested in Internet Explore 8 and 9.
119 }
120 
121 // WebKit
122 else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
123 {
125 
126  // Features we can only be sure of with WebKit (no known independent tests)
129 
130  if (USER_AGENT.indexOf("Chrome") === -1)
132 
136 
137  var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
138  versionEnd = USER_AGENT.indexOf(" ", versionStart),
139  versionString = USER_AGENT.substring(versionStart, versionEnd),
140  versionDivision = versionString.indexOf('.'),
141  majorVersion = parseInt(versionString.substring(0, versionDivision)),
142  minorVersion = parseInt(versionString.substr(versionDivision + 1));
143 
144  if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
146 
147  // FIXME this is a terrible hack to get around this bug:
148  // https://bugs.webkit.org/show_bug.cgi?id=21548
149  if (![CPPlatform isBrowser])
151 
152  if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
154 
155  // This is supposedly fixed in webkit r123603. Seems to work in Chrome 21 but not Safari 6.0.
156  if (majorVersion < 537)
158 
159  if (USER_AGENT.indexOf("Chrome") === CPNotFound)
161 
162  // Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
163  if (majorVersion > 533)
165 }
166 
167 // KHTML
168 else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
169 {
171 }
172 
173 // Gecko
174 else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
175 {
177 
179 
180  var index = USER_AGENT.indexOf("Firefox"),
181  version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
182 
183  if (version >= 3.0)
185 
186  if (version < 3.0)
188 
189  // Some day this might be fixed and should be version prefixed. No known fixed version yet.
191 }
192 
193 // Feature Specific Checks
194 if (typeof document != "undefined")
195 {
196  var canvasElement = document.createElement("canvas");
197  // Detect Canvas Support
198  if (canvasElement && canvasElement.getContext)
199  {
201 
202  // Detect Canvas setTransform/transform support
203  var context = document.createElement("canvas").getContext("2d");
204 
205  if (context && context.setTransform && context.transform)
207  }
208 
209  var DOMElement = document.createElement("div");
210 
211  // Detect whether we have innerText or textContent (or neither)
212  if (DOMElement.innerText != undefined)
214  else if (DOMElement.textContent != undefined)
216 
217  var DOMInputElement = document.createElement("input");
218  if ("oninput" in DOMInputElement)
220  else if (typeof DOMInputElement.setAttribute === "function")
221  {
222  DOMInputElement.setAttribute("oninput", "return;");
223  if (typeof DOMInputElement.oninput === "function")
225  }
226 }
227 
228 function CPFeatureIsCompatible(aFeature)
229 {
230  return PLATFORM_FEATURES & aFeature;
231 }
232 
233 function CPPlatformHasBug(aBug)
234 {
235  return PLATFORM_BUGS & aBug;
236 }
237 
238 function CPBrowserIsEngine(anEngine)
239 {
240  return PLATFORM_ENGINE === anEngine;
241 }
242 
243 function CPBrowserIsOperatingSystem(anOperatingSystem)
244 {
245  return OPERATING_SYSTEM === anOperatingSystem;
246 }
247 
249 
250 if (USER_AGENT.indexOf("Mac") !== -1)
251 {
253 
255 
256  CPUndoKeyEquivalent = @"z";
257  CPRedoKeyEquivalent = @"Z";
258 
261 }
262 else
263 {
264  if (USER_AGENT.indexOf("Windows") !== -1)
266 
268 
271 
274 }
275 
285 function CPBrowserStyleProperty(aProperty)
286 {
287  var lowerProperty = aProperty.toLowerCase();
288 
289  if (PLATFORM_STYLE_JS_PROPERTIES[lowerProperty] === undefined)
290  {
291  var r = nil;
292 
293 #if PLATFORM(DOM)
294  var testElement = document.createElement('div');
295 
296  switch (lowerProperty)
297  {
298  case 'transitionend':
299  var candidates = {
300  'WebkitTransition' : 'webkitTransitionEnd',
301  'MozTransition' : 'transitionend',
302  'OTransition' : 'oTransitionEnd',
303  'msTransition' : 'MSTransitionEnd',
304  'transition' : 'transitionend'
305  };
306 
307  r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transition']] || nil;
308  break;
309  default:
310  var prefixes = ["Webkit", "Moz", "O", "ms"],
311  strippedProperty = aProperty.split('-').join(' '),
312  capProperty = [strippedProperty capitalizedString].split(' ').join('');
313 
314  for (var i = 0; i < prefixes.length; i++)
315  {
316  // First check if the property is already valid without being formatted, otherwise try the capitalized property
317  if (prefixes[i] + aProperty in testElement.style)
318  {
319  r = prefixes[i] + aProperty;
320  break;
321  }
322  else if (prefixes[i] + capProperty in testElement.style)
323  {
324  r = prefixes[i] + capProperty;
325  break;
326  }
327  }
328 
329  if (!r && lowerProperty in testElement.style)
330  r = lowerProperty;
331 
332  break;
333  }
334 #endif
335 
336  PLATFORM_STYLE_JS_PROPERTIES[lowerProperty] = r;
337  }
338 
339  return PLATFORM_STYLE_JS_PROPERTIES[lowerProperty];
340 }
341 
342 function CPBrowserCSSProperty(aProperty)
343 {
344  var browserProperty = CPBrowserStyleProperty(aProperty);
345 
346  if (!browserProperty)
347  return nil;
348 
349  var prefixes = {
350  'Webkit': '-webkit-',
351  'Moz': '-moz-',
352  'O': '-o-',
353  'ms': '-ms-'
354  };
355 
356  for (var prefix in prefixes)
357  {
358  if (browserProperty.substring(0, prefix.length) == prefix)
359  {
360  var browserPropertyWithoutPrefix = browserProperty.substring(prefix.length),
361  parts = browserPropertyWithoutPrefix.match(/[A-Z][a-z]+/g);
362 
363  // If there were any capitalized words in the browserProperty, insert a "-" between each one
364  if (parts && parts.length > 0)
365  browserPropertyWithoutPrefix = parts.join("-");
366 
367  return prefixes[prefix] + browserPropertyWithoutPrefix.toLowerCase();
368  }
369  }
370 
371  var parts = browserProperty.match(/[A-Z][a-z]+/g);
372 
373  if (parts && parts.length > 0)
374  browserProperty = parts.join("-");
375 
376  return browserProperty.toLowerCase();
377 }