Merge pull request #22733 from atom/decaffeinate

Decaffeinate elements
This commit is contained in:
Sadick
2021-07-19 18:31:45 +03:00
committed by GitHub
6 changed files with 376 additions and 233 deletions

View File

@@ -1,71 +0,0 @@
{CompositeDisposable} = require 'event-kit'
PaneResizeHandleElement = require './pane-resize-handle-element'
class PaneAxisElement extends HTMLElement
attachedCallback: ->
@subscriptions ?= @subscribeToModel()
@childAdded({child, index}) for child, index in @model.getChildren()
detachedCallback: ->
@subscriptions.dispose()
@subscriptions = null
@childRemoved({child}) for child in @model.getChildren()
initialize: (@model, @viewRegistry) ->
@subscriptions ?= @subscribeToModel()
@childAdded({child, index}) for child, index in @model.getChildren()
switch @model.getOrientation()
when 'horizontal'
@classList.add('horizontal', 'pane-row')
when 'vertical'
@classList.add('vertical', 'pane-column')
this
subscribeToModel: ->
subscriptions = new CompositeDisposable
subscriptions.add @model.onDidAddChild(@childAdded.bind(this))
subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this))
subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this))
subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this))
subscriptions
isPaneResizeHandleElement: (element) ->
element?.nodeName.toLowerCase() is 'atom-pane-resize-handle'
childAdded: ({child, index}) ->
view = @viewRegistry.getView(child)
@insertBefore(view, @children[index * 2])
prevElement = view.previousSibling
# if previous element is not pane resize element, then insert new resize element
if prevElement? and not @isPaneResizeHandleElement(prevElement)
resizeHandle = document.createElement('atom-pane-resize-handle')
@insertBefore(resizeHandle, view)
nextElement = view.nextSibling
# if next element isnot resize element, then insert new resize element
if nextElement? and not @isPaneResizeHandleElement(nextElement)
resizeHandle = document.createElement('atom-pane-resize-handle')
@insertBefore(resizeHandle, nextElement)
childRemoved: ({child}) ->
view = @viewRegistry.getView(child)
siblingView = view.previousSibling
# make sure next sibling view is pane resize view
if siblingView? and @isPaneResizeHandleElement(siblingView)
siblingView.remove()
view.remove()
childReplaced: ({index, oldChild, newChild}) ->
focusedElement = document.activeElement if @hasFocus()
@childRemoved({child: oldChild, index})
@childAdded({child: newChild, index})
focusedElement?.focus() if document.activeElement is document.body
flexScaleChanged: (flexScale) -> @style.flexGrow = flexScale
hasFocus: ->
this is document.activeElement or @contains(document.activeElement)
module.exports = PaneAxisElement = document.registerElement 'atom-pane-axis', prototype: PaneAxisElement.prototype

121
src/pane-axis-element.js Normal file
View File

