mirror of
https://github.com/atom/atom.git
synced 2026-01-23 22:08:08 -05:00
Merge pull request #16827 from atom/fb-mdt-pane-element-to-js
Convert PaneContainerElement and PaneElement to JS
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
class PaneContainerElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@classList.add 'panes'
|
||||
|
||||
initialize: (@model, {@views}) ->
|
||||
throw new Error("Must pass a views parameter when initializing PaneContainerElements") unless @views?
|
||||
|
||||
@subscriptions.add @model.observeRoot(@rootChanged.bind(this))
|
||||
this
|
||||
|
||||
rootChanged: (root) ->
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@firstChild?.remove()
|
||||
if root?
|
||||
view = @views.getView(root)
|
||||
@appendChild(view)
|
||||
focusedElement?.focus()
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
|
||||
module.exports = PaneContainerElement = document.registerElement 'atom-pane-container', prototype: PaneContainerElement.prototype
|
||||
40
src/pane-container-element.js
Normal file
40
src/pane-container-element.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const {CompositeDisposable} = require('event-kit')
|
||||
|
||||
class PaneContainerElement extends HTMLElement {
|
||||
createdCallback () {
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
this.classList.add('panes')
|
||||
}
|
||||
|
||||
initialize (model, {views}) {
|
||||
this.model = model
|
||||
this.views = views
|
||||
if (this.views == null) {
|
||||
throw new Error('Must pass a views parameter when initializing PaneContainerElements')
|
||||
}
|
||||
this.subscriptions.add(this.model.observeRoot(this.rootChanged.bind(this)))
|
||||
return this
|
||||
}
|
||||
|
||||
rootChanged (root) {
|
||||
const focusedElement = this.hasFocus() ? document.activeElement : null
|
||||
if (this.firstChild != null) {
|
||||
this.firstChild.remove()
|
||||
}
|
||||
if (root != null) {
|
||||
const view = this.views.getView(root)
|
||||
this.appendChild(view)
|
||||
if (focusedElement != null) {
|
||||
focusedElement.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasFocus () {
|
||||
return this === document.activeElement || this.contains(document.activeElement)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = document.registerElement('atom-pane-container', {
|
||||
prototype: PaneContainerElement.prototype
|
||||
})
|
||||
@@ -1,139 +0,0 @@
|
||||
path = require 'path'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
|
||||
class PaneElement extends HTMLElement
|
||||
attached: false
|
||||
|
||||
createdCallback: ->
|
||||
@attached = false
|
||||
@subscriptions = new CompositeDisposable
|
||||
@inlineDisplayStyles = new WeakMap
|
||||
|
||||
@initializeContent()
|
||||
@subscribeToDOMEvents()
|
||||
|
||||
attachedCallback: ->
|
||||
@attached = true
|
||||
@focus() if @model.isFocused()
|
||||
|
||||
detachedCallback: ->
|
||||
@attached = false
|
||||
|
||||
initializeContent: ->
|
||||
@setAttribute 'class', 'pane'
|
||||
@setAttribute 'tabindex', -1
|
||||
@appendChild @itemViews = document.createElement('div')
|
||||
@itemViews.setAttribute 'class', 'item-views'
|
||||
|
||||
subscribeToDOMEvents: ->
|
||||
handleFocus = (event) =>
|
||||
@model.focus() unless @isActivating or @model.isDestroyed() or @contains(event.relatedTarget)
|
||||
if event.target is this and view = @getActiveView()
|
||||
view.focus()
|
||||
event.stopPropagation()
|
||||
|
||||
handleBlur = (event) =>
|
||||
@model.blur() unless @contains(event.relatedTarget)
|
||||
|
||||
handleDragOver = (event) ->
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
handleDrop = (event) =>
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
@getModel().activate()
|
||||
pathsToOpen = Array::map.call event.dataTransfer.files, (file) -> file.path
|
||||
@applicationDelegate.open({pathsToOpen}) if pathsToOpen.length > 0
|
||||
|
||||
@addEventListener 'focus', handleFocus, true
|
||||
@addEventListener 'blur', handleBlur, true
|
||||
@addEventListener 'dragover', handleDragOver
|
||||
@addEventListener 'drop', handleDrop
|
||||
|
||||
initialize: (@model, {@views, @applicationDelegate}) ->
|
||||
throw new Error("Must pass a views parameter when initializing PaneElements") unless @views?
|
||||
throw new Error("Must pass an applicationDelegate parameter when initializing PaneElements") unless @applicationDelegate?
|
||||
|
||||
@subscriptions.add @model.onDidActivate(@activated.bind(this))
|
||||
@subscriptions.add @model.observeActive(@activeStatusChanged.bind(this))
|
||||
@subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this))
|
||||
@subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this))
|
||||
this
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
activated: ->
|
||||
@isActivating = true
|
||||
@focus() unless @hasFocus() # Don't steal focus from children.
|
||||
@isActivating = false
|
||||
|
||||
activeStatusChanged: (active) ->
|
||||
if active
|
||||
@classList.add('active')
|
||||
else
|
||||
@classList.remove('active')
|
||||
|
||||
activeItemChanged: (item) ->
|
||||
delete @dataset.activeItemName
|
||||
delete @dataset.activeItemPath
|
||||
@changePathDisposable?.dispose()
|
||||
|
||||
return unless item?
|
||||
|
||||
hasFocus = @hasFocus()
|
||||
itemView = @views.getView(item)
|
||||
|
||||
if itemPath = item.getPath?()
|
||||
@dataset.activeItemName = path.basename(itemPath)
|
||||
@dataset.activeItemPath = itemPath
|
||||
|
||||
if item.onDidChangePath?
|
||||
@changePathDisposable = item.onDidChangePath =>
|
||||
itemPath = item.getPath()
|
||||
@dataset.activeItemName = path.basename(itemPath)
|
||||
@dataset.activeItemPath = itemPath
|
||||
|
||||
unless @itemViews.contains(itemView)
|
||||
@itemViews.appendChild(itemView)
|
||||
|
||||
for child in @itemViews.children
|
||||
if child is itemView
|
||||
@showItemView(child) if @attached
|
||||
else
|
||||
@hideItemView(child)
|
||||
|
||||
itemView.focus() if hasFocus
|
||||
|
||||
showItemView: (itemView) ->
|
||||
inlineDisplayStyle = @inlineDisplayStyles.get(itemView)
|
||||
if inlineDisplayStyle?
|
||||
itemView.style.display = inlineDisplayStyle
|
||||
else
|
||||
itemView.style.display = ''
|
||||
|
||||
hideItemView: (itemView) ->
|
||||
inlineDisplayStyle = itemView.style.display
|
||||
unless inlineDisplayStyle is 'none'
|
||||
@inlineDisplayStyles.set(itemView, inlineDisplayStyle) if inlineDisplayStyle?
|
||||
itemView.style.display = 'none'
|
||||
|
||||
itemRemoved: ({item, index, destroyed}) ->
|
||||
if viewToRemove = @views.getView(item)
|
||||
viewToRemove.remove()
|
||||
|
||||
paneDestroyed: ->
|
||||
@subscriptions.dispose()
|
||||
@changePathDisposable?.dispose()
|
||||
|
||||
flexScaleChanged: (flexScale) ->
|
||||
@style.flexGrow = flexScale
|
||||
|
||||
getActiveView: -> @views.getView(@model.getActiveItem())
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
module.exports = PaneElement = document.registerElement 'atom-pane', prototype: PaneElement.prototype
|
||||
218
src/pane-element.js
Normal file
218
src/pane-element.js
Normal file
@@ -0,0 +1,218 @@
|
||||
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
|
||||
})
|
||||
Reference in New Issue
Block a user