mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Merge pull request #4165 from atom/ns-shadow-dom-style-updates
Make it easier to style atom-text-editor from outside its shadow root
This commit is contained in:
@@ -59,7 +59,7 @@ LinesComponent = React.createClass
|
||||
@renderedDecorationsByLineId = {}
|
||||
|
||||
componentDidMount: ->
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
if @props.useShadowDOM
|
||||
insertionPoint = document.createElement('content')
|
||||
insertionPoint.setAttribute('select', '.overlayer')
|
||||
@getDOMNode().appendChild(insertionPoint)
|
||||
|
||||
@@ -18,6 +18,9 @@ class StylesElement extends HTMLElement
|
||||
@styleElementClonesByOriginalElement = new WeakMap
|
||||
|
||||
attachedCallback: ->
|
||||
if @context is 'atom-text-editor'
|
||||
for styleElement in @children
|
||||
@upgradeDeprecatedSelectors(styleElement)
|
||||
@initialize()
|
||||
|
||||
detachedCallback: ->
|
||||
@@ -48,6 +51,7 @@ class StylesElement extends HTMLElement
|
||||
return unless @styleElementMatchesContext(styleElement)
|
||||
|
||||
styleElementClone = styleElement.cloneNode(true)
|
||||
styleElementClone.sourcePath = styleElement.sourcePath
|
||||
styleElementClone.context = styleElement.context
|
||||
@styleElementClonesByOriginalElement.set(styleElement, styleElementClone)
|
||||
|
||||
@@ -59,6 +63,10 @@ class StylesElement extends HTMLElement
|
||||
break
|
||||
|
||||
@insertBefore(styleElementClone, insertBefore)
|
||||
|
||||
if @context is 'atom-text-editor'
|
||||
@upgradeDeprecatedSelectors(styleElementClone)
|
||||
|
||||
@emitter.emit 'did-add-style-element', styleElementClone
|
||||
|
||||
styleElementRemoved: (styleElement) ->
|
||||
@@ -78,4 +86,30 @@ class StylesElement extends HTMLElement
|
||||
styleElementMatchesContext: (styleElement) ->
|
||||
not @context? or styleElement.context is @context
|
||||
|
||||
upgradeDeprecatedSelectors: (styleElement) ->
|
||||
return unless styleElement.sheet?
|
||||
|
||||
upgradedSelectors = []
|
||||
|
||||
for rule in styleElement.sheet.cssRules
|
||||
continue if /\:host/.test(rule.selectorText)
|
||||
|
||||
inputSelector = rule.selectorText
|
||||
outputSelector = rule.selectorText
|
||||
.replace(/\.editor-colors($|[ >])/g, ':host$1')
|
||||
.replace(/\.editor([:.][^ ,>]+)/g, ':host($1)')
|
||||
.replace(/\.editor($|[ ,>])/g, ':host$1')
|
||||
|
||||
unless inputSelector is outputSelector
|
||||
rule.selectorText = outputSelector
|
||||
upgradedSelectors.push({inputSelector, outputSelector})
|
||||
|
||||
if upgradedSelectors.length > 0
|
||||
warning = "Upgraded the following syntax theme selectors in `#{styleElement.sourcePath}` for shadow DOM compatibility:\n\n"
|
||||
for {inputSelector, outputSelector} in upgradedSelectors
|
||||
warning += "`#{inputSelector}` => `#{outputSelector}`\n"
|
||||
|
||||
warning += "\nSee the upgrade guide for information on removing this warning."
|
||||
console.warn(warning)
|
||||
|
||||
module.exports = StylesElement = document.registerElement 'atom-styles', prototype: StylesElement.prototype
|
||||
|
||||
@@ -50,7 +50,7 @@ TextEditorComponent = React.createClass
|
||||
|
||||
render: ->
|
||||
{focused, showIndentGuide, showLineNumbers, visible} = @state
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement} = @props
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement, useShadowDOM} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty()
|
||||
style = {}
|
||||
@@ -90,7 +90,10 @@ TextEditorComponent = React.createClass
|
||||
|
||||
style.height = scrollViewHeight if @autoHeight
|
||||
|
||||
className = 'editor-contents'
|
||||
if useShadowDOM
|
||||
className = 'editor-contents--private'
|
||||
else
|
||||
className = 'editor-contents'
|
||||
className += ' is-focused' if focused
|
||||
className += ' has-selection' if hasSelection
|
||||
|
||||
@@ -117,7 +120,7 @@ TextEditorComponent = React.createClass
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, mini
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, mini, useShadowDOM
|
||||
}
|
||||
|
||||
ScrollbarComponent
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
{View, $, callRemoveHooks} = require 'space-pen'
|
||||
React = require 'react-atom-fork'
|
||||
Path = require 'path'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorComponent = require './text-editor-component'
|
||||
TextEditorView = null
|
||||
|
||||
ShadowStyleSheet = null
|
||||
|
||||
class TextEditorElement extends HTMLElement
|
||||
model: null
|
||||
componentDescriptor: null
|
||||
@@ -25,24 +28,31 @@ class TextEditorElement extends HTMLElement
|
||||
@setAttribute('tabindex', -1)
|
||||
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
@useShadowDOM = true
|
||||
|
||||
unless ShadowStyleSheet?
|
||||
ShadowStyleSheet = document.createElement('style')
|
||||
ShadowStyleSheet.textContent = atom.themes.loadLessStylesheet(require.resolve('../static/text-editor-shadow.less'))
|
||||
|
||||
@createShadowRoot()
|
||||
|
||||
@shadowRoot.appendChild(ShadowStyleSheet.cloneNode(true))
|
||||
@stylesElement = document.createElement('atom-styles')
|
||||
@stylesElement.setAttribute('context', 'atom-text-editor')
|
||||
@stylesElement.initialize()
|
||||
|
||||
@rootElement = document.createElement('div')
|
||||
@rootElement.classList.add('shadow')
|
||||
@rootElement.classList.add('editor--private')
|
||||
|
||||
@shadowRoot.appendChild(@stylesElement)
|
||||
@shadowRoot.appendChild(@rootElement)
|
||||
else
|
||||
@useShadowDOM = false
|
||||
|
||||
@classList.add('editor', 'editor-colors')
|
||||
@stylesElement = document.head.querySelector('atom-styles')
|
||||
@rootElement = this
|
||||
|
||||
@rootElement.classList.add('editor', 'editor-colors')
|
||||
|
||||
|
||||
createSpacePenShim: ->
|
||||
TextEditorView ?= require './text-editor-view'
|
||||
@__spacePenView = new TextEditorView(this)
|
||||
@@ -60,6 +70,7 @@ class TextEditorElement extends HTMLElement
|
||||
@model = model
|
||||
@mountComponent()
|
||||
@addGrammarScopeAttribute()
|
||||
@addMiniAttributeIfNeeded()
|
||||
@model.onDidChangeGrammar => @addGrammarScopeAttribute()
|
||||
@addEncodingAttribute()
|
||||
@model.onDidChangeEncoding => @addEncodingAttribute()
|
||||
@@ -88,10 +99,11 @@ class TextEditorElement extends HTMLElement
|
||||
editor: @model
|
||||
mini: @model.mini
|
||||
lineOverdrawMargin: @lineOverdrawMargin
|
||||
useShadowDOM: @useShadowDOM
|
||||
)
|
||||
@component = React.renderComponent(@componentDescriptor, @rootElement)
|
||||
|
||||
unless atom.config.get('editor.useShadowDOM')
|
||||
unless @useShadowDOM
|
||||
inputNode = @component.refs.input.getDOMNode()
|
||||
inputNode.addEventListener 'focus', @focused.bind(this)
|
||||
inputNode.addEventListener 'blur', => @dispatchEvent(new FocusEvent('blur', bubbles: false))
|
||||
@@ -109,7 +121,7 @@ class TextEditorElement extends HTMLElement
|
||||
@focusOnAttach = true
|
||||
|
||||
blurred: (event) ->
|
||||
unless atom.config.get('editor.useShadowDOM')
|
||||
unless @useShadowDOM
|
||||
if event.relatedTarget is @component?.refs.input?.getDOMNode()
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
@@ -120,6 +132,9 @@ class TextEditorElement extends HTMLElement
|
||||
grammarScope = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')
|
||||
@dataset.grammar = grammarScope
|
||||
|
||||
addMiniAttributeIfNeeded: ->
|
||||
@setAttributeNode(document.createAttribute("mini")) if @model.isMini()
|
||||
|
||||
addEncodingAttribute: ->
|
||||
@dataset.encoding = @model.getEncoding()
|
||||
|
||||
@@ -199,7 +214,7 @@ atom.commands.add 'atom-text-editor', stopEventPropagationAndGroupUndo(
|
||||
'editor:lower-case': -> @lowerCase()
|
||||
)
|
||||
|
||||
atom.commands.add 'atom-text-editor:not(.mini)', stopEventPropagationAndGroupUndo(
|
||||
atom.commands.add 'atom-text-editor:not([mini])', stopEventPropagationAndGroupUndo(
|
||||
'core:move-up': -> @moveUp()
|
||||
'core:move-down': -> @moveDown()
|
||||
'core:move-to-top': -> @moveToTop()
|
||||
|
||||
@@ -6,7 +6,7 @@ Delegator = require 'delegato'
|
||||
{Model} = require 'theorist'
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{Point, Range} = TextBuffer = require 'text-buffer'
|
||||
LanguageMode = require './language-mode'
|
||||
DisplayBuffer = require './display-buffer'
|
||||
Cursor = require './cursor'
|
||||
@@ -84,6 +84,7 @@ class TextEditor extends Model
|
||||
@cursors = []
|
||||
@selections = []
|
||||
|
||||
buffer ?= new TextBuffer
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped})
|
||||
@buffer = @displayBuffer.buffer
|
||||
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
|
||||
|
||||
@@ -249,9 +249,6 @@ class ThemeManager
|
||||
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
|
||||
@requireStylesheet(nativeStylesheetPath)
|
||||
|
||||
textEditorStylesPath = path.join(@resourcePath, 'static', 'text-editor-shadow.less')
|
||||
atom.styles.addStyleSheet(@loadLessStylesheet(textEditorStylesPath), sourcePath: textEditorStylesPath, context: 'atom-text-editor')
|
||||
|
||||
stylesheetElementForId: (id) ->
|
||||
document.head.querySelector("atom-styles style[source-path=\"#{id}\"]")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user