@@ -0,0 +1,121 @@
const { CompositeDisposable } = require('event-kit');
/* eslint-disable-next-line no-unused-vars */
const PaneResizeHandleElement = require('./pane-resize-handle-element');
class PaneAxisElement extends HTMLElement {
attachedCallback() {
if (this.subscriptions == null) {
this.subscriptions = this.subscribeToModel();
}
this.model
.getChildren()
.map((child, index) => this.childAdded({ child, index }));
}
detachedCallback() {
this.subscriptions.dispose();
this.subscriptions = null;
this.model.getChildren().map(child => this.childRemoved({ child }));
}
initialize(model, viewRegistry) {
this.model = model;
this.viewRegistry = viewRegistry;
if (this.subscriptions == null) {
this.subscriptions = this.subscribeToModel();
}
const iterable = this.model.getChildren();
for (let index = 0; index < iterable.length; index++) {
const child = iterable[index];
this.childAdded({ child, index });
}
switch (this.model.getOrientation()) {
case 'horizontal':
this.classList.add('horizontal', 'pane-row');
break;
case 'vertical':
this.classList.add('vertical', 'pane-column');
break;
}
return this;
}
subscribeToModel() {
const subscriptions = new CompositeDisposable();
subscriptions.add(this.model.onDidAddChild(this.childAdded.bind(this)));
subscriptions.add(
this.model.onDidRemoveChild(this.childRemoved.bind(this))
);
subscriptions.add(
this.model.onDidReplaceChild(this.childReplaced.bind(this))
);
subscriptions.add(
this.model.observeFlexScale(this.flexScaleChanged.bind(this))
);
return subscriptions;
}
isPaneResizeHandleElement(element) {
return (
(element != null ? element.nodeName.toLowerCase() : undefined) ===
'atom-pane-resize-handle'
);
}
childAdded({ child, index }) {
let resizeHandle;
const view = this.viewRegistry.getView(child);
this.insertBefore(view, this.children[index * 2]);
const prevElement = view.previousSibling;
// if previous element is not pane resize element, then insert new resize element
if (prevElement != null && !this.isPaneResizeHandleElement(prevElement)) {
resizeHandle = document.createElement('atom-pane-resize-handle');
this.insertBefore(resizeHandle, view);
}
const nextElement = view.nextSibling;
// if next element isnot resize element, then insert new resize element
if (nextElement != null && !this.isPaneResizeHandleElement(nextElement)) {
resizeHandle = document.createElement('atom-pane-resize-handle');
return this.insertBefore(resizeHandle, nextElement);
}
}
childRemoved({ child }) {
const view = this.viewRegistry.getView(child);
const siblingView = view.previousSibling;
// make sure next sibling view is pane resize view
if (siblingView != null && this.isPaneResizeHandleElement(siblingView)) {
siblingView.remove();
}
return view.remove();
}
childReplaced({ index, oldChild, newChild }) {
let focusedElement;
if (this.hasFocus()) {
focusedElement = document.activeElement;
}
this.childRemoved({ child: oldChild, index });
this.childAdded({ child: newChild, index });
if (document.activeElement === document.body) {
return focusedElement != null ? focusedElement.focus() : undefined;
}
}
flexScaleChanged(flexScale) {
this.style.flexGrow = flexScale;
}
hasFocus() {
return (
this === document.activeElement || this.contains(document.activeElement)
);
}
}
module.exports = document.registerElement('atom-pane-axis', {
prototype: PaneAxisElement.prototype
});

View File

