window.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. define(["./_base/lang", "./sniff", "./_base/window", "./dom", "./dom-geometry", "./dom-style", "./dom-construct"],
  2. function(lang, has, baseWindow, dom, geom, style, domConstruct){
  3. // feature detection
  4. /* not needed but included here for future reference
  5. has.add("rtl-innerVerticalScrollBar-on-left", function(win, doc){
  6. var body = baseWindow.body(doc),
  7. scrollable = domConstruct.create('div', {
  8. style: {overflow:'scroll', overflowX:'hidden', direction:'rtl', visibility:'hidden', position:'absolute', left:'0', width:'64px', height:'64px'}
  9. }, body, "last"),
  10. center = domConstruct.create('center', {
  11. style: {overflow:'hidden', direction:'ltr'}
  12. }, scrollable, "last"),
  13. inner = domConstruct.create('div', {
  14. style: {overflow:'visible', display:'inline' }
  15. }, center, "last");
  16. inner.innerHTML=" ";
  17. var midPoint = Math.max(inner.offsetLeft, geom.position(inner).x);
  18. var ret = midPoint >= 32;
  19. center.removeChild(inner);
  20. scrollable.removeChild(center);
  21. body.removeChild(scrollable);
  22. return ret;
  23. });
  24. */
  25. has.add("rtl-adjust-position-for-verticalScrollBar", function(win, doc){
  26. var body = baseWindow.body(doc),
  27. scrollable = domConstruct.create('div', {
  28. style: {overflow:'scroll', overflowX:'visible', direction:'rtl', visibility:'hidden', position:'absolute', left:'0', top:'0', width:'64px', height:'64px'}
  29. }, body, "last"),
  30. div = domConstruct.create('div', {
  31. style: {overflow:'hidden', direction:'ltr'}
  32. }, scrollable, "last"),
  33. ret = geom.position(div).x != 0;
  34. scrollable.removeChild(div);
  35. body.removeChild(scrollable);
  36. return ret;
  37. });
  38. has.add("position-fixed-support", function(win, doc){
  39. // IE6, IE7+quirks, and some older mobile browsers don't support position:fixed
  40. var body = baseWindow.body(doc),
  41. outer = domConstruct.create('span', {
  42. style: {visibility:'hidden', position:'fixed', left:'1px', top:'1px'}
  43. }, body, "last"),
  44. inner = domConstruct.create('span', {
  45. style: {position:'fixed', left:'0', top:'0'}
  46. }, outer, "last"),
  47. ret = geom.position(inner).x != geom.position(outer).x;
  48. outer.removeChild(inner);
  49. body.removeChild(outer);
  50. return ret;
  51. });
  52. // module:
  53. // dojo/window
  54. var window = {
  55. // summary:
  56. // TODOC
  57. getBox: function(/*Document?*/ doc){
  58. // summary:
  59. // Returns the dimensions and scroll position of the viewable area of a browser window
  60. doc = doc || baseWindow.doc;
  61. var
  62. scrollRoot = (doc.compatMode == 'BackCompat') ? baseWindow.body(doc) : doc.documentElement,
  63. // get scroll position
  64. scroll = geom.docScroll(doc), // scrollRoot.scrollTop/Left should work
  65. w, h;
  66. if(has("touch")){ // if(scrollbars not supported)
  67. var uiWindow = window.get(doc); // use UI window, not dojo.global window
  68. // on mobile, scrollRoot.clientHeight <= uiWindow.innerHeight <= scrollRoot.offsetHeight, return uiWindow.innerHeight
  69. w = uiWindow.innerWidth || scrollRoot.clientWidth; // || scrollRoot.clientXXX probably never evaluated
  70. h = uiWindow.innerHeight || scrollRoot.clientHeight;
  71. }else{
  72. // on desktops, scrollRoot.clientHeight <= scrollRoot.offsetHeight <= uiWindow.innerHeight, return scrollRoot.clientHeight
  73. // uiWindow.innerWidth/Height includes the scrollbar and cannot be used
  74. w = scrollRoot.clientWidth;
  75. h = scrollRoot.clientHeight;
  76. }
  77. return {
  78. l: scroll.x,
  79. t: scroll.y,
  80. w: w,
  81. h: h
  82. };
  83. },
  84. get: function(/*Document*/ doc){
  85. // summary:
  86. // Get window object associated with document doc.
  87. // doc:
  88. // The document to get the associated window for.
  89. // In some IE versions (at least 6.0), document.parentWindow does not return a
  90. // reference to the real window object (maybe a copy), so we must fix it as well
  91. // We use IE specific execScript to attach the real window reference to
  92. // document._parentWindow for later use
  93. if(has("ie") && window !== document.parentWindow){
  94. /*
  95. In IE 6, only the variable "window" can be used to connect events (others
  96. may be only copies).
  97. */
  98. doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
  99. //to prevent memory leak, unset it after use
  100. //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
  101. var win = doc._parentWindow;
  102. doc._parentWindow = null;
  103. return win; // Window
  104. }
  105. return doc.parentWindow || doc.defaultView; // Window
  106. },
  107. scrollIntoView: function(/*DomNode*/ node, /*Object?*/ pos){
  108. // summary:
  109. // Scroll the passed node into view using minimal movement, if it is not already.
  110. // Don't rely on node.scrollIntoView working just because the function is there since
  111. // it forces the node to the page's bottom or top (and left or right in IE) without consideration for the minimal movement.
  112. // WebKit's node.scrollIntoViewIfNeeded doesn't work either for inner scrollbars in right-to-left mode
  113. // and when there's a fixed position scrollable element
  114. try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
  115. node = dom.byId(node);
  116. var doc = node.ownerDocument || baseWindow.doc, // TODO: why baseWindow.doc? Isn't node.ownerDocument always defined?
  117. body = baseWindow.body(doc),
  118. html = doc.documentElement || body.parentNode,
  119. isIE = has("ie"),
  120. isWK = has("webkit");
  121. // if an untested browser, then use the native method
  122. if(node == body || node == html){ return; }
  123. if(!(has("mozilla") || isIE || isWK || has("opera") || has("trident")) && ("scrollIntoView" in node)){
  124. node.scrollIntoView(false); // short-circuit to native if possible
  125. return;
  126. }
  127. var backCompat = doc.compatMode == 'BackCompat',
  128. rootWidth = Math.min(body.clientWidth || html.clientWidth, html.clientWidth || body.clientWidth),
  129. rootHeight = Math.min(body.clientHeight || html.clientHeight, html.clientHeight || body.clientHeight),
  130. scrollRoot = (isWK || backCompat) ? body : html,
  131. nodePos = pos || geom.position(node),
  132. el = node.parentNode,
  133. isFixed = function(el){
  134. return (isIE <= 6 || (isIE == 7 && backCompat))
  135. ? false
  136. : (has("position-fixed-support") && (style.get(el, 'position').toLowerCase() == "fixed"));
  137. },
  138. self = this,
  139. scrollElementBy = function(el, x, y){
  140. if(el.tagName == "BODY" || el.tagName == "HTML"){
  141. self.get(el.ownerDocument).scrollBy(x, y);
  142. }else{
  143. x && (el.scrollLeft += x);
  144. y && (el.scrollTop += y);
  145. }
  146. };
  147. if(isFixed(node)){ return; } // nothing to do
  148. while(el){
  149. if(el == body){ el = scrollRoot; }
  150. var elPos = geom.position(el),
  151. fixedPos = isFixed(el),
  152. rtl = style.getComputedStyle(el).direction.toLowerCase() == "rtl";
  153. if(el == scrollRoot){
  154. elPos.w = rootWidth; elPos.h = rootHeight;
  155. if(scrollRoot == html && (isIE || has("trident")) && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
  156. if(elPos.x < 0 || !isIE || isIE >= 9 || has("trident")){ elPos.x = 0; } // older IE can have values > 0
  157. if(elPos.y < 0 || !isIE || isIE >= 9 || has("trident")){ elPos.y = 0; }
  158. }else{
  159. var pb = geom.getPadBorderExtents(el);
  160. elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
  161. var clientSize = el.clientWidth,
  162. scrollBarSize = elPos.w - clientSize;
  163. if(clientSize > 0 && scrollBarSize > 0){
  164. if(rtl && has("rtl-adjust-position-for-verticalScrollBar")){
  165. elPos.x += scrollBarSize;
  166. }
  167. elPos.w = clientSize;
  168. }
  169. clientSize = el.clientHeight;
  170. scrollBarSize = elPos.h - clientSize;
  171. if(clientSize > 0 && scrollBarSize > 0){
  172. elPos.h = clientSize;
  173. }
  174. }
  175. if(fixedPos){ // bounded by viewport, not parents
  176. if(elPos.y < 0){
  177. elPos.h += elPos.y; elPos.y = 0;
  178. }
  179. if(elPos.x < 0){
  180. elPos.w += elPos.x; elPos.x = 0;
  181. }
  182. if(elPos.y + elPos.h > rootHeight){
  183. elPos.h = rootHeight - elPos.y;
  184. }
  185. if(elPos.x + elPos.w > rootWidth){
  186. elPos.w = rootWidth - elPos.x;
  187. }
  188. }
  189. // calculate overflow in all 4 directions
  190. var l = nodePos.x - elPos.x, // beyond left: < 0
  191. // t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
  192. t = nodePos.y - elPos.y, // beyond top: < 0
  193. r = l + nodePos.w - elPos.w, // beyond right: > 0
  194. bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
  195. var s, old;
  196. if(r * l > 0 && (!!el.scrollLeft || el == scrollRoot || el.scrollWidth > el.offsetHeight)){
  197. s = Math[l < 0? "max" : "min"](l, r);
  198. if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9 || has("trident"))){ s = -s; }
  199. old = el.scrollLeft;
  200. scrollElementBy(el, s, 0);
  201. s = el.scrollLeft - old;
  202. nodePos.x -= s;
  203. }
  204. if(bot * t > 0 && (!!el.scrollTop || el == scrollRoot || el.scrollHeight > el.offsetHeight)){
  205. s = Math.ceil(Math[t < 0? "max" : "min"](t, bot));
  206. old = el.scrollTop;
  207. scrollElementBy(el, 0, s);
  208. s = el.scrollTop - old;
  209. nodePos.y -= s;
  210. }
  211. el = (el != scrollRoot) && !fixedPos && el.parentNode;
  212. }
  213. }catch(error){
  214. console.error('scrollIntoView: ' + error);
  215. node.scrollIntoView(false);
  216. }
  217. }
  218. };
  219. has("extend-dojo") && lang.setObject("dojo.window", window);
  220. return window;
  221. });