This commit is contained in:
Mu-An ✌️ Chiou 2018-07-05 22:26:39 -04:00
Коммит 1501ab0a14
15 изменённых файлов: 8068 добавлений и 0 удалений

16
.babelrc Normal file
Просмотреть файл

@ -0,0 +1,16 @@
{
"env": {
"esm": {
"presets": [
["es2015", {"modules": false}],
"flow"
]
},
"umd": {
"plugins": [
"transform-es2015-modules-umd"
],
"presets": ["es2015", "flow"]
}
}
}

8
.eslintrc.json Normal file
Просмотреть файл

@ -0,0 +1,8 @@
{
"extends": [
"plugin:github/es6",
"plugin:github/browser",
"plugin:github/flow"
],
"parser": "babel-eslint"
}

9
.flowconfig Normal file
Просмотреть файл

@ -0,0 +1,9 @@
[ignore]
[include]
[libs]
[options]
[lints]

2
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,2 @@
dist
node_modules

9
.travis.yml Normal file
Просмотреть файл

@ -0,0 +1,9 @@
language: node_js
sudo: required
node_js:
- "node"
addons:
chrome: stable
cache:
directories:
- node_modules

20
LICENSE Normal file
Просмотреть файл

@ -0,0 +1,20 @@
Copyright (c) 2018 GitHub, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

52
README.md Normal file
Просмотреть файл

@ -0,0 +1,52 @@
# `quoteSelection`
Add selected text to a text area as a markdown quote.
## Installation
```
$ npm install @github/quote-selection
```
## Usage
```js
import quoteSelection from '@github/quote-selection'
quoteSelection(quotableContainer, textarea)
```
---
### HTML
```html
<div class="js-quote-selection"><p>Text to quote</p></div>
<textarea class="js-textarea"></textarea>
```
### JS
```js
import quoteSelection from '@github/quote-selection'
document.addEventListener('keydown', function(event) {
if (event.key === 'r' && !event.metaKey && !event.ctrlKey && !event.altKey) {
const quoted = quoteSelection(
document.querySelector('.js-quote-selection'),
document.querySelector('.js-textarea')
)
if (quoted) event.preventDefault()
}
})
```
## Development
```
npm install
npm test
```
## License
Distributed under the MIT license. See LICENSE for details.

32
examples/index.html Normal file
Просмотреть файл

@ -0,0 +1,32 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>quote-selection demo</title>
</head>
<body>
<p>Select and press <kbd>r</kbd> to quote. Selecting this line does not quote.<p>
<hr>
<div class="js-quote-selection">
<h4>Blame</h4>
<p>The "blame" feature in Git describes the last modification to each line of a file, which generally displays the revision, author and time. This is helpful, for example, in tracking down when a feature was added, or which commit led to a particular bug.</p>
<h4>Branch</h4>
<p>A branch is a parallel version of a repository. It is contained within the repository, but does not affect the primary or <code>master</code> branch allowing you to work freely without disrupting the "live" version. When you've made the changes you want to make, you can merge your branch back into the <code>master</code> branch to publish your changes.</p>
<textarea class="js-textarea" cols="50" rows="10"></textarea>
</div>
<script type="module">
import quoteSelection from '../dist/quote-selection.esm.js'
document.addEventListener('keydown', function(event) {
if (event.key === 'r' && !event.metaKey && !event.ctrlKey && !event.altKey) {
const quoted = quoteSelection(
document.querySelector('.js-quote-selection'),
document.querySelector('.js-textarea')
)
if (quoted) event.preventDefault()
}
})
</script>
</body>
</html>

7750
package-lock.json сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

38
package.json Normal file
Просмотреть файл