@@ -1,80 +0,0 @@
class PaneResizeHandleElement extends HTMLElement
createdCallback: ->
@resizePane = @resizePane.bind(this)
@resizeStopped = @resizeStopped.bind(this)
@subscribeToDOMEvents()
subscribeToDOMEvents: ->
@addEventListener 'dblclick', @resizeToFitContent.bind(this)
@addEventListener 'mousedown', @resizeStarted.bind(this)
attachedCallback: ->
# For some reason Chromium 58 is firing the attached callback after the
# element has been detached, so we ignore the callback when a parent element
# can't be found.
if @parentElement
@isHorizontal = @parentElement.classList.contains("horizontal")
@classList.add if @isHorizontal then 'horizontal' else 'vertical'
detachedCallback: ->
@resizeStopped()
resizeToFitContent: ->
# clear flex-grow css style of both pane
@previousSibling?.model.setFlexScale(1)
@nextSibling?.model.setFlexScale(1)
resizeStarted: (e) ->
e.stopPropagation()
if not @overlay
@overlay = document.createElement('div')
@overlay.classList.add('atom-pane-cursor-overlay')
@overlay.classList.add(if @isHorizontal then 'horizontal' else 'vertical')
@appendChild @overlay
document.addEventListener 'mousemove', @resizePane
document.addEventListener 'mouseup', @resizeStopped
resizeStopped: ->
document.removeEventListener 'mousemove', @resizePane
document.removeEventListener 'mouseup', @resizeStopped
if @overlay
@removeChild @overlay
@overlay = undefined
calcRatio: (ratio1, ratio2, total) ->
allRatio = ratio1 + ratio2
[total * ratio1 / allRatio, total * ratio2 / allRatio]
setFlexGrow: (prevSize, nextSize) ->
@prevModel = @previousSibling.model
@nextModel = @nextSibling.model
totalScale = @prevModel.getFlexScale() + @nextModel.getFlexScale()
flexGrows = @calcRatio(prevSize, nextSize, totalScale)
@prevModel.setFlexScale flexGrows[0]
@nextModel.setFlexScale flexGrows[1]
fixInRange: (val, minValue, maxValue) ->
Math.min(Math.max(val, minValue), maxValue)
resizePane: ({clientX, clientY, which}) ->
return @resizeStopped() unless which is 1
return @resizeStopped() unless @previousSibling? and @nextSibling?
if @isHorizontal
totalWidth = @previousSibling.clientWidth + @nextSibling.clientWidth
#get the left and right width after move the resize view
leftWidth = clientX - @previousSibling.getBoundingClientRect().left
leftWidth = @fixInRange(leftWidth, 0, totalWidth)
rightWidth = totalWidth - leftWidth
# set the flex grow by the ratio of left width and right width
# to change pane width
@setFlexGrow(leftWidth, rightWidth)
else
totalHeight = @previousSibling.clientHeight + @nextSibling.clientHeight
topHeight = clientY - @previousSibling.getBoundingClientRect().top
topHeight = @fixInRange(topHeight, 0, totalHeight)
bottomHeight = totalHeight - topHeight
@setFlexGrow(topHeight, bottomHeight)
module.exports = PaneResizeHandleElement =
document.registerElement 'atom-pane-resize-handle', prototype: PaneResizeHandleElement.prototype

View File

@@ -0,0 +1,110 @@
class PaneResizeHandleElement extends HTMLElement {
createdCallback() {
this.resizePane = this.resizePane.bind(this);
this.resizeStopped = this.resizeStopped.bind(this);
this.subscribeToDOMEvents();
}
subscribeToDOMEvents() {
this.addEventListener('dblclick', this.resizeToFitContent.bind(this));
this.addEventListener('mousedown', this.resizeStarted.bind(this));
}
attachedCallback() {
// For some reason Chromium 58 is firing the attached callback after the
// element has been detached, so we ignore the callback when a parent element
// can't be found.
if (this.parentElement) {
this.isHorizontal = this.parentElement.classList.contains('horizontal');
this.classList.add(this.isHorizontal ? 'horizontal' : 'vertical');
}
}
detachedCallback() {
this.resizeStopped();
}
resizeToFitContent() {
// clear flex-grow css style of both pane
if (this.previousSibling != null) {
this.previousSibling.model.setFlexScale(1);
}
return this.nextSibling != null
? this.nextSibling.model.setFlexScale(1)
: undefined;
}
resizeStarted(e) {
e.stopPropagation();
if (!this.overlay) {
this.overlay = document.createElement('div');
this.overlay.classList.add('atom-pane-cursor-overlay');
this.overlay.classList.add(this.isHorizontal ? 'horizontal' : 'vertical');
this.appendChild(this.overlay);
}
document.addEventListener('mousemove', this.resizePane);
document.addEventListener('mouseup', this.resizeStopped);
}
resizeStopped() {
document.removeEventListener('mousemove', this.resizePane);
document.removeEventListener('mouseup', this.resizeStopped);
if (this.overlay) {
this.removeChild(this.overlay);
this.overlay = undefined;
}
}
calcRatio(ratio1, ratio2, total) {
const allRatio = ratio1 + ratio2;
return [(total * ratio1) / allRatio, (total * ratio2) / allRatio];
}
setFlexGrow(prevSize, nextSize) {
this.prevModel = this.previousSibling.model;
this.nextModel = this.nextSibling.model;
const totalScale =
this.prevModel.getFlexScale() + this.nextModel.getFlexScale();
const flexGrows = this.calcRatio(prevSize, nextSize, totalScale);
this.prevModel.setFlexScale(flexGrows[0]);
this.nextModel.setFlexScale(flexGrows[1]);
}
fixInRange(val, minValue, maxValue) {
return Math.min(Math.max(val, minValue), maxValue);
}
resizePane({ clientX, clientY, which }) {
if (which !== 1) {
return this.resizeStopped();
}
if (this.previousSibling == null || this.nextSibling == null) {
return this.resizeStopped();
}
if (this.isHorizontal) {
const totalWidth =
this.previousSibling.clientWidth + this.nextSibling.clientWidth;
// get the left and right width after move the resize view
let leftWidth =
clientX - this.previousSibling.getBoundingClientRect().left;
leftWidth = this.fixInRange(leftWidth, 0, totalWidth);
const rightWidth = totalWidth - leftWidth;
// set the flex grow by the ratio of left width and right width
// to change pane width
this.setFlexGrow(leftWidth, rightWidth);
} else {
const totalHeight =
this.previousSibling.clientHeight + this.nextSibling.clientHeight;
let topHeight =
clientY - this.previousSibling.getBoundingClientRect().top;
topHeight = this.fixInRange(topHeight, 0, totalHeight);
const bottomHeight = totalHeight - topHeight;
this.setFlexGrow(topHeight, bottomHeight);
}
}
}
module.exports = document.registerElement('atom-pane-resize-handle', {
prototype: PaneResizeHandleElement.prototype
});

