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:
Nathan Sobo
2014-11-14 08:18:35 -07:00
18 changed files with 465 additions and 221 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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}\"]")