@ -0,0 +1,38 @@
{
"name": "@github/quote-selection",
"description": "Add selected text to a text area as a markdown quote.",
"version": "0.0.1",
"main": "dist/quote-selection.umd.js",
"module": "dist/quote-selection.esm.js",
"license": "MIT",
"repository": "github/quote-selection",
"files": [
"dist"
],
"scripts": {
"clean": "rm -rf dist",
"lint": "eslint quote-selection.js test/ && flow check",
"prebuild": "npm run clean && npm run lint && mkdir dist",
"build-umd": "BABEL_ENV=umd babel quote-selection.js -o dist/quote-selection.umd.js",
"build-esm": "BABEL_ENV=esm babel quote-selection.js -o dist/quote-selection.esm.js",
"build": "npm run build-umd && npm run build-esm",
"pretest": "npm run build",
"test": "karma start test/karma.config.js",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-flow": "^6.23.0",
"chai": "^4.1.2",
"eslint": "^5.0.1",
"eslint-plugin-github": "1.0.0",
"flow-bin": "^0.75.0",
"karma": "^2.0.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"mocha": "^5.0.5"
}
}

1
prettier.config.js Normal file
Просмотреть файл

@ -0,0 +1 @@
module.exports = require('eslint-plugin-github/prettier.config')

38
quote-selection.js Normal file
Просмотреть файл

@ -0,0 +1,38 @@
/* @flow */
export default function quoteSelection(container: HTMLElement, field: HTMLTextAreaElement): boolean {
const selection = window.getSelection()
let selectionText = selection.toString().trim()
if (!selectionText) return false
let focusNode = selection.focusNode
if (!focusNode) return false
if (focusNode.nodeType !== Node.ELEMENT_NODE) focusNode = focusNode.parentNode
if (!(focusNode instanceof Element)) return false
if (!container.contains(focusNode)) return false
const eventDetail = {selection, selectionText}
const fireEvent = container.dispatchEvent(
new CustomEvent('quote-selection', {
bubble: true,
detail: eventDetail
})
)
if (!fireEvent) return true
selectionText = eventDetail.selectionText
let quotedText = `> ${selectionText.replace(/\n/g, '\n> ')}\n\n`
if (field.value) {
quotedText = `${field.value}\n\n${quotedText}`
}
field.value = quotedText
field.focus()
field.selectionStart = field.value.length
field.scrollTop = field.scrollHeight
return true
}

12
test/.eslintrc.json Normal file
Просмотреть файл

@ -0,0 +1,12 @@
{
"rules": {
"flowtype/require-valid-file-annotation": "off"
},
"env": {
"mocha": true
},
"globals": {
"assert": true
},
"extends": "../.eslintrc.json"
}

14
test/karma.config.js Normal file
Просмотреть файл

@ -0,0 +1,14 @@
module.exports = function(config) {
config.set({
frameworks: ['mocha', 'chai'],
files: ['../dist/quote-selection.umd.js', 'test.js'],
reporters: ['mocha'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
browsers: ['ChromeHeadless'],
autoWatch: false,
singleRun: true,
concurrency: Infinity
})
}

67
test/test.js Normal file
Просмотреть файл

@ -0,0 +1,67 @@
/* global quoteSelection */
describe('quote-selection', function() {
describe('with quotable selection', function() {
beforeEach(function() {
document.body.innerHTML = `
<p id="not-quotable">Not quotable text</p>
<p id="quotable">Quotable text</p>
<textarea>Has text</textarea>
`
const el = document.querySelector('#quotable')
window.getSelection = function() {
return {
focusNode: el,
toString: () => el.textContent
}
}
})
afterEach(function() {
document.body.innerHTML = ''
})
it('textarea is updated', function(done) {
const container = document.querySelector('#quotable')
const textarea = document.querySelector('textarea')
container.addEventListener('quote-selection', function() {
done()
})
const quoted = quoteSelection.default(container, textarea)
assert(quoted)
assert.equal(textarea.value, 'Has text\n\n> Quotable text\n\n')
})
})
describe('with non-quotable selection', function() {
beforeEach(function() {
document.body.innerHTML = `
<p id="not-quotable">Not quotable text</p>
<p id="quotable">Quotable text</p>
<textarea>Has text</textarea>
`
const el = document.querySelector('#not-quotable')
window.getSelection = function() {
return {
focusNode: el,
toString: () => el.textContent
}
}
})
afterEach(function() {
document.body.innerHTML = ''
})
it('textarea is not updated', function() {
const container = document.querySelector('#quotable')
const textarea = document.querySelector('textarea')
const quoted = quoteSelection.default(container, textarea)
assert(!quoted)
assert.equal(textarea.value, 'Has text')
})
})
})