Просмотр исходного кода

remove jq for many dom geom utils

Adam Shaw 8 лет назад
Родитель
Сommit
f7201f7cb3

+ 6 - 5
src/agenda/AgendaView.ts

@@ -1,5 +1,4 @@
 import * as moment from 'moment'
 import * as moment from 'moment'
-import * as $ from 'jquery'
 import {
 import {
   matchCellWidths,
   matchCellWidths,
   uncompensateScroll,
   uncompensateScroll,
@@ -177,7 +176,7 @@ export default class AgendaView extends View {
     super.updateSize(totalHeight, isAuto, isResize)
     super.updateSize(totalHeight, isAuto, isResize)
 
 
     // make all axis cells line up, and record the width so newly created axis cells will have it
     // make all axis cells line up, and record the width so newly created axis cells will have it
-    this.axisWidth = matchCellWidths($(this.el.querySelectorAll('.fc-axis')))
+    this.axisWidth = matchCellWidths(findElsWithin(this.el, '.fc-axis'))
 
 
     // hack to give the view some height prior to timeGrid's columns being rendered
     // hack to give the view some height prior to timeGrid's columns being rendered
     // TODO: separate setting height from scroller VS timeGrid.
     // TODO: separate setting height from scroller VS timeGrid.
@@ -197,7 +196,7 @@ export default class AgendaView extends View {
     // reset all dimensions back to the original state
     // reset all dimensions back to the original state
     this.timeGrid.bottomRuleEl.style.display = 'none' // will be shown later if this <hr> is necessary
     this.timeGrid.bottomRuleEl.style.display = 'none' // will be shown later if this <hr> is necessary
     this.scroller.clear() // sets height to 'auto' and clears overflow
     this.scroller.clear() // sets height to 'auto' and clears overflow
-    uncompensateScroll($(noScrollRowEls))
+    noScrollRowEls.forEach(uncompensateScroll)
 
 
     // limit number of events in the all-day area
     // limit number of events in the all-day area
     if (this.dayGrid) {
     if (this.dayGrid) {
@@ -221,7 +220,9 @@ export default class AgendaView extends View {
       if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars?
       if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars?
 
 
         // make the all-day and header rows lines up
         // make the all-day and header rows lines up
-        compensateScroll($(noScrollRowEls), scrollbarWidths)
+        noScrollRowEls.forEach(function(rowEl) {
+          compensateScroll(rowEl, scrollbarWidths)
+        })
 
 
         // the scrollbar compensation might have changed text flow, which might affect height, so recalculate
         // the scrollbar compensation might have changed text flow, which might affect height, so recalculate
         // and reapply the desired height to the scroller.
         // and reapply the desired height to the scroller.
@@ -244,7 +245,7 @@ export default class AgendaView extends View {
   // given a desired total height of the view, returns what the height of the scroller should be
   // given a desired total height of the view, returns what the height of the scroller should be
   computeScrollerHeight(totalHeight) {
   computeScrollerHeight(totalHeight) {
     return totalHeight -
     return totalHeight -
-      subtractInnerElHeight($(this.el), $(this.scroller.el)) // everything that's NOT the scroller
+      subtractInnerElHeight(this.el, this.scroller.el) // everything that's NOT the scroller
   }
   }
 
 
 
 

+ 8 - 9
src/basic/BasicView.ts

@@ -1,4 +1,3 @@
-import * as $ from 'jquery'
 import {
 import {
   matchCellWidths,
   matchCellWidths,
   uncompensateScroll,
   uncompensateScroll,
@@ -8,7 +7,7 @@ import {
   undistributeHeight,
   undistributeHeight,
   htmlEscape
   htmlEscape
 } from '../util'
 } from '../util'
-import { makeElement } from '../util/dom'
+import { makeElement, findElsWithin } from '../util/dom'
 import Scroller from '../common/Scroller'
 import Scroller from '../common/Scroller'
 import View from '../View'
 import View from '../View'
 import BasicViewDateProfileGenerator from './BasicViewDateProfileGenerator'
 import BasicViewDateProfileGenerator from './BasicViewDateProfileGenerator'
@@ -153,7 +152,7 @@ export default class BasicView extends View {
     let eventLimit = this.opt('eventLimit')
     let eventLimit = this.opt('eventLimit')
     let headRowEl =
     let headRowEl =
       dayGrid.headContainerEl ?
       dayGrid.headContainerEl ?
-        dayGrid.headContainerEl.querySelector('.fc-row') :
+        dayGrid.headContainerEl.querySelector('.fc-row') as HTMLElement :
         null
         null
     let scrollerHeight
     let scrollerHeight
     let scrollbarWidths
     let scrollbarWidths
@@ -174,14 +173,14 @@ export default class BasicView extends View {
       // Make sure all week number cells running down the side have the same width.
       // Make sure all week number cells running down the side have the same width.
       // Record the width for cells created later.
       // Record the width for cells created later.
       this.weekNumberWidth = matchCellWidths(
       this.weekNumberWidth = matchCellWidths(
-        $(this.el.querySelectorAll('.fc-week-number'))
+        findElsWithin(this.el, '.fc-week-number')
       )
       )
     }
     }
 
 
     // reset all heights to be natural
     // reset all heights to be natural
     this.scroller.clear()
     this.scroller.clear()
     if (headRowEl) {
     if (headRowEl) {
-      uncompensateScroll($(headRowEl))
+      uncompensateScroll(headRowEl)
     }
     }
 
 
     dayGrid.removeSegPopover() // kill the "more" popover if displayed
     dayGrid.removeSegPopover() // kill the "more" popover if displayed
@@ -209,7 +208,7 @@ export default class BasicView extends View {
       if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars?
       if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars?
 
 
         if (headRowEl) {
         if (headRowEl) {
-          compensateScroll($(headRowEl), scrollbarWidths)
+          compensateScroll(headRowEl, scrollbarWidths)
         }
         }
 
 
         // doing the scrollbar compensation might have created text overflow which created more height. redo
         // doing the scrollbar compensation might have created text overflow which created more height. redo
@@ -226,16 +225,16 @@ export default class BasicView extends View {
   // given a desired total height of the view, returns what the height of the scroller should be
   // given a desired total height of the view, returns what the height of the scroller should be
   computeScrollerHeight(totalHeight) {
   computeScrollerHeight(totalHeight) {
     return totalHeight -
     return totalHeight -
-      subtractInnerElHeight($(this.el), $(this.scroller.el)) // everything that's NOT the scroller
+      subtractInnerElHeight(this.el, this.scroller.el) // everything that's NOT the scroller
   }
   }
 
 
 
 
   // Sets the height of just the DayGrid component in this view
   // Sets the height of just the DayGrid component in this view
   setGridHeight(height, isAuto) {
   setGridHeight(height, isAuto) {
     if (isAuto) {
     if (isAuto) {
-      undistributeHeight($(this.dayGrid.rowEls)) // let the rows be their natural height with no expanding
+      undistributeHeight(this.dayGrid.rowEls) // let the rows be their natural height with no expanding
     } else {
     } else {
-      distributeHeight($(this.dayGrid.rowEls), height, true) // true = compensate for height-hogging rows
+      distributeHeight(this.dayGrid.rowEls, height, true) // true = compensate for height-hogging rows
     }
     }
   }
   }
 
 

+ 1 - 2
src/basic/MonthView.ts

@@ -1,4 +1,3 @@
-import * as $ from 'jquery'
 import * as moment from 'moment'
 import * as moment from 'moment'
 import { distributeHeight } from '../util'
 import { distributeHeight } from '../util'
 import BasicView from './BasicView'
 import BasicView from './BasicView'
@@ -18,7 +17,7 @@ export default class MonthView extends BasicView {
       height *= this.dayGrid.rowCnt / 6
       height *= this.dayGrid.rowCnt / 6
     }
     }
 
 
-    distributeHeight($(this.dayGrid.rowEls), height, !isAuto) // if auto, don't compensate for height-hogging rows
+    distributeHeight(this.dayGrid.rowEls, height, !isAuto) // if auto, don't compensate for height-hogging rows
   }
   }
 
 
 
 

+ 5 - 6
src/common/CoordCache.ts

@@ -1,5 +1,4 @@
-import * as $ from 'jquery'
-import { getClientRect, getScrollParent } from '../util'
+import { getInnerRect, getScrollParent } from '../util'
 
 
 export interface CoordCacheOptions {
 export interface CoordCacheOptions {
   els: HTMLElement[]
   els: HTMLElement[]
@@ -237,13 +236,13 @@ export default class CoordCache {
   // Right now, only returns a rectangle if constrained by an overflow:scroll element.
   // Right now, only returns a rectangle if constrained by an overflow:scroll element.
   // Returns null if there are no elements
   // Returns null if there are no elements
   queryBoundingRect() {
   queryBoundingRect() {
-    let scrollParentEl
+    let scrollParentEl: HTMLElement
 
 
     if (this.els.length > 0) {
     if (this.els.length > 0) {
-      scrollParentEl = getScrollParent($(this.els[0]))
+      scrollParentEl = getScrollParent(this.els[0])
 
 
-      if (!scrollParentEl.is(document)) {
-        return getClientRect(scrollParentEl)
+      if (scrollParentEl) {
+        return getInnerRect(scrollParentEl)
       }
       }
     }
     }
 
 

+ 4 - 8
src/common/DragListener.ts

@@ -42,7 +42,7 @@ export default class DragListener {
   originY: any
   originY: any
 
 
   // the wrapping element that scrolls, or MIGHT scroll if there's overflow.
   // the wrapping element that scrolls, or MIGHT scroll if there's overflow.
-  // TODO: do this for wrappers that have overflow:hidden as well.
+  // within the body. so, can't be the body/document/window. might be null
   scrollEl: HTMLElement
   scrollEl: HTMLElement
 
 
   isInteracting: boolean = false
   isInteracting: boolean = false
@@ -110,7 +110,7 @@ export default class DragListener {
 
 
       this.originX = getEvX(ev)
       this.originX = getEvX(ev)
       this.originY = getEvY(ev)
       this.originY = getEvY(ev)
-      this.scrollEl = getScrollParent($(ev.target))[0]
+      this.scrollEl = getScrollParent(ev.target)
 
 
       this.bindHandlers()
       this.bindHandlers()
       this.initAutoScroll()
       this.initAutoScroll()
@@ -354,11 +354,7 @@ export default class DragListener {
   initAutoScroll() {
   initAutoScroll() {
     let scrollEl = this.scrollEl
     let scrollEl = this.scrollEl
 
 
-    this.isAutoScroll =
-      this.options.scroll &&
-      scrollEl &&
-      scrollEl !== (window as any) &&
-      scrollEl !== (document as any)
+    this.isAutoScroll = Boolean(this.options.scroll && scrollEl)
 
 
     if (this.isAutoScroll) {
     if (this.isAutoScroll) {
       // debounce makes sure rapid calls don't happen
       // debounce makes sure rapid calls don't happen
@@ -381,7 +377,7 @@ export default class DragListener {
   computeScrollBounds() {
   computeScrollBounds() {
     if (this.isAutoScroll) {
     if (this.isAutoScroll) {
       this.scrollBounds = this.scrollEl.getBoundingClientRect()
       this.scrollBounds = this.scrollEl.getBoundingClientRect()
-      // TODO: use getClientRect in future. but prevents auto scrolling when on top of scrollbars
+      // TODO: use getInnerRect in future. but prevents auto scrolling when on top of scrollbars
     }
     }
   }
   }
 
 

+ 4 - 9
src/common/Popover.ts

@@ -120,7 +120,7 @@ export default class Popover {
     let options = this.options
     let options = this.options
     let el = this.el
     let el = this.el
     let rect = el.getBoundingClientRect()
     let rect = el.getBoundingClientRect()
-    let viewportEl = getScrollParent($(el))[0]
+    let scrollEl = getScrollParent(el)
     let viewportRect
     let viewportRect
     let top // the "position" (not "offset") values for the popover
     let top // the "position" (not "offset") values for the popover
     let left //
     let left //
@@ -135,20 +135,15 @@ export default class Popover {
       left = 0
       left = 0
     }
     }
 
 
-    // normalize getScrollParent's result
-    if (viewportEl === (document as any)) {
-      viewportEl = (window as any)
-    }
-
-    if (viewportEl === (window as any)) {
+    if (scrollEl) {
+      viewportRect = scrollEl.getBoundingClientRect()
+    } else {
       viewportRect = {
       viewportRect = {
         top: 0,
         top: 0,
         left: 0,
         left: 0,
         width: document.documentElement.clientWidth,
         width: document.documentElement.clientWidth,
         height: document.documentElement.clientHeight
         height: document.documentElement.clientHeight
       }
       }
-    } else {
-      viewportRect = viewportEl.getBoundingClientRect()
     }
     }
 
 
     // constrain to the view port. if constrained by two edges, give precedence to top/left
     // constrain to the view port. if constrained by two edges, give precedence to top/left

+ 7 - 3
src/common/Scroller.ts

@@ -1,5 +1,4 @@
-import * as $ from 'jquery'
-import { getScrollbarWidths } from '../util'
+import { getEdges } from '../util'
 import { removeElement } from '../util/dom'
 import { removeElement } from '../util/dom'
 import Class from '../common/Class'
 import Class from '../common/Class'
 
 
@@ -124,7 +123,12 @@ export default class Scroller extends Class {
 
 
 
 
   getScrollbarWidths() {
   getScrollbarWidths() {
-    return getScrollbarWidths($(this.scrollEl))
+    let edges = getEdges(this.scrollEl)
+    return {
+      left: edges.scrollbarLeft,
+      right: edges.scrollbarRight,
+      bottom: edges.scrollbarBottom
+    }
   }
   }
 
 
 }
 }

+ 2 - 3
src/exports.ts

@@ -21,9 +21,8 @@ export {
   cssToStr,
   cssToStr,
   proxy,
   proxy,
   capitaliseFirstLetter,
   capitaliseFirstLetter,
-  getClientRect,
-  getContentRect,
-  getScrollbarWidths,
+  getInnerRect,
+  getEdges,
   preventDefault,
   preventDefault,
   parseFieldSpecs,
   parseFieldSpecs,
   compareByFieldSpecs,
   compareByFieldSpecs,

+ 1 - 2
src/list/ListView.ts

@@ -1,4 +1,3 @@
-import * as $ from 'jquery'
 import { htmlEscape, subtractInnerElHeight } from '../util'
 import { htmlEscape, subtractInnerElHeight } from '../util'
 import { htmlToElement, makeElement } from '../util/dom'
 import { htmlToElement, makeElement } from '../util/dom'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
@@ -68,7 +67,7 @@ export default class ListView extends View {
 
 
   computeScrollerHeight(totalHeight) {
   computeScrollerHeight(totalHeight) {
     return totalHeight -
     return totalHeight -
-      subtractInnerElHeight($(this.el), $(this.scroller.el)) // everything that's NOT the scroller
+      subtractInnerElHeight(this.el, this.scroller.el) // everything that's NOT the scroller
   }
   }
 
 
 
 

+ 120 - 102
src/util.ts

@@ -1,5 +1,5 @@
 import * as moment from 'moment'
 import * as moment from 'moment'
-import * as $ from 'jquery'
+import { applyStyle, computeHeightAndMargins } from './util/dom'
 
 
 
 
 /* FullCalendar-specific DOM Utilities
 /* FullCalendar-specific DOM Utilities
@@ -8,42 +8,42 @@ import * as $ from 'jquery'
 
 
 // Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left
 // Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left
 // and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that.
 // and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that.
-export function compensateScroll(rowEls: JQuery, scrollbarWidths) {
+export function compensateScroll(rowEl: HTMLElement, scrollbarWidths) {
   if (scrollbarWidths.left) {
   if (scrollbarWidths.left) {
-    rowEls.css({
-      'border-left-width': 1,
-      'margin-left': scrollbarWidths.left - 1
+    applyStyle(rowEl, {
+      borderLeftWidth: 1,
+      marginLeft: scrollbarWidths.left - 1
     })
     })
   }
   }
   if (scrollbarWidths.right) {
   if (scrollbarWidths.right) {
-    rowEls.css({
-      'border-right-width': 1,
-      'margin-right': scrollbarWidths.right - 1
+    applyStyle(rowEl, {
+      borderRightWidth: 1,
+      marginRight: scrollbarWidths.right - 1
     })
     })
   }
   }
 }
 }
 
 
 
 
 // Undoes compensateScroll and restores all borders/margins
 // Undoes compensateScroll and restores all borders/margins
-export function uncompensateScroll(rowEls: JQuery) {
-  rowEls.css({
-    'margin-left': '',
-    'margin-right': '',
-    'border-left-width': '',
-    'border-right-width': ''
+export function uncompensateScroll(rowEl: HTMLElement) {
+  applyStyle(rowEl, {
+    marginLeft: '',
+    marginRight: '',
+    borderLeftWidth: '',
+    borderRightWidth: ''
   })
   })
 }
 }
 
 
 
 
 // Make the mouse cursor express that an event is not allowed in the current area
 // Make the mouse cursor express that an event is not allowed in the current area
 export function disableCursor() {
 export function disableCursor() {
-  $('body').addClass('fc-not-allowed')
+  document.body.classList.add('fc-not-allowed')
 }
 }
 
 
 
 
 // Returns the mouse cursor to its original look
 // Returns the mouse cursor to its original look
 export function enableCursor() {
 export function enableCursor() {
-  $('body').removeClass('fc-not-allowed')
+  document.body.classList.remove('fc-not-allowed')
 }
 }
 
 
 
 
@@ -51,7 +51,7 @@ export function enableCursor() {
 // By default, all elements that are shorter than the recommended height are expanded uniformly, not considering
 // By default, all elements that are shorter than the recommended height are expanded uniformly, not considering
 // any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and
 // any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and
 // reduces the available height.
 // reduces the available height.
-export function distributeHeight(els: JQuery, availableHeight, shouldRedistribute) {
+export function distributeHeight(els: HTMLElement[], availableHeight, shouldRedistribute) {
 
 
   // *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions,
   // *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions,
   // and it is better to be shorter than taller, to avoid creating unnecessary scrollbars.
   // and it is better to be shorter than taller, to avoid creating unnecessary scrollbars.
@@ -67,14 +67,14 @@ export function distributeHeight(els: JQuery, availableHeight, shouldRedistribut
 
 
   // find elements that are below the recommended height (expandable).
   // find elements that are below the recommended height (expandable).
   // important to query for heights in a single first pass (to avoid reflow oscillation).
   // important to query for heights in a single first pass (to avoid reflow oscillation).
-  els.each(function(i, el) {
+  els.forEach(function(el, i) {
     let minOffset = i === els.length - 1 ? minOffset2 : minOffset1
     let minOffset = i === els.length - 1 ? minOffset2 : minOffset1
-    let naturalOffset = $(el).outerHeight(true)
+    let naturalOffset = computeHeightAndMargins(el)
 
 
     if (naturalOffset < minOffset) {
     if (naturalOffset < minOffset) {
       flexEls.push(el)
       flexEls.push(el)
       flexOffsets.push(naturalOffset)
       flexOffsets.push(naturalOffset)
-      flexHeights.push($(el).height())
+      flexHeights.push(el.offsetHeight)
     } else {
     } else {
       // this element stretches past recommended height (non-expandable). mark the space as occupied.
       // this element stretches past recommended height (non-expandable). mark the space as occupied.
       usedHeight += naturalOffset
       usedHeight += naturalOffset
@@ -89,41 +89,48 @@ export function distributeHeight(els: JQuery, availableHeight, shouldRedistribut
   }
   }
 
 
   // assign heights to all expandable elements
   // assign heights to all expandable elements
-  $(flexEls).each(function(i, el) {
+  flexEls.forEach(function(el, i) {
     let minOffset = i === flexEls.length - 1 ? minOffset2 : minOffset1
     let minOffset = i === flexEls.length - 1 ? minOffset2 : minOffset1
     let naturalOffset = flexOffsets[i]
     let naturalOffset = flexOffsets[i]
     let naturalHeight = flexHeights[i]
     let naturalHeight = flexHeights[i]
     let newHeight = minOffset - (naturalOffset - naturalHeight) // subtract the margin/padding
     let newHeight = minOffset - (naturalOffset - naturalHeight) // subtract the margin/padding
 
 
     if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things
     if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things
-      $(el).height(newHeight)
+      el.style.height = newHeight + 'px'
     }
     }
   })
   })
 }
 }
 
 
 
 
 // Undoes distrubuteHeight, restoring all els to their natural height
 // Undoes distrubuteHeight, restoring all els to their natural height
-export function undistributeHeight(els: JQuery) {
-  els.height('')
+export function undistributeHeight(els: HTMLElement[]) {
+  els.forEach(function(el) {
+    el.style.height = ''
+  })
 }
 }
 
 
 
 
 // Given `els`, a jQuery set of <td> cells, find the cell with the largest natural width and set the widths of all the
 // Given `els`, a jQuery set of <td> cells, find the cell with the largest natural width and set the widths of all the
 // cells to be that width.
 // cells to be that width.
 // PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline
 // PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline
-export function matchCellWidths(els: JQuery) {
+export function matchCellWidths(els: HTMLElement[]) {
   let maxInnerWidth = 0
   let maxInnerWidth = 0
 
 
-  els.find('> *').each(function(i, innerEl) {
-    let innerWidth = $(innerEl).outerWidth()
-    if (innerWidth > maxInnerWidth) {
-      maxInnerWidth = innerWidth
+  els.forEach(function(el) {
+    let innerEl = el.firstChild // hopefully an element
+    if (innerEl instanceof HTMLElement) {
+      let innerWidth = innerEl.offsetWidth
+      if (innerWidth > maxInnerWidth) {
+        maxInnerWidth = innerWidth
+      }
     }
     }
   })
   })
 
 
   maxInnerWidth++ // sometimes not accurate of width the text needs to stay on one line. insurance
   maxInnerWidth++ // sometimes not accurate of width the text needs to stay on one line. insurance
 
 
-  els.width(maxInnerWidth)
+  els.forEach(function(el) {
+    el.style.width = maxInnerWidth + 'px'
+  })
 
 
   return maxInnerWidth
   return maxInnerWidth
 }
 }
@@ -131,17 +138,22 @@ export function matchCellWidths(els: JQuery) {
 
 
 // Given one element that resides inside another,
 // Given one element that resides inside another,
 // Subtracts the height of the inner element from the outer element.
 // Subtracts the height of the inner element from the outer element.
-export function subtractInnerElHeight(outerEl: JQuery, innerEl: JQuery) {
-  let both = outerEl.add(innerEl)
-  let diff
+export function subtractInnerElHeight(outerEl: HTMLElement, innerEl: HTMLElement) {
 
 
   // effin' IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked
   // effin' IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked
-  both.css({
+  let reflowStyleProps = {
     position: 'relative', // cause a reflow, which will force fresh dimension recalculation
     position: 'relative', // cause a reflow, which will force fresh dimension recalculation
     left: -1 // ensure reflow in case the el was already relative. negative is less likely to cause new scroll
     left: -1 // ensure reflow in case the el was already relative. negative is less likely to cause new scroll
-  })
-  diff = outerEl.outerHeight() - innerEl.outerHeight() // grab the dimensions
-  both.css({ position: '', left: '' }) // undo hack
+  }
+  applyStyle(outerEl, reflowStyleProps)
+  applyStyle(innerEl, reflowStyleProps)
+
+  let diff = outerEl.offsetHeight - innerEl.offsetHeight // grab the dimensions
+
+  // undo hack
+  let resetStyleProps = { position: '', left: '' }
+  applyStyle(outerEl, resetStyleProps)
+  applyStyle(innerEl, resetStyleProps)
 
 
   return diff
   return diff
 }
 }
@@ -151,84 +163,97 @@ export function subtractInnerElHeight(outerEl: JQuery, innerEl: JQuery) {
 ----------------------------------------------------------------------------------------------------------------------*/
 ----------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
-// borrowed from https://github.com/jquery/jquery-ui/blob/1.11.0/ui/core.js#L51
-// TODO: normalize window/document?
-export function getScrollParent(el: JQuery) {
-  let position = el.css('position')
-  let scrollParent = el.parents().filter(function() {
-    let parent = $(this)
-    return (/(auto|scroll)/).test(
-      parent.css('overflow') + parent.css('overflow-y') + parent.css('overflow-x')
-    )
-  }).eq(0)
+// will return null of no scroll parent. will NOT return window/body
+export function getScrollParent(el: HTMLElement): HTMLElement | null {
 
 
-  return position === 'fixed' || !scrollParent.length ? $(el[0].ownerDocument || document) : scrollParent
-}
+  while (el instanceof HTMLElement) { // will stop when gets to document or null
+    let computedStyle = window.getComputedStyle(el)
 
 
+    if (computedStyle.position === 'fixed') {
+      break
+    }
 
 
-// Queries the area within the margin/border/scrollbars of a jQuery element. Does not go within the padding.
-// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
-// Origin is optional.
-// WARNING: given element can't have borders
-// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
-export function getClientRect(el: JQuery, origin?) {
-  let offset = el.offset()
-  let scrollbarWidths = getScrollbarWidths(el)
-  let left = offset.left + getCssFloat(el, 'border-left-width') + scrollbarWidths.left - (origin ? origin.left : 0)
-  let top = offset.top + getCssFloat(el, 'border-top-width') + scrollbarWidths.top - (origin ? origin.top : 0)
+    if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) {
+      return el
+    }
 
 
-  return {
-    left: left,
-    right: left + el[0].clientWidth, // clientWidth includes padding but NOT scrollbars
-    top: top,
-    bottom: top + el[0].clientHeight // clientHeight includes padding but NOT scrollbars
+    el = el.parentNode as HTMLElement
   }
   }
+
+  return null
 }
 }
 
 
 
 
-// Queries the area within the margin/border/padding of a jQuery element. Assumed not to have scrollbars.
-// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
-// Origin is optional.
-export function getContentRect(el: JQuery, origin) {
-  let offset = el.offset() // just outside of border, margin not included
-  let left = offset.left + getCssFloat(el, 'border-left-width') + getCssFloat(el, 'padding-left') -
-    (origin ? origin.left : 0)
-  let top = offset.top + getCssFloat(el, 'border-top-width') + getCssFloat(el, 'padding-top') -
-    (origin ? origin.top : 0)
+export interface EdgeInfo {
+  borderLeft: number
+  borderRight: number
+  borderTop: number
+  borderBottom: number
+  scrollbarLeft: number
+  scrollbarRight: number
+  scrollbarBottom: number
+  paddingLeft?: number
+  paddingRight?: number
+  paddingTop?: number
+  paddingBottom?: number
+}
 
 
-  return {
-    left: left,
-    right: left + el.width(),
-    top: top,
-    bottom: top + el.height()
+export function getEdges(el, getPadding = false): EdgeInfo {
+  let computedStyle = window.getComputedStyle(el)
+  let borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0
+  let borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0
+  let borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0
+  let borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0
+  let scrollbarLeftRight = sanitizeScrollbarWidth(el.offsetWidth - el.clientWidth - borderLeft - borderRight)
+  let scrollbarBottom = sanitizeScrollbarWidth(el.offsetHeight - el.clientHeight - borderTop - borderBottom)
+  let res: EdgeInfo = {
+    borderLeft,
+    borderRight,
+    borderTop,
+    borderBottom,
+    scrollbarBottom,
+    scrollbarLeft: 0,
+    scrollbarRight: 0
   }
   }
-}
 
 
+  if (getIsLeftRtlScrollbars() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side?
+    res.scrollbarLeft = scrollbarLeftRight
+  } else {
+    res.scrollbarRight = scrollbarLeftRight
+  }
 
 
-// Returns the computed left/right/top/bottom scrollbar widths for the given jQuery element.
-// WARNING: given element can't have borders (which will cause offsetWidth/offsetHeight to be larger).
-// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
-export function getScrollbarWidths(el: JQuery) {
-  let leftRightWidth = el[0].offsetWidth - el[0].clientWidth
-  let bottomWidth = el[0].offsetHeight - el[0].clientHeight
-  let widths
+  if (getPadding) {
+    res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0
+    res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0
+    res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0
+    res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0
+  }
 
 
-  leftRightWidth = sanitizeScrollbarWidth(leftRightWidth)
-  bottomWidth = sanitizeScrollbarWidth(bottomWidth)
+  return res
+}
 
 
-  widths = { left: 0, right: 0, top: 0, bottom: bottomWidth }
+export function getInnerRect(el, goWithinPadding = false) {
+  let outerRect = el.getBoundingClientRect()
+  let edges = getEdges(el, goWithinPadding)
+  let res = {
+    left: outerRect.left + edges.borderLeft + edges.scrollbarLeft,
+    right: outerRect.right - edges.borderRight - edges.scrollbarRight,
+    top: outerRect.top + edges.borderTop,
+    bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom
+  }
 
 
-  if (getIsLeftRtlScrollbars() && el.css('direction') === 'rtl') { // is the scrollbar on the left side?
-    widths.left = leftRightWidth
-  } else {
-    widths.right = leftRightWidth
+  if (goWithinPadding) {
+    res.left += edges.paddingLeft
+    res.right -= edges.paddingRight
+    res.top += edges.paddingTop
+    res.bottom -= edges.paddingBottom
   }
   }
 
 
-  return widths
+  return res
 }
 }
 
 
 
 
-// The scrollbar width computations in getScrollbarWidths are sometimes flawed when it comes to
+// The scrollbar width computations in getEdges are sometimes flawed when it comes to
 // retina displays, rounding, and IE11. Massage them into a usable value.
 // retina displays, rounding, and IE11. Massage them into a usable value.
 function sanitizeScrollbarWidth(width) {
 function sanitizeScrollbarWidth(width) {
   width = Math.max(0, width) // no negatives
   width = Math.max(0, width) // no negatives
@@ -267,13 +292,6 @@ function computeIsLeftRtlScrollbars() { // creates an offscreen test element, th
 }
 }
 
 
 
 
-// Retrieves a jQuery element's computed CSS value as a floating-point number.
-// If the queried value is non-numeric (ex: IE can return "medium" for border width), will just return zero.
-function getCssFloat(el: JQuery, prop) {
-  return parseFloat(el.css(prop)) || 0
-}
-
-
 /* Mouse / Touch Utilities
 /* Mouse / Touch Utilities
 ----------------------------------------------------------------------------------------------------------------------*/
 ----------------------------------------------------------------------------------------------------------------------*/
 
 

+ 0 - 88
tests/automated/legacy/getClientRect.js

@@ -1,88 +0,0 @@
-import { getStockScrollbarWidths } from '../lib/dom-misc'
-
-describe('getClientRect', function() {
-
-  var getClientRect = $.fullCalendar.getClientRect
-
-  defineTests(
-    'when margin',
-    { margin: '5px 10px' },
-    { width: 100, height: 100 },
-    { width: 100, height: 100 }
-  )
-  defineTests(
-    'when padding',
-    { padding: '5px 10px' },
-    { width: 100, height: 100 },
-    { width: 120, height: 110 }
-  )
-
-  /// / getClientRect doesn't work with borders anymore
-  // defineTests(
-  //  'when border',
-  //  { border: '5px solid red' },
-  //  { width: 100, height: 100 },
-  //  { width: 100, height: 100 }
-  // );
-  // defineTests(
-  //  'when border and padding',
-  //  { border: '5px solid red', padding: '5px 10px' },
-  //  { width: 100, height: 100 },
-  //  { width: 120, height: 110 }
-  // );
-
-  function defineTests(description, cssProps, innerDims, dims) {
-    describe(description, function() {
-      describe('when no scrolling', function() {
-        describe('when LTR', function() {
-          defineTest(false, 'ltr', cssProps, innerDims, dims)
-        })
-        describe('when RTL', function() {
-          defineTest(false, 'rtl', cssProps, innerDims, dims)
-        })
-      })
-      describe('when scrolling', function() {
-        describe('when LTR', function() {
-          defineTest(true, 'ltr', cssProps, innerDims, dims)
-        })
-        describe('when RTL', function() {
-          defineTest(true, 'rtl', cssProps, innerDims, dims)
-        })
-      })
-    })
-  }
-
-  function defineTest(isScrolling, dir, cssProps, innerDims, dims) {
-    it('computes correct dimensions', function() {
-      var el = $(
-        '<div style="position:absolute" />'
-      )
-        .css('overflow', isScrolling ? 'scroll' : 'hidden')
-        .css('direction', dir)
-        .css(cssProps)
-        .append(
-          $('<div style="position:relative" />').css(innerDims)
-        )
-        .appendTo('body')
-
-      var rect = getClientRect(el)
-      var offset = el.offset()
-      var borderLeftWidth = parseFloat(el.css('border-left-width')) || 0
-      var borderTopWidth = parseFloat(el.css('border-top-width')) || 0
-      var scrollbarWidths
-
-      if (isScrolling) {
-        scrollbarWidths = getStockScrollbarWidths(dir)
-      } else {
-        scrollbarWidths = { left: 0, right: 0, top: 0, bottom: 0 }
-      }
-
-      expect(rect.left).toBe(offset.left + borderLeftWidth + scrollbarWidths.left)
-      expect(rect.top).toBe(offset.top + borderTopWidth + scrollbarWidths.top)
-      expect(rect.right - rect.left).toBe(dims.width)
-      expect(rect.bottom - rect.top).toBe(dims.height)
-
-      el.remove()
-    })
-  }
-})

+ 15 - 17
tests/automated/legacy/getScrollbarWidths.js → tests/automated/legacy/getEdges.js

@@ -1,8 +1,8 @@
 import { getStockScrollbarWidths } from '../lib/dom-misc'
 import { getStockScrollbarWidths } from '../lib/dom-misc'
 
 
-describe('getScrollbarWidths', function() {
+describe('getEdges', function() {
 
 
-  var getScrollbarWidths = $.fullCalendar.getScrollbarWidths
+  var getEdges = $.fullCalendar.getEdges
 
 
   defineTests(
   defineTests(
     'when margin',
     'when margin',
@@ -13,15 +13,14 @@ describe('getScrollbarWidths', function() {
     { padding: '5px 10px' }
     { padding: '5px 10px' }
   )
   )
 
 
-  /// / getScrollbarWidths doesn't work with borders anymore
-  // defineTests(
-  //  'when border',
-  //  { border: '5px solid red' }
-  // );
-  // defineTests(
-  //  'when border and padding',
-  //  { border: '5px solid red', padding: '5px 10px' }
-  // );
+  defineTests(
+   'when border',
+   { border: '5px solid red' }
+  );
+  defineTests(
+   'when border and padding',
+   { border: '5px solid red', padding: '5px 10px' }
+  );
 
 
   function defineTests(description, cssProps) {
   function defineTests(description, cssProps) {
     describe(description, function() {
     describe(description, function() {
@@ -55,19 +54,18 @@ describe('getScrollbarWidths', function() {
         .append('<div style="position:relative;width:100px;height:100px" />')
         .append('<div style="position:relative;width:100px;height:100px" />')
         .appendTo('body')
         .appendTo('body')
 
 
-      var widths = getScrollbarWidths(el)
+      var edges = getEdges(el[0])
       var correctWidths
       var correctWidths
 
 
       if (isScrolling) {
       if (isScrolling) {
         correctWidths = getStockScrollbarWidths(dir)
         correctWidths = getStockScrollbarWidths(dir)
       } else {
       } else {
-        correctWidths = { left: 0, right: 0, top: 0, bottom: 0 }
+        correctWidths = { left: 0, right: 0, bottom: 0 }
       }
       }
 
 
-      expect(widths.left).toBe(correctWidths.left)
-      expect(widths.right).toBe(correctWidths.right)
-      expect(widths.top).toBe(correctWidths.top)
-      expect(widths.bottom).toBe(correctWidths.bottom)
+      expect(edges.scrollbarLeft).toBe(correctWidths.left)
+      expect(edges.scrollbarRight).toBe(correctWidths.right)
+      expect(edges.scrollbarBottom).toBe(correctWidths.bottom)
 
 
       el.remove()
       el.remove()
     })
     })

+ 105 - 0
tests/automated/legacy/getInnerRect.js

@@ -0,0 +1,105 @@
+import { getStockScrollbarWidths } from '../lib/dom-misc'
+
+describe('getInnerRect', function() {
+  var INNER_WIDTH = 150
+  var INNER_HEIGHT = 100
+  var BORDER_LEFT = 1
+  var BORDER_RIGHT = 2
+  var BORDER_TOP = 3
+  var BORDER_BOTTOM = 4
+  var PADDING_LEFT = 5
+  var PADDING_RIGHT = 6
+  var PADDING_TOP = 7
+  var PADDING_BOTTOM = 8
+  var getInnerRect = $.fullCalendar.getInnerRect
+
+  describeValues({
+    'when LTR': 'ltr',
+    'when RTL': 'rtl'
+  }, function(dir) {
+    var el
+
+    beforeEach(function() {
+      el = $('<div/>')
+        .css({
+          direction: dir,
+          position: 'absolute',
+          top: 0,
+          left: 0,
+          borderStyle: 'solid',
+          borderColor: 'black',
+          borderLeftWidth: BORDER_LEFT,
+          borderRightWidth: BORDER_RIGHT,
+          borderTopWidth: BORDER_TOP,
+          borderBottomWidth: BORDER_BOTTOM,
+          paddingLeft: PADDING_LEFT,
+          paddingRight: PADDING_RIGHT,
+          paddingTop: PADDING_TOP,
+          paddingBottom: PADDING_BOTTOM
+        })
+        .append(
+          $('<div/>').css({
+            width: INNER_WIDTH,
+            height: INNER_HEIGHT
+          })
+        )
+        .appendTo('body')
+    })
+
+    afterEach(function() {
+      el.remove()
+    })
+
+    describe('when no scrolling', function() {
+      beforeEach(function() {
+        el.css('overflow', 'hidden')
+      })
+
+      it('goes within border', function() {
+        expect(getInnerRect(el[0])).toEqual({
+          left: BORDER_LEFT,
+          right: BORDER_LEFT + PADDING_LEFT + INNER_WIDTH + PADDING_RIGHT,
+          top: BORDER_TOP,
+          bottom: BORDER_TOP + PADDING_TOP + INNER_HEIGHT + PADDING_BOTTOM
+        })
+      })
+
+      it('can go within padding', function() {
+        expect(getInnerRect(el[0], true)).toEqual({
+          left: BORDER_LEFT + PADDING_LEFT,
+          right: BORDER_LEFT + PADDING_LEFT + INNER_WIDTH,
+          top: BORDER_TOP + PADDING_TOP,
+          bottom: BORDER_TOP + PADDING_TOP + INNER_HEIGHT
+        })
+      })
+
+    })
+
+    describe('when scrolling', function() {
+      beforeEach(function() {
+        el.css('overflow', 'scroll')
+      })
+
+      var stockScrollbars = getStockScrollbarWidths(dir)
+
+      it('goes within border and scrollbars', function() {
+        expect(getInnerRect(el[0])).toEqual({
+          left: BORDER_LEFT + stockScrollbars.left,
+          right: BORDER_LEFT + stockScrollbars.left + PADDING_LEFT + INNER_WIDTH + PADDING_RIGHT,
+          top: BORDER_TOP,
+          bottom: BORDER_TOP + PADDING_TOP + INNER_HEIGHT + PADDING_BOTTOM
+        })
+      })
+
+      it('can go within padding', function() {
+        expect(getInnerRect(el[0], true)).toEqual({
+          left: BORDER_LEFT + stockScrollbars.left + PADDING_LEFT,
+          right: BORDER_LEFT + stockScrollbars.left + PADDING_LEFT + INNER_WIDTH,
+          top: BORDER_TOP + PADDING_TOP,
+          bottom: BORDER_TOP + PADDING_TOP + INNER_HEIGHT
+        })
+      })
+
+    })
+  })
+})