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