View File

@@ -1,82 +0,0 @@
{Emitter, CompositeDisposable} = require 'event-kit'
class StylesElement extends HTMLElement
subscriptions: null
context: null
onDidAddStyleElement: (callback) ->
@emitter.on 'did-add-style-element', callback
onDidRemoveStyleElement: (callback) ->
@emitter.on 'did-remove-style-element', callback
onDidUpdateStyleElement: (callback) ->
@emitter.on 'did-update-style-element', callback
createdCallback: ->
@subscriptions = new CompositeDisposable
@emitter = new Emitter
@styleElementClonesByOriginalElement = new WeakMap
attachedCallback: ->
@context = @getAttribute('context') ? undefined
detachedCallback: ->
@subscriptions.dispose()
@subscriptions = new CompositeDisposable
attributeChangedCallback: (attrName, oldVal, newVal) ->
@contextChanged() if attrName is 'context'
initialize: (@styleManager) ->
throw new Error("Must pass a styleManager parameter when initializing a StylesElement") unless @styleManager?
@subscriptions.add @styleManager.observeStyleElements(@styleElementAdded.bind(this))
@subscriptions.add @styleManager.onDidRemoveStyleElement(@styleElementRemoved.bind(this))
@subscriptions.add @styleManager.onDidUpdateStyleElement(@styleElementUpdated.bind(this))
contextChanged: ->
return unless @subscriptions?
@styleElementRemoved(child) for child in Array::slice.call(@children)
@context = @getAttribute('context')
@styleElementAdded(styleElement) for styleElement in @styleManager.getStyleElements()
return
styleElementAdded: (styleElement) ->
return unless @styleElementMatchesContext(styleElement)
styleElementClone = styleElement.cloneNode(true)
styleElementClone.sourcePath = styleElement.sourcePath
styleElementClone.context = styleElement.context
styleElementClone.priority = styleElement.priority
@styleElementClonesByOriginalElement.set(styleElement, styleElementClone)
priority = styleElement.priority
if priority?
for child in @children
if child.priority > priority
insertBefore = child
break
@insertBefore(styleElementClone, insertBefore)
@emitter.emit 'did-add-style-element', styleElementClone
styleElementRemoved: (styleElement) ->
return unless @styleElementMatchesContext(styleElement)
styleElementClone = @styleElementClonesByOriginalElement.get(styleElement) ? styleElement
styleElementClone.remove()
@emitter.emit 'did-remove-style-element', styleElementClone
styleElementUpdated: (styleElement) ->
return unless @styleElementMatchesContext(styleElement)
styleElementClone = @styleElementClonesByOriginalElement.get(styleElement)
styleElementClone.textContent = styleElement.textContent
@emitter.emit 'did-update-style-element', styleElementClone
styleElementMatchesContext: (styleElement) ->
not @context? or styleElement.context is @context
module.exports = StylesElement = document.registerElement 'atom-styles', prototype: StylesElement.prototype

