jsoneditor
Version:
A web-based tool to view, edit, format, and validate JSON
104 lines (93 loc) • 3.4 kB
JavaScript
'use strict'
/**
* @constructor FocusTracker
* A custom focus tracker for a DOM element with complex internal DOM structure
* @param {[Object]} config A set of configurations for the FocusTracker
* {DOM Object} target * The DOM object to track (required)
* {Function} onFocus onFocus callback
* {Function} onBlur onBlur callback
*
* @return
*/
export class FocusTracker {
constructor (config) {
this.target = config.target || null
if (!this.target) {
throw new Error('FocusTracker constructor called without a "target" to track.')
}
this.onFocus = (typeof config.onFocus === 'function') ? config.onFocus : null
this.onBlur = (typeof config.onBlur === 'function') ? config.onBlur : null
this._onClick = this._onEvent.bind(this)
this._onKeyUp = function (event) {
if (event.which === 9 || event.keyCode === 9) {
this._onEvent(event)
}
}.bind(this)
this._onBlur = this._onEvent.bind(this)
this.focusFlag = false
this.firstEventFlag = true
/*
Adds required (click and keyup) event listeners to the 'document' object
to track the focus of the given 'target'
*/
if (this.onFocus || this.onBlur) {
document.addEventListener('click', this._onClick)
document.addEventListener('keyup', this._onKeyUp)
document.addEventListener('blur', this._onBlur)
}
}
/**
* Removes the event listeners on the 'document' object
* that were added to track the focus of the given 'target'
*/
destroy () {
document.removeEventListener('click', this._onClick)
document.removeEventListener('keyup', this._onKeyUp)
document.removeEventListener('blur', this._onBlur)
this._onEvent({ target: document.body }) // calling _onEvent with body element in the hope that the FocusTracker is added to an element inside the body tag
}
/**
* Tracks the focus of the target and calls the onFocus and onBlur
* event callbacks if available.
* @param {Event} [event] The 'click' or 'keyup' event object,
* from the respective events set on
* document object
* @private
*/
_onEvent (event) {
const target = event.target
let focusFlag
if (target === this.target) {
focusFlag = true
} else if (this.target.contains(target) || this.target.contains(document.activeElement)) {
focusFlag = true
} else {
focusFlag = false
}
if (focusFlag) {
if (!this.focusFlag) {
// trigger the onFocus callback
if (this.onFocus) {
this.onFocus({ type: 'focus', target: this.target })
}
this.focusFlag = true
}
} else {
if (this.focusFlag || this.firstEventFlag) {
// trigger the onBlur callback
if (this.onBlur) {
this.onBlur({ type: 'blur', target: this.target })
}
this.focusFlag = false
/*
When switching from one mode to another in the editor, the FocusTracker gets recreated.
At that time, this.focusFlag will be init to 'false' and will fail the above if condition, when blur occurs
this.firstEventFlag is added to overcome that issue
*/
if (this.firstEventFlag) {
this.firstEventFlag = false
}
}
}
}
}