import * as $ from 'jquery'
import { htmlEscape } from './util'
/* Toolbar with buttons and title
----------------------------------------------------------------------------------------------------------------------*/
export default class Toolbar {
calendar: any
toolbarOptions: any
el: any = null // mirrors local `el`
viewsWithButtons: any = []
constructor(calendar, toolbarOptions) {
this.calendar = calendar
this.toolbarOptions = toolbarOptions
}
// method to update toolbar-specific options, not calendar-wide options
setToolbarOptions(newToolbarOptions) {
this.toolbarOptions = newToolbarOptions
}
// can be called repeatedly and will rerender
render() {
let sections = this.toolbarOptions.layout
let el = this.el
if (sections) {
if (!el) {
el = this.el = $("
")
} else {
el.empty()
}
el.append(this.renderSection('left'))
.append(this.renderSection('right'))
.append(this.renderSection('center'))
.append('')
} else {
this.removeElement()
}
}
removeElement() {
if (this.el) {
this.el.remove()
this.el = null
}
}
renderSection(position) {
let calendar = this.calendar
let theme = calendar.theme
let optionsManager = calendar.optionsManager
let viewSpecManager = calendar.viewSpecManager
let sectionEl = $('')
let buttonStr = this.toolbarOptions.layout[position]
let calendarCustomButtons = optionsManager.get('customButtons') || {}
let calendarButtonTextOverrides = optionsManager.overrides.buttonText || {}
let calendarButtonText = optionsManager.get('buttonText') || {}
if (buttonStr) {
$.each(buttonStr.split(' '), (i, buttonGroupStr) => {
let groupChildren = $()
let isOnlyButtons = true
let groupEl
$.each(buttonGroupStr.split(','), (j, buttonName) => {
let customButtonProps
let viewSpec
let buttonClick
let buttonIcon // only one of these will be set
let buttonText // "
let buttonInnerHtml
let buttonClasses
let buttonEl
let buttonAriaAttr
if (buttonName === 'title') {
groupChildren = groupChildren.add($('
')) // we always want it to take up height
isOnlyButtons = false
} else {
if ((customButtonProps = calendarCustomButtons[buttonName])) {
buttonClick = function(ev) {
if (customButtonProps.click) {
customButtonProps.click.call(buttonEl[0], ev)
}
};
(buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||
(buttonIcon = theme.getIconClass(buttonName)) ||
(buttonText = customButtonProps.text)
} else if ((viewSpec = viewSpecManager.getViewSpec(buttonName))) {
this.viewsWithButtons.push(buttonName)
buttonClick = function() {
calendar.changeView(buttonName)
};
(buttonText = viewSpec.buttonTextOverride) ||
(buttonIcon = theme.getIconClass(buttonName)) ||
(buttonText = viewSpec.buttonTextDefault)
} else if (calendar[buttonName]) { // a calendar method
buttonClick = function() {
calendar[buttonName]()
};
(buttonText = calendarButtonTextOverrides[buttonName]) ||
(buttonIcon = theme.getIconClass(buttonName)) ||
(buttonText = calendarButtonText[buttonName])
// ^ everything else is considered default
}
if (buttonClick) {
buttonClasses = [
'fc-' + buttonName + '-button',
theme.getClass('button'),
theme.getClass('stateDefault')
]
if (buttonText) {
buttonInnerHtml = htmlEscape(buttonText)
buttonAriaAttr = ''
} else if (buttonIcon) {
buttonInnerHtml = ""
buttonAriaAttr = ' aria-label="' + buttonName + '"'
}
buttonEl = $( // type="button" so that it doesn't submit a form
''
)
.click(function(ev) {
// don't process clicks for disabled buttons
if (!buttonEl.hasClass(theme.getClass('stateDisabled'))) {
buttonClick(ev)
// after the click action, if the button becomes the "active" tab, or disabled,
// it should never have a hover class, so remove it now.
if (
buttonEl.hasClass(theme.getClass('stateActive')) ||
buttonEl.hasClass(theme.getClass('stateDisabled'))
) {
buttonEl.removeClass(theme.getClass('stateHover'))
}
}
})
.mousedown(function() {
// the *down* effect (mouse pressed in).
// only on buttons that are not the "active" tab, or disabled
buttonEl
.not('.' + theme.getClass('stateActive'))
.not('.' + theme.getClass('stateDisabled'))
.addClass(theme.getClass('stateDown'))
})
.mouseup(function() {
// undo the *down* effect
buttonEl.removeClass(theme.getClass('stateDown'))
})
.hover(
function() {
// the *hover* effect.
// only on buttons that are not the "active" tab, or disabled
buttonEl
.not('.' + theme.getClass('stateActive'))
.not('.' + theme.getClass('stateDisabled'))
.addClass(theme.getClass('stateHover'))
},
function() {
// undo the *hover* effect
buttonEl
.removeClass(theme.getClass('stateHover'))
.removeClass(theme.getClass('stateDown')) // if mouseleave happens before mouseup
}
)
groupChildren = groupChildren.add(buttonEl)
}
}
})
if (isOnlyButtons) {
groupChildren
.first().addClass(theme.getClass('cornerLeft')).end()
.last().addClass(theme.getClass('cornerRight')).end()
}
if (groupChildren.length > 1) {
groupEl = $('')
if (isOnlyButtons) {
groupEl.addClass(theme.getClass('buttonGroup'))
}
groupEl.append(groupChildren)
sectionEl.append(groupEl)
} else {
sectionEl.append(groupChildren) // 1 or 0 children
}
})
}
return sectionEl
}
updateTitle(text) {
if (this.el) {
this.el.find('h2').text(text)
}
}
activateButton(buttonName) {
if (this.el) {
this.el.find('.fc-' + buttonName + '-button')
.addClass(this.calendar.theme.getClass('stateActive'))
}
}
deactivateButton(buttonName) {
if (this.el) {
this.el.find('.fc-' + buttonName + '-button')
.removeClass(this.calendar.theme.getClass('stateActive'))
}
}
disableButton(buttonName) {
if (this.el) {
this.el.find('.fc-' + buttonName + '-button')
.prop('disabled', true)
.addClass(this.calendar.theme.getClass('stateDisabled'))
}
}
enableButton(buttonName) {
if (this.el) {
this.el.find('.fc-' + buttonName + '-button')
.prop('disabled', false)
.removeClass(this.calendar.theme.getClass('stateDisabled'))
}
}
getViewsWithButtons() {
return this.viewsWithButtons
}
}