mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-21 13:51:59 +02:00
refactor onKeyDown to use data object
This commit is contained in:
parent
fba3fe7a13
commit
d20b8511bb
History.md
examples
auto-markdown
code-highlighting
development/performance-rich
images
links
paste-html
rich-text
tables
lib
package.json@ -5,6 +5,13 @@ This document maintains a list of changes to Slate with each new version. Until
|
||||
---
|
||||
|
||||
|
||||
### `0.8.0` — _July 27, 2016_
|
||||
|
||||
- **The `onKeyDown` and `onBeforeInput` handlers signatures have changed!** Previously, some Slate handlers had a signature of `(e, state, editor)` and others had a signature of `(e, data, state, editor)`. Now all handlers will be passed a data object, even if it is empty. This is helpful for future compatibility where we might need to add data to a handler that previously didn't have any, and is nicer for consistency. The `onKeyDown` handler's new `data` object contains the `key` name and a series of `is*` properties to make handling hotkeys easier. The `onBeforeInput` handler's new `data` object is empty.
|
||||
|
||||
- **The `Utils` export has been removed.** Previously, a `Key` utility and the `findDOMNode` utility were exposed under the `Utils` object. The `Key` has been removed in favor of the `data` object passed to `onKeyDown`. And then `findDOMNode` utility has been upgraded to a top-level named export, so you'll now need to access it via `import { findDOMNode } from 'slate'`.
|
||||
|
||||
|
||||
### `0.7.0` — _July 24, 2016_
|
||||
|
||||
#### BREAKING CHANGES
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
import { Editor, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import keycode from 'keycode'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
@ -108,13 +107,13 @@ class AutoMarkdown extends React.Component {
|
||||
* On key down, check for our specific key shortcuts.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Data} data
|
||||
* @param {State} state
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onKeyDown = (e, state) => {
|
||||
const key = keycode(e.which)
|
||||
switch (key) {
|
||||
onKeyDown = (e, data, state) => {
|
||||
switch (data.key) {
|
||||
case 'space': return this.onSpace(e, state)
|
||||
case 'backspace': return this.onBackspace(e, state)
|
||||
case 'enter': return this.onEnter(e, state)
|
||||
|
@ -2,7 +2,6 @@
|
||||
import { Editor, Mark, Raw, Selection } from '../..'
|
||||
import Prism from 'prismjs'
|
||||
import React from 'react'
|
||||
import keycode from 'keycode'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
@ -65,13 +64,13 @@ class CodeHighlighting extends React.Component {
|
||||
* On key down inside code blocks, insert soft new lines.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
onKeyDown = (e, state) => {
|
||||
const key = keycode(e.which)
|
||||
if (key != 'enter') return
|
||||
onKeyDown = (e, data, state) => {
|
||||
if (data.key != 'enter') return
|
||||
const { startBlock } = state
|
||||
if (startBlock.type != 'code') return
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
import { Editor, Mark, Raw, Utils } from '../../..'
|
||||
import { Editor, Mark, Raw } from '../../..'
|
||||
import React from 'react'
|
||||
import initialState from './state.json'
|
||||
import keycode from 'keycode'
|
||||
|
||||
/**
|
||||
* Define the default node type.
|
||||
@ -105,16 +104,16 @@ class RichText extends React.Component {
|
||||
* On key down, if it's a formatting command toggle a mark.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
onKeyDown = (e, state) => {
|
||||
if (!Utils.Key.isCommand(e)) return
|
||||
const key = keycode(e.which)
|
||||
onKeyDown = (e, data, state) => {
|
||||
if (!data.isMod) return
|
||||
let mark
|
||||
|
||||
switch (key) {
|
||||
switch (data.key) {
|
||||
case 'b':
|
||||
mark = 'bold'
|
||||
break
|
||||
|
@ -162,18 +162,18 @@ class Images extends React.Component {
|
||||
* On drop, insert the image wherever it is dropped.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} drop
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
onDrop = (e, drop, state) => {
|
||||
if (drop.type != 'node') return
|
||||
onDrop = (e, data, state) => {
|
||||
if (data.type != 'node') return
|
||||
return state
|
||||
.transform()
|
||||
.removeNodeByKey(drop.node.key)
|
||||
.moveTo(drop.target)
|
||||
.insertBlock(drop.node)
|
||||
.removeNodeByKey(data.node.key)
|
||||
.moveTo(data.target)
|
||||
.insertBlock(data.node)
|
||||
.apply()
|
||||
}
|
||||
|
||||
@ -181,16 +181,16 @@ class Images extends React.Component {
|
||||
* On paste, if the pasted content is an image URL, insert it.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} paste
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
onPaste = (e, paste, state) => {
|
||||
if (paste.type != 'text') return
|
||||
if (!isUrl(paste.text)) return
|
||||
if (!isImage(paste.text)) return
|
||||
return this.insertImage(state, paste.text)
|
||||
onPaste = (e, data, state) => {
|
||||
if (data.type != 'text') return
|
||||
if (!isUrl(data.text)) return
|
||||
if (!isImage(data.text)) return
|
||||
return this.insertImage(state, data.text)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,14 +106,14 @@ class Links extends React.Component {
|
||||
* On paste, if the text is a link, wrap the selection in a link.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} paste
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
*/
|
||||
|
||||
onPaste = (e, paste, state) => {
|
||||
onPaste = (e, data, state) => {
|
||||
if (state.isCollapsed) return
|
||||
if (paste.type != 'text' && paste.type != 'html') return
|
||||
if (!isUrl(paste.text)) return
|
||||
if (data.type != 'text' && data.type != 'html') return
|
||||
if (!isUrl(data.text)) return
|
||||
|
||||
let transform = state.transform()
|
||||
|
||||
@ -122,7 +122,7 @@ class Links extends React.Component {
|
||||
}
|
||||
|
||||
return transform
|
||||
.wrapInline('link', { href: paste.text })
|
||||
.wrapInline('link', { href: data.text })
|
||||
.collapseToEnd()
|
||||
.apply()
|
||||
}
|
||||
|
@ -188,14 +188,13 @@ class PasteHtml extends React.Component {
|
||||
* On paste, deserialize the HTML and then insert the fragment.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} paste
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
*/
|
||||
|
||||
onPaste = (e, paste, state) => {
|
||||
if (paste.type != 'html') return
|
||||
const { html } = paste
|
||||
const { document } = serializer.deserialize(html)
|
||||
onPaste = (e, data, state) => {
|
||||
if (data.type != 'html') return
|
||||
const { document } = serializer.deserialize(data.html)
|
||||
|
||||
return state
|
||||
.transform()
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
import { Editor, Mark, Raw, Utils } from '../..'
|
||||
import { Editor, Mark, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import initialState from './state.json'
|
||||
import keycode from 'keycode'
|
||||
|
||||
/**
|
||||
* Define the default node type.
|
||||
@ -105,16 +104,16 @@ class RichText extends React.Component {
|
||||
* On key down, if it's a formatting command toggle a mark.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
onKeyDown = (e, state) => {
|
||||
if (!Utils.Key.isCommand(e)) return
|
||||
const key = keycode(e.which)
|
||||
onKeyDown = (e, data, state) => {
|
||||
if (!data.isMod) return
|
||||
let mark
|
||||
|
||||
switch (key) {
|
||||
switch (data.key) {
|
||||
case 'b':
|
||||
mark = 'bold'
|
||||
break
|
||||
|
@ -101,13 +101,14 @@ class Tables extends React.Component {
|
||||
* On key down, check for our specific key shortcuts.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onKeyDown = (e, state) => {
|
||||
onKeyDown = (e, data, state) => {
|
||||
if (state.startBlock.type != 'table-cell') return
|
||||
switch (keycode(e.which)) {
|
||||
switch (data.key) {
|
||||
case 'backspace': return this.onBackspace(e, state)
|
||||
case 'delete': return this.onDelete(e, state)
|
||||
case 'enter': return this.onEnter(e, state)
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
import Base64 from '../serializers/base-64'
|
||||
import Key from '../utils/key'
|
||||
import Node from './node'
|
||||
import OffsetKey from '../utils/offset-key'
|
||||
import Raw from '../serializers/raw'
|
||||
@ -9,7 +8,7 @@ import Selection from '../models/selection'
|
||||
import TYPES from '../utils/types'
|
||||
import includes from 'lodash/includes'
|
||||
import keycode from 'keycode'
|
||||
import { IS_FIREFOX } from '../utils/environment'
|
||||
import { IS_FIREFOX, IS_MAC } from '../utils/environment'
|
||||
|
||||
/**
|
||||
* Noop.
|
||||
@ -454,7 +453,23 @@ class Content extends React.Component {
|
||||
onKeyDown = (e) => {
|
||||
if (this.props.readOnly) return
|
||||
const key = keycode(e.which)
|
||||
const data = {}
|
||||
|
||||
// Add helpful properties for handling hotkeys to the data object.
|
||||
data.code = e.which
|
||||
data.key = key
|
||||
data.isAlt = e.altKey
|
||||
data.isCmd = IS_MAC ? e.metaKey && !e.altKey : false
|
||||
data.isCtrl = e.ctrlKey && !e.altKey
|
||||
data.isLine = IS_MAC ? e.metaKey : false
|
||||
data.isMeta = e.metaKey
|
||||
data.isMod = IS_MAC ? e.metaKey && !e.altKey : e.ctrlKey && !e.altKey
|
||||
data.isShift = e.shiftKey
|
||||
data.isWord = IS_MAC ? e.altKey : e.ctrlKey
|
||||
|
||||
// When composing, these characters commit the composition but also move the
|
||||
// selection before we're able to handle it, so prevent their default,
|
||||
// selection-moving behavior.
|
||||
if (
|
||||
this.tmp.isComposing &&
|
||||
(key == 'left' || key == 'right' || key == 'up' || key == 'down')
|
||||
@ -463,19 +478,21 @@ class Content extends React.Component {
|
||||
return
|
||||
}
|
||||
|
||||
// These key commands have native behavior in contenteditable elements which
|
||||
// will cause our state to be out of sync, so prevent them.
|
||||
if (
|
||||
(key == 'enter') ||
|
||||
(key == 'backspace') ||
|
||||
(key == 'delete') ||
|
||||
(key == 'b' && Key.isCommand(e)) ||
|
||||
(key == 'i' && Key.isCommand(e)) ||
|
||||
(key == 'y' && Key.isWindowsCommand(e)) ||
|
||||
(key == 'z' && Key.isCommand(e))
|
||||
(key == 'b' && data.isMod) ||
|
||||
(key == 'i' && data.isMod) ||
|
||||
(key == 'y' && data.isMod) ||
|
||||
(key == 'z' && data.isMod)
|
||||
) {
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
this.props.onKeyDown(e)
|
||||
this.props.onKeyDown(e, data)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -488,37 +505,37 @@ class Content extends React.Component {
|
||||
if (this.props.readOnly) return
|
||||
e.preventDefault()
|
||||
|
||||
const data = e.clipboardData
|
||||
const paste = {}
|
||||
const { clipboardData } = e
|
||||
const data = {}
|
||||
|
||||
// COMPAT: In Firefox, `types` is array-like. (2016/06/21)
|
||||
const types = Array.from(data.types)
|
||||
const types = Array.from(clipboardData.types)
|
||||
|
||||
// Handle files.
|
||||
if (data.files.length) {
|
||||
paste.type = 'files'
|
||||
paste.files = data.files
|
||||
if (clipboardData.files.length) {
|
||||
data.type = 'files'
|
||||
data.files = clipboardData.files
|
||||
}
|
||||
|
||||
// Treat it as rich text if there is HTML content.
|
||||
else if (includes(types, TYPES.HTML)) {
|
||||
paste.type = 'html'
|
||||
paste.text = data.getData(TYPES.TEXT)
|
||||
paste.html = data.getData(TYPES.HTML)
|
||||
data.type = 'html'
|
||||
data.text = clipboardData.getData(TYPES.TEXT)
|
||||
data.html = clipboardData.getData(TYPES.HTML)
|
||||
}
|
||||
|
||||
// Treat everything else as plain text.
|
||||
else {
|
||||
paste.type = 'text'
|
||||
paste.text = data.getData(TYPES.TEXT)
|
||||
data.type = 'text'
|
||||
data.text = clipboardData.getData(TYPES.TEXT)
|
||||
}
|
||||
|
||||
// If html, and the html includes a `data-fragment` attribute, it's actually
|
||||
// a raw-serialized JSON fragment from a previous cut/copy, so deserialize
|
||||
// it and insert it normally.
|
||||
if (paste.type == 'html' && ~paste.html.indexOf('<span data-fragment="')) {
|
||||
if (data.type == 'html' && ~data.html.indexOf('<span data-fragment="')) {
|
||||
const regexp = /data-fragment="([^\s]+)"/
|
||||
const matches = regexp.exec(paste.html)
|
||||
const matches = regexp.exec(data.html)
|
||||
const [ full, encoded ] = matches
|
||||
const fragment = Base64.deserializeNode(encoded)
|
||||
let { state } = this.props
|
||||
@ -532,8 +549,7 @@ class Content extends React.Component {
|
||||
return
|
||||
}
|
||||
|
||||
paste.data = data
|
||||
this.props.onPaste(e, paste)
|
||||
this.props.onPaste(e, data)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -551,12 +567,12 @@ class Content extends React.Component {
|
||||
const { state, renderDecorations } = this.props
|
||||
let { document, selection } = state
|
||||
const native = window.getSelection()
|
||||
const select = {}
|
||||
const data = {}
|
||||
|
||||
// If there are no ranges, the editor was blurred natively.
|
||||
if (!native.rangeCount) {
|
||||
select.selection = selection.merge({ isFocused: false })
|
||||
select.isNative = true
|
||||
data.selection = selection.merge({ isFocused: false })
|
||||
data.isNative = true
|
||||
}
|
||||
|
||||
// Otherwise, determine the Slate selection from the native one.
|
||||
@ -579,12 +595,12 @@ class Content extends React.Component {
|
||||
|
||||
// If the native selection is inside text nodes, we can trust the native
|
||||
// state and not need to re-render.
|
||||
select.isNative = (
|
||||
data.isNative = (
|
||||
anchorNode.nodeType == 3 &&
|
||||
focusNode.nodeType == 3
|
||||
)
|
||||
|
||||
select.selection = selection.merge({
|
||||
data.selection = selection.merge({
|
||||
anchorKey: anchor.key,
|
||||
anchorOffset: anchor.offset,
|
||||
focusKey: focus.key,
|
||||
@ -593,7 +609,7 @@ class Content extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
this.props.onSelect(e, select)
|
||||
this.props.onSelect(e, data)
|
||||
}
|
||||
|
||||
/**
|
||||
|
14
lib/index.js
14
lib/index.js
@ -33,14 +33,8 @@ import Raw from './serializers/raw'
|
||||
* Utils.
|
||||
*/
|
||||
|
||||
import Key from './utils/key'
|
||||
import findDOMNode from './utils/find-dom-node'
|
||||
|
||||
const Utils = {
|
||||
Key,
|
||||
findDOMNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
@ -60,8 +54,8 @@ export {
|
||||
Selection,
|
||||
State,
|
||||
Text,
|
||||
Utils,
|
||||
Void
|
||||
Void,
|
||||
findDOMNode
|
||||
}
|
||||
|
||||
export default {
|
||||
@ -79,6 +73,6 @@ export default {
|
||||
Selection,
|
||||
State,
|
||||
Text,
|
||||
Utils,
|
||||
Void
|
||||
Void,
|
||||
findDOMNode
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
import Base64 from '../serializers/base-64'
|
||||
import Character from '../models/character'
|
||||
import Key from '../utils/key'
|
||||
import Placeholder from '../components/placeholder'
|
||||
import React from 'react'
|
||||
import String from '../utils/string'
|
||||
@ -314,17 +313,18 @@ function Plugin(options = {}) {
|
||||
* On key down.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
function onKeyDown(e, state) {
|
||||
switch (keycode(e.which)) {
|
||||
case 'enter': return onKeyDownEnter(e, state)
|
||||
case 'backspace': return onKeyDownBackspace(e, state)
|
||||
case 'delete': return onKeyDownDelete(e, state)
|
||||
case 'y': return onKeyDownY(e, state)
|
||||
case 'z': return onKeyDownZ(e, state)
|
||||
function onKeyDown(e, data, state) {
|
||||
switch (data.key) {
|
||||
case 'enter': return onKeyDownEnter(e, data, state)
|
||||
case 'backspace': return onKeyDownBackspace(e, data, state)
|
||||
case 'delete': return onKeyDownDelete(e, data, state)
|
||||
case 'y': return onKeyDownY(e, data, state)
|
||||
case 'z': return onKeyDownZ(e, data, state)
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,11 +332,12 @@ function Plugin(options = {}) {
|
||||
* On `enter` key down, split the current block in half.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
function onKeyDownEnter(e, state) {
|
||||
function onKeyDownEnter(e, data, state) {
|
||||
const { document, startKey, startBlock } = state
|
||||
|
||||
// For void blocks, we don't want to split. Instead we just move to the
|
||||
@ -360,11 +361,12 @@ function Plugin(options = {}) {
|
||||
* On `backspace` key down, delete backwards.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
function onKeyDownBackspace(e, state) {
|
||||
function onKeyDownBackspace(e, data, state) {
|
||||
// If expanded, delete regularly.
|
||||
if (state.isExpanded) {
|
||||
return state
|
||||
@ -378,11 +380,15 @@ function Plugin(options = {}) {
|
||||
let n
|
||||
|
||||
// Determine how far backwards to delete.
|
||||
if (Key.isWord(e)) {
|
||||
if (data.isWord) {
|
||||
n = String.getWordOffsetBackward(text, startOffset)
|
||||
} else if (Key.isLine(e)) {
|
||||
}
|
||||
|
||||
else if (data.isLine) {
|
||||
n = startOffset
|
||||
} else {
|
||||
}
|
||||
|
||||
else {
|
||||
n = String.getCharOffsetBackward(text, startOffset)
|
||||
}
|
||||
|
||||
@ -396,11 +402,12 @@ function Plugin(options = {}) {
|
||||
* On `delete` key down, delete forwards.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
function onKeyDownDelete(e, state) {
|
||||
function onKeyDownDelete(e, data, state) {
|
||||
// If expanded, delete regularly.
|
||||
if (state.isExpanded) {
|
||||
return state
|
||||
@ -414,11 +421,15 @@ function Plugin(options = {}) {
|
||||
let n
|
||||
|
||||
// Determine how far forwards to delete.
|
||||
if (Key.isWord(e)) {
|
||||
if (data.isWord) {
|
||||
n = String.getWordOffsetForward(text, startOffset)
|
||||
} else if (Key.isLine(e)) {
|
||||
}
|
||||
|
||||
else if (data.isLine) {
|
||||
n = text.length - startOffset
|
||||
} else {
|
||||
}
|
||||
|
||||
else {
|
||||
n = String.getCharOffsetForward(text, startOffset)
|
||||
}
|
||||
|
||||
@ -432,12 +443,13 @@ function Plugin(options = {}) {
|
||||
* On `y` key down, redo.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
function onKeyDownY(e, state) {
|
||||
if (!Key.isWindowsCommand(e)) return
|
||||
function onKeyDownY(e, data, state) {
|
||||
if (!data.isMod) return
|
||||
return state
|
||||
.transform()
|
||||
.redo()
|
||||
@ -447,15 +459,16 @@ function Plugin(options = {}) {
|
||||
* On `z` key down, undo or redo.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @param {Object} data
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
function onKeyDownZ(e, state) {
|
||||
if (!Key.isCommand(e)) return
|
||||
function onKeyDownZ(e, data, state) {
|
||||
if (!data.isMod) return
|
||||
return state
|
||||
.transform()
|
||||
[IS_MAC && Key.isShift(e) ? 'redo' : 'undo']()
|
||||
[data.isShift ? 'redo' : 'undo']()
|
||||
}
|
||||
|
||||
/**
|
||||
|
123
lib/utils/key.js
123
lib/utils/key.js
@ -1,123 +0,0 @@
|
||||
|
||||
import { IS_MAC, IS_WINDOWS } from './environment'
|
||||
|
||||
/**
|
||||
* Does an `e` have the alt modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isAlt(e) {
|
||||
return e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isCommand(e) {
|
||||
return IS_MAC
|
||||
? e.metaKey && !e.altKey
|
||||
: e.ctrlKey && !e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the control modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isCtrl(e) {
|
||||
return e.ctrlKey && !e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the line-level modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isLine(e) {
|
||||
return IS_MAC
|
||||
? e.metaKey
|
||||
: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the Mac command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isMacCommand(e) {
|
||||
return IS_MAC && isCommand(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the option modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isOption(e) {
|
||||
return IS_MAC && e.altKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the shift modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isShift(e) {
|
||||
return e.shiftKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the Windows command modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isWindowsCommand(e) {
|
||||
return IS_WINDOWS && isCommand(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an `e` have the word-level modifier?
|
||||
*
|
||||
* @param {Event} e
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function isWord(e) {
|
||||
return IS_MAC
|
||||
? e.altKey
|
||||
: e.ctrlKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default {
|
||||
isAlt,
|
||||
isCommand,
|
||||
isCtrl,
|
||||
isLine,
|
||||
isMacCommand,
|
||||
isOption,
|
||||
isShift,
|
||||
isWindowsCommand,
|
||||
isWord
|
||||
}
|
@ -58,7 +58,7 @@
|
||||
"watchify": "^3.7.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf ./dist ./node_modules",
|
||||
"clean": "rm -rf ./dist ./node_modules ./examples/build.js",
|
||||
"disc": "npm run dist && npm run disc:build && npm run disc:open",
|
||||
"disc:build": "mkdir -p ./tmp && browserify ./dist/index.js --full-paths --outfile ./tmp/build.js",
|
||||
"disc:open": "discify ./tmp/build.js --open",
|
||||
|
Loading…
x
Reference in New Issue
Block a user