UNPKG

luda

Version:

A library helps to build cross-framework UI components.

204 lines (178 loc) 6.88 kB
import '../kernel/index.coffee' luda.mixin 'tabable', # cls: # tabable: # active: string # required # indicatorActive: string # required # prev: string # optional # next: string # optional # data: # tabable: # interruption: string # required # wrap: string # optional # default: # tabable: # activeIndex: integer # optional # wrap: boolean # optional # evt: # tabable: # activate: string #required # activated: string #required # deactivate: string #required # deactivated: string #required # selector: # tabable: # targets: string # required # indicators: string # required # prevCtrl: string # optional # nextCtrl: string # optional tabableActiveIndex: -> index = @default?.tabable?.activeIndex or 0 @tabableTargets.els.some (it, i) => return false unless luda(it).hasClass @cls.tabable.active index = i true index tabableWrapable: -> wrapAttr = @data.tabable.wrap return false unless wrapAttr wrapable = @root.data wrapAttr return false if wrapable is false @default?.tabable?.wrap tabableActivate: (index) -> return unless luda.isNumeric index direction = if index < @tabableActiveIndex() then 'prev' else 'next' @tabableSlide index, direction tabableNext: -> index = @tabableActiveIndex() + 1 if index >= @tabableTargets.length return unless @tabableWrapable() index = 0 @tabableSlide index, 'next' tabablePrev: -> index = @tabableActiveIndex() - 1 if index < 0 return unless @tabableWrapable() index = @tabableTargets.length - 1 @tabableSlide index, 'prev' tabableLayout: -> @tabableTargets.els.forEach (it, index) => item = luda it return if (activeCls = @cls.tabable.active) and item.hasClass activeCls return if (nextCls = @cls.tabable.next) and item.hasClass nextCls return if (prevCls = @cls.tabable.prev) and item.hasClass prevCls isActive = index is @tabableActiveIndex() item.css('transition', 'none') .toggleClass(activeCls, isActive) .toggleClass(prevCls, index < @tabableActiveIndex()) .toggleClass(nextCls, index > @tabableActiveIndex()) .reflow().css('transition', '') isActive and item.trigger @evt.tabable.activated @tabableSetIndicatorsState() @tabableSetDirectionCtrlsState() tabableSlide: (index, direction) -> return unless luda.isNumeric index return if index is (activatedIndex = @tabableActiveIndex()) return if index < 0 or index >= @tabableTargets.length item = @tabableTargets.eq index activated = @tabableTargets.eq activatedIndex activateEvt = item.trigger(@evt.tabable.activate, null, true)[0] return if activateEvt.isDefaultPrevented() deactivateEvt = activated.trigger(@evt.tabable.deactivate, null, true)[0] return if deactivateEvt.isDefaultPrevented() oppsite = if direction is 'next' then 'prev' else 'next' directionCls = @cls.tabable[direction] oppsiteCls = @cls.tabable[oppsite] activeCls = @cls.tabable.active item.css('transition', 'none') .addClass(directionCls).removeClass(oppsiteCls) .reflow().css('transition', '') .addClass(activeCls).removeClass(directionCls) activated.addClass(oppsiteCls).removeClass(activeCls) @tabableActivating = setTimeout => delete @tabableActivating item.trigger @evt.tabable.activated , item.transitionDuration() @tabableDeactivateIndex = activatedIndex @tabableDeactivating = setTimeout => delete @tabableDeactivating delete @tabableDeactivateIndex activated.trigger @evt.tabable.deactivated , activated.transitionDuration() @tabableSetIndicatorsState() @tabableSetDirectionCtrlsState() true tabableTransitioning: -> 'tabableActivating' of this or 'tabableDeactivating' of this tabableSetIndicatorsState: -> @tabableIndicators.els.forEach (it, index) => activeCls = @cls.tabable.indicatorActive val = index is @tabableActiveIndex() luda(it).toggleClass activeCls, val tabableSetDirectionCtrlsState: -> prevCtrl = @tabablePrevCtrl nextCtrl = @tabableNextCtrl return unless prevCtrl or nextCtrl if @tabableTargets.length <= 1 prevDis = nextDis = '' else if @tabableWrapable() prevDis = nextDis = null else index = @tabableActiveIndex() minIndex = 0 maxIndex = @tabableTargets.length - 1 prevDis = if index is minIndex then '' else null nextDis = if index is maxIndex then '' else null prevCtrl and prevCtrl.attr 'disabled', prevDis nextCtrl and nextCtrl.attr 'disabled', nextDis tabableActivateOnEvent: (e) -> return if @tabableTransitioning() index = e.detail?.tabable?.activeIndex unless index? index = @tabableIndicators.els.indexOf e.currentTarget @tabableActivate index tabablePrevOnEvent: (e) -> @tabablePrev() unless @tabableTransitioning() tabableNextOnEvent: (e) -> @tabableNext() unless @tabableTransitioning() tabableDestroy: -> if 'tabableActivating' of this clearTimeout @tabableActivating interruption = {activate: @tabableActiveIndex()} if 'tabableDeactivating' of this clearTimeout @tabableDeactivating interruption ||= {} interruption.deactivateIndex = @tabableDeactivateIndex @root.data @data.tabable.interruption, interruption tabableCreate: -> @tabableLayout() dataAttr = @data.tabable.interruption return unless interruption = @root.data dataAttr if (activate = interruption.activated)? @tabableTargets.eq(activated).trigger @evt.tabable.activated if (deactive = interruption.deactivated)? @tabableTargets.eq(deactivated).trigger @evt.tabable.deactivated @root.removeData dataAttr tabableFind: -> conf = tabableTargets: @selector.tabable.targets tabableIndicators: @selector.tabable.indicators conf.tabablePrevCtrl = prevCtrl if prevCtrl = @selector.tabable.prevCtrl conf.tabableNextCtrl = nextCtrl if nextCtrl = @selector.tabable.nextCtrl conf tabableWatch: -> attr = [] wrapAttr = @data.tabable.wrap wrapAttr and attr.push [wrapAttr, @tabableSetDirectionControlState] attr: attr node: [ [@selector.tabable.targets, @tabableLayout] [@selector.tabable.indicators, @tabableSetIndicatorsState] ] tabableListen: -> listeners = [ ['click', @selector.tabable.indicators, @tabableActivateOnEvent] ] if prevCtrl = @selector.tabable.prevCtrl listeners.push ['click', prevCtrl, @tabablePrevOnEvent] if nextCtrl = @selector.tabable.nextCtrl listeners.push ['click', nextCtrl, @tabableNextOnEvent] listeners