mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-11 18:32:20 +08:00
1d99a18bf6
Summary: tooltip fades in now Test Plan: edgehill --test Reviewers: bengotow Reviewed By: bengotow Differential Revision: https://review.inboxapp.com/D1317
169 lines
5.3 KiB
CoffeeScript
169 lines
5.3 KiB
CoffeeScript
_ = require 'underscore-plus'
|
|
React = require 'react/addons'
|
|
{CompositeDisposable} = require 'event-kit'
|
|
{RetinaImg} = require 'ui-components'
|
|
|
|
module.exports =
|
|
FloatingToolbar = React.createClass
|
|
getInitialState: ->
|
|
mode: "buttons"
|
|
urlInputValue: @_initialUrl() ? ""
|
|
|
|
componentDidMount: ->
|
|
@isHovering = false
|
|
@subscriptions = new CompositeDisposable()
|
|
@_saveUrl = _.debounce @__saveUrl, 10
|
|
|
|
componentWillReceiveProps: (nextProps) ->
|
|
@setState
|
|
mode: nextProps.initialMode
|
|
urlInputValue: @_initialUrl(nextProps)
|
|
|
|
componentWillUnmount: ->
|
|
@subscriptions?.dispose()
|
|
@isHovering = false
|
|
|
|
componentDidUpdate: ->
|
|
if @state.mode is "edit-link" and not @props.linkToModify
|
|
# Note, it's important that we're focused on the urlInput because
|
|
# the parent of this component needs to know to not hide us on their
|
|
# onBlur method.
|
|
@refs.urlInput.getDOMNode().focus() if @isMounted()
|
|
|
|
render: ->
|
|
<div ref="floatingToolbar"
|
|
className={@_toolbarClasses()} style={@_toolbarStyles()}>
|
|
<div className="toolbar-pointer" style={@_toolbarPointerStyles()}></div>
|
|
{@_toolbarType()}
|
|
</div>
|
|
|
|
_toolbarClasses: ->
|
|
classes = {}
|
|
classes[@props.pos] = true
|
|
React.addons.classSet _.extend classes,
|
|
"floating-toolbar": true
|
|
"toolbar": true
|
|
"toolbar-visible": @props.visible
|
|
|
|
_toolbarStyles: ->
|
|
styles =
|
|
left: @_toolbarLeft()
|
|
top: @props.top
|
|
return styles
|
|
|
|
_toolbarType: ->
|
|
if @state.mode is "buttons" then @_renderButtons()
|
|
else if @state.mode is "edit-link" then @_renderLink()
|
|
else return <div></div>
|
|
|
|
_renderButtons: ->
|
|
<div className="toolbar-buttons">
|
|
<button className="btn btn-bold toolbar-btn"
|
|
onClick={@_execCommand}
|
|
data-command-name="bold"></button>
|
|
<button className="btn btn-italic toolbar-btn"
|
|
onClick={@_execCommand}
|
|
data-command-name="italic"></button>
|
|
<button className="btn btn-underline toolbar-btn"
|
|
onClick={@_execCommand}
|
|
data-command-name="underline"></button>
|
|
<button className="btn btn-link toolbar-btn"
|
|
onClick={@_showLink}
|
|
data-command-name="link"></button>
|
|
</div>
|
|
|
|
_renderLink: ->
|
|
removeBtn = ""
|
|
if @_initialUrl()
|
|
removeBtn = <button className="btn btn-icon"
|
|
onMouseDown={@_removeUrl}><i className="fa fa-times"></i></button>
|
|
|
|
<div className="toolbar-new-link"
|
|
onMouseEnter={@_onMouseEnter}
|
|
onMouseLeave={@_onMouseLeave}>
|
|
<i className="fa fa-link preview-btn-icon"></i>
|
|
<input type="text"
|
|
ref="urlInput"
|
|
value={@state.urlInputValue}
|
|
onBlur={@_saveUrl}
|
|
onKeyPress={@_saveUrlOnEnter}
|
|
onChange={@_onInputChange}
|
|
className="floating-toolbar-input"
|
|
placeholder="Paste or type a link" />
|
|
<button className="btn btn-icon"
|
|
onKeyPress={@_saveUrlOnEnter}
|
|
onMouseDown={@_saveUrl}><i className="fa fa-check"></i></button>
|
|
{removeBtn}
|
|
</div>
|
|
|
|
_onMouseEnter: ->
|
|
@isHovering = true
|
|
@props.onMouseEnter?()
|
|
|
|
_onMouseLeave: ->
|
|
@isHovering = false
|
|
if @props.linkToModify and document.activeElement isnt @refs.urlInput.getDOMNode()
|
|
@props.onMouseLeave?()
|
|
|
|
|
|
_initialUrl: (props=@props) ->
|
|
props.linkToModify?.getAttribute?('href')
|
|
|
|
_onInputChange: (event) ->
|
|
@setState urlInputValue: event.target.value
|
|
|
|
_saveUrlOnEnter: (event) ->
|
|
if event.key is "Enter" and @state.urlInputValue.trim().length > 0
|
|
@_saveUrl()
|
|
|
|
# We signify the removal of a url with an empty string. This protects us
|
|
# from the case where people delete the url text and hit save. In that
|
|
# case we also want to remove the link.
|
|
_removeUrl: ->
|
|
@setState urlInputValue: ""
|
|
@props.onSaveUrl "", @props.linkToModify
|
|
|
|
__saveUrl: ->
|
|
return unless @isMounted() and @state.urlInputValue?
|
|
@props.onSaveUrl @state.urlInputValue, @props.linkToModify
|
|
|
|
_execCommand: (event) ->
|
|
cmd = event.currentTarget.getAttribute 'data-command-name'
|
|
document.execCommand(cmd, false, null)
|
|
true
|
|
|
|
_toolbarLeft: ->
|
|
CONTENT_PADDING = @props.contentPadding ? 15
|
|
max = @props.editAreaWidth - @_halfWidth()*2 - CONTENT_PADDING
|
|
left = Math.min(Math.max(@props.left - @_halfWidth(), CONTENT_PADDING), max)
|
|
return left
|
|
|
|
_toolbarPointerStyles: ->
|
|
CONTENT_PADDING = @props.contentPadding ? 15
|
|
POINTER_WIDTH = 6 + 2 #2px of border-radius
|
|
max = @props.editAreaWidth - CONTENT_PADDING
|
|
min = CONTENT_PADDING
|
|
absoluteLeft = Math.max(Math.min(@props.left, max), min)
|
|
relativeLeft = absoluteLeft - @_toolbarLeft()
|
|
|
|
left = Math.max(Math.min(relativeLeft, @_halfWidth()*2-POINTER_WIDTH), POINTER_WIDTH)
|
|
styles =
|
|
left: left
|
|
return styles
|
|
|
|
_halfWidth: ->
|
|
# We can't calculate the width of the floating toolbar declaratively
|
|
# because it hasn't been rendered yet. As such, we'll keep the width
|
|
# fixed to make it much eaier.
|
|
TOOLBAR_BUTTONS_WIDTH = 114#px
|
|
TOOLBAR_URL_WIDTH = 210#px
|
|
|
|
if @state.mode is "buttons"
|
|
TOOLBAR_BUTTONS_WIDTH / 2
|
|
else if @state.mode is "edit-link"
|
|
TOOLBAR_URL_WIDTH / 2
|
|
else
|
|
TOOLBAR_BUTTONS_WIDTH / 2
|
|
|
|
_showLink: ->
|
|
@setState mode: "edit-link"
|