Files
atom/src/pane-element.js
2018-02-23 14:39:57 -08:00

219 lines
5.6 KiB
JavaScript

const path = require('path')
const {CompositeDisposable} = require('event-kit')
class PaneElement extends HTMLElement {
createdCallback () {
this.attached = false
this.subscriptions = new CompositeDisposable()
this.inlineDisplayStyles = new WeakMap()
this.initializeContent()
this.subscribeToDOMEvents()
}
attachedCallback () {
this.attached = true
if (this.model.isFocused()) {
this.focus()
}
}
detachedCallback () {
this.attached = false
}
initializeContent () {
this.setAttribute('class', 'pane')
this.setAttribute('tabindex', -1)
this.itemViews = document.createElement('div')
this.appendChild(this.itemViews)
this.itemViews.setAttribute('class', 'item-views')
}
subscribeToDOMEvents () {
const handleFocus = event => {
if (
!(
this.isActivating ||
this.model.isDestroyed() ||
this.contains(event.relatedTarget)
)
) {
this.model.focus()
}
if (event.target !== this) return
const view = this.getActiveView()
if (view) {
view.focus()
event.stopPropagation()
}
}
const handleBlur = event => {
if (!this.contains(event.relatedTarget)) {
this.model.blur()
}
}
const handleDragOver = event => {
event.preventDefault()
event.stopPropagation()
}
const handleDrop = event => {
event.preventDefault()
event.stopPropagation()
this.getModel().activate()
const pathsToOpen = [...event.dataTransfer.files].map(file => file.path)
if (pathsToOpen.length > 0) {
this.applicationDelegate.open({pathsToOpen})
}
}
this.addEventListener('focus', handleFocus, true)
this.addEventListener('blur', handleBlur, true)
this.addEventListener('dragover', handleDragOver)
this.addEventListener('drop', handleDrop)
}
initialize (model, {views, applicationDelegate}) {
this.model = model
this.views = views
this.applicationDelegate = applicationDelegate
if (this.views == null) {
throw new Error(
'Must pass a views parameter when initializing PaneElements'
)
}
if (this.applicationDelegate == null) {
throw new Error(
'Must pass an applicationDelegate parameter when initializing PaneElements'
)
}
this.subscriptions.add(this.model.onDidActivate(this.activated.bind(this)))
this.subscriptions.add(
this.model.observeActive(this.activeStatusChanged.bind(this))
)
this.subscriptions.add(
this.model.observeActiveItem(this.activeItemChanged.bind(this))
)
this.subscriptions.add(
this.model.onDidRemoveItem(this.itemRemoved.bind(this))
)
this.subscriptions.add(
this.model.onDidDestroy(this.paneDestroyed.bind(this))
)
this.subscriptions.add(
this.model.observeFlexScale(this.flexScaleChanged.bind(this))
)
return this
}
getModel () {
return this.model
}
activated () {
this.isActivating = true
if (!this.hasFocus()) {
// Don't steal focus from children.
this.focus()
}
this.isActivating = false
}
activeStatusChanged (active) {
if (active) {
this.classList.add('active')
} else {
this.classList.remove('active')
}
}
activeItemChanged (item) {
delete this.dataset.activeItemName
delete this.dataset.activeItemPath
if (this.changePathDisposable != null) {
this.changePathDisposable.dispose()
}
if (item == null) {
return
}
const hasFocus = this.hasFocus()
const itemView = this.views.getView(item)
const itemPath = typeof item.getPath === 'function' ? item.getPath() : null
if (itemPath) {
this.dataset.activeItemName = path.basename(itemPath)
this.dataset.activeItemPath = itemPath
if (item.onDidChangePath != null) {
this.changePathDisposable = item.onDidChangePath(() => {
const itemPath = item.getPath()
this.dataset.activeItemName = path.basename(itemPath)
this.dataset.activeItemPath = itemPath
})
}
}
if (!this.itemViews.contains(itemView)) {
this.itemViews.appendChild(itemView)
}
for (const child of this.itemViews.children) {
if (child === itemView) {
if (this.attached) {
this.showItemView(child)
}
} else {
this.hideItemView(child)
}
}
if (hasFocus) {
itemView.focus()
}
}
showItemView (itemView) {
const inlineDisplayStyle = this.inlineDisplayStyles.get(itemView)
if (inlineDisplayStyle != null) {
itemView.style.display = inlineDisplayStyle
} else {
itemView.style.display = ''
}
}
hideItemView (itemView) {
const inlineDisplayStyle = itemView.style.display
if (inlineDisplayStyle !== 'none') {
if (inlineDisplayStyle != null) {
this.inlineDisplayStyles.set(itemView, inlineDisplayStyle)
}
itemView.style.display = 'none'
}
}
itemRemoved ({item, index, destroyed}) {
const viewToRemove = this.views.getView(item)
if (viewToRemove) {
viewToRemove.remove()
}
}
paneDestroyed () {
this.subscriptions.dispose()
if (this.changePathDisposable != null) {
this.changePathDisposable.dispose()
}
}
flexScaleChanged (flexScale) {
this.style.flexGrow = flexScale
}
getActiveView () {
return this.views.getView(this.model.getActiveItem())
}
hasFocus () {
return (
this === document.activeElement || this.contains(document.activeElement)
)
}
}
module.exports = document.registerElement('atom-pane', {
prototype: PaneElement.prototype
})