145
src/styles-element.js Normal file
View File

@@ -0,0 +1,145 @@
const { Emitter, CompositeDisposable } = require('event-kit');
class StylesElement extends HTMLElement {
constructor() {
super();
this.subscriptions = null;
this.context = null;
}
onDidAddStyleElement(callback) {
this.emitter.on('did-add-style-element', callback);
}
onDidRemoveStyleElement(callback) {
this.emitter.on('did-remove-style-element', callback);
}
onDidUpdateStyleElement(callback) {
this.emitter.on('did-update-style-element', callback);
}
createdCallback() {
this.subscriptions = new CompositeDisposable();
this.emitter = new Emitter();
this.styleElementClonesByOriginalElement = new WeakMap();
}
attachedCallback() {
let left;
this.context =
(left = this.getAttribute('context')) != null ? left : undefined;
}
detachedCallback() {
this.subscriptions.dispose();
this.subscriptions = new CompositeDisposable();
}
attributeChangedCallback(attrName) {
if (attrName === 'context') {
return this.contextChanged();
}
}
initialize(styleManager) {
this.styleManager = styleManager;
if (this.styleManager == null) {
throw new Error(
'Must pass a styleManager parameter when initializing a StylesElement'
);
}
this.subscriptions.add(
this.styleManager.observeStyleElements(this.styleElementAdded.bind(this))
);
this.subscriptions.add(
this.styleManager.onDidRemoveStyleElement(
this.styleElementRemoved.bind(this)
)
);
return this.subscriptions.add(
this.styleManager.onDidUpdateStyleElement(
this.styleElementUpdated.bind(this)
)
);
}
contextChanged() {
if (this.subscriptions == null) {
return;
}
for (let child of Array.from(Array.prototype.slice.call(this.children))) {
this.styleElementRemoved(child);
}
this.context = this.getAttribute('context');
for (let styleElement of Array.from(this.styleManager.getStyleElements())) {
this.styleElementAdded(styleElement);
}
}
styleElementAdded(styleElement) {
let insertBefore;
if (!this.styleElementMatchesContext(styleElement)) {
return;
}
const styleElementClone = styleElement.cloneNode(true);
styleElementClone.sourcePath = styleElement.sourcePath;
styleElementClone.context = styleElement.context;
styleElementClone.priority = styleElement.priority;
this.styleElementClonesByOriginalElement.set(
styleElement,
styleElementClone
);
const { priority } = styleElement;
if (priority != null) {
for (let child of this.children) {
if (child.priority > priority) {
insertBefore = child;
break;
}
}
}
this.insertBefore(styleElementClone, insertBefore);
this.emitter.emit('did-add-style-element', styleElementClone);
}
styleElementRemoved(styleElement) {
let left;
if (!this.styleElementMatchesContext(styleElement)) {
return;
}
const styleElementClone =
(left = this.styleElementClonesByOriginalElement.get(styleElement)) !=
null
? left
: styleElement;
styleElementClone.remove();
this.emitter.emit('did-remove-style-element', styleElementClone);
}
styleElementUpdated(styleElement) {
if (!this.styleElementMatchesContext(styleElement)) {
return;
}
const styleElementClone = this.styleElementClonesByOriginalElement.get(
styleElement
);
styleElementClone.textContent = styleElement.textContent;
this.emitter.emit('did-update-style-element', styleElementClone);
}
styleElementMatchesContext(styleElement) {
return this.context == null || styleElement.context === this.context;
}
}
module.exports = document.registerElement('atom-styles', {
prototype: StylesElement.prototype
});