Skip to content
This repository has been archived by the owner on May 30, 2022. It is now read-only.

Commit

Permalink
refactor(macAffix): Switched to use $document and $window.
Browse files Browse the repository at this point in the history
Better top and bottom offset validation
  • Loading branch information
adrianlee44 committed Nov 22, 2013
1 parent c9611f0 commit 0393bbc
Showing 1 changed file with 95 additions and 87 deletions.
182 changes: 95 additions & 87 deletions src/directives/affix.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,100 +5,108 @@
@description
Fix the component at a certain position
@param {Expr} mac-affix-disabled To unpin element
@param {Expr} mac-affix-top Top offset (default 0)
@param {Expr} mac-affix-bottom Bottom offset (default 0)
@param {Expr} mac-affix-disabled To unpin element (default false)
@param {Expr} mac-affix-top Top offset (default 0)
@param {Expr} mac-affix-bottom Bottom offset (default 0)
@param {Event} refresh-mac-affix To update the position of affixed element
###

angular.module("Mac").directive "macAffix", ->
link: ($scope, element, attrs) ->
defaults =
top: 0
bottom: 0
disabled: false
classes: "affix affix-top affix-bottom"

offset = top: defaults.top, bottom: defaults.bottom
position = top: 0, left: 0
disabled = defaults.disabled
lastAffix = null
unpin = null
windowEl = angular.element(window)

if attrs.macAffixTop?
offset.top = $scope.$eval(attrs.macAffixTop) or defaults.top
$scope.$watch attrs.macAffixTop, (value) ->
offset.top = value if value?

if attrs.macAffixBottom?
offset.bottom = $scope.$eval(attrs.macAffixBottom) or defaults.bottom
$scope.$watch attrs.macAffixBottom, (value) ->
offset.bottom = value if value?

(getPosition = ->
position = element.offset()
)()

scrollEvent = ->
# Check if element is visible
return if element[0].offsetHeight <= 0 and element[0].offsetWidth <= 0

scrollTop = windowEl.scrollTop()
scrollHeight = angular.element(document).height()

affix =
if unpin? and scrollTop + unpin <= position.top
false
else if position.top + element.height() >= scrollHeight - offset.bottom
"bottom"
else if scrollTop <= offset.top
"top"
angular.module("Mac").directive "macAffix", [
"$document"
"$window"
($document, $window)->
link: ($scope, element, attrs) ->
defaults =
top: 0
bottom: 0
disabled: false
classes: "affix affix-top affix-bottom"

offset = top: defaults.top, bottom: defaults.bottom
position = element.offset()
disabled = defaults.disabled
lastAffix = null
unpin = null
windowEl = angular.element($window)

###
@name setOffset
@description
Update top or bottom offset. This function will make sure the value is
an integer and use default value
###
setOffset = (key, value, useDefault = false) ->
value = defaults[key] if useDefault and not value?
offset[key] = +value if value? and not isNaN(+value)

if attrs.macAffixTop?
setOffset "top", $scope.$eval(attrs.macAffixTop), true
$scope.$watch attrs.macAffixTop, (value) -> setOffset "top", value

if attrs.macAffixBottom?
setOffset "bottom", $scope.$eval(attrs.macAffixBottom), true
$scope.$watch attrs.macAffixBottom, (value) -> setOffset "bottom", value

scrollEvent = ->
# Check if element is visible
return if element[0].offsetHeight <= 0 and element[0].offsetWidth <= 0

scrollTop = windowEl.scrollTop()
scrollHeight = $document.height()

affix =
if unpin? and scrollTop + unpin <= position.top
false
else if position.top + element.height() >= scrollHeight - offset.bottom
"bottom"
else if scrollTop <= offset.top
"top"
else
false

return if affix is lastAffix
lastAffix = affix

element.css "top", "" if unpin

element
.removeClass(defaults.classes)
.addClass "affix" + (if affix then "-#{affix}" else "")

if affix is "bottom"
unpin = position.top - scrollTop
element.css(
"top",
$document[0].body.offsetHeight - offset.bottom - element.height()
)
else
false
unpin = null

return if affix is lastAffix
lastAffix = affix
return true

element.css "top", "" if unpin
if attrs.macAffixDisabled?
disabled = $scope.$eval(attrs.macAffixDisabled) or defaults.disabled
$scope.$watch attrs.macAffixDisabled, (value) ->
return if not value? or value is disabled

element
.removeClass(defaults.classes)
.addClass "affix" + (if affix then "-#{affix}" else "")
disabled = value
action = if value then "unbind" else "bind"
windowEl[action] "scroll", scrollEvent

if affix is "bottom"
unpin = position.top - scrollTop
element.css(
"top",
document.body.offsetHeight - offset.bottom - element.height()
)
else
unpin = null
if disabled
# clear all styles and reset affix element
lastAffix = null
unpin = null

return true
element
.css("top", "")
.removeClass defaults.classes
else
scrollEvent()

if attrs.macAffixDisabled?
disabled = $scope.$eval(attrs.macAffixDisabled) or defaults.disabled
$scope.$watch attrs.macAffixDisabled, (value) ->
return if not value? or value is disabled
unless disabled
windowEl.bind "scroll", scrollEvent

disabled = value
action = if value then "unbind" else "bind"
windowEl[action] "scroll", scrollEvent

if disabled
# clear all styles and reset affix element
lastAffix = null
unpin = null

element
.css("top", "")
.removeClass defaults.classes
else
scrollEvent()

unless disabled
windowEl.bind "scroll", scrollEvent

$scope.$on "refresh-mac-affix", getPosition
$scope.$on "$destroy", ->
windowEl.unbind "scroll", scrollEvent
$scope.$on "refresh-mac-affix", -> position = element.offset()
$scope.$on "$destroy", -> windowEl.unbind "scroll", scrollEvent
]

0 comments on commit 0393bbc

Please sign in to comment.