mirror of
https://github.com/fregante/GhostText.git
synced 2024-10-05 23:47:43 +03:00
Meta: Prettier and cleanup (#182)
This commit is contained in:
parent
261c838a82
commit
d8703b5d5c
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = tab
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.yml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
11
.github/ISSUE_TEMPLATE.md
vendored
11
.github/ISSUE_TEMPLATE.md
vendored
@ -2,19 +2,16 @@
|
|||||||
|
|
||||||
Thanks for trying out GhostText and opening this issue!
|
Thanks for trying out GhostText and opening this issue!
|
||||||
|
|
||||||
Before opening an issue for a possible bug,
|
Before opening an issue for a possible bug, please make sure you try GhostText in Chrome and Sublime Text.
|
||||||
please make sure you try GhostText in Chrome and Sublime Text.
|
This is the most common configuration and will help me understand better where the problem is.
|
||||||
This is the most common configuration and will help me
|
|
||||||
understand better where the problem is.
|
|
||||||
|
|
||||||
If it works with Sublime Text but not with a third party editor,
|
If it works with Sublime Text but not with a third party editor, please open an issue in their repository.
|
||||||
please open an issue in their repository.
|
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
|
|
||||||
Browser:
|
Browser:
|
||||||
Editor:
|
Editor:
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
19
.github/workflows/labeler.yml
vendored
Normal file
19
.github/workflows/labeler.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
env: {}
|
||||||
|
|
||||||
|
# DO NOT EDIT BELOW, USE: npx ghat fregante/title-to-labels-action/workflow
|
||||||
|
|
||||||
|
name: Labeler
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, edited]
|
||||||
|
issues:
|
||||||
|
types: [opened, edited]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Label:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: fregante/title-to-labels-action@v1
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
47
.gitignore
vendored
47
.gitignore
vendored
@ -1,44 +1,5 @@
|
|||||||
*.py[cod]
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Packages
|
|
||||||
*.egg
|
|
||||||
*.egg-info
|
|
||||||
dist
|
|
||||||
build
|
|
||||||
eggs
|
|
||||||
parts
|
|
||||||
bin
|
|
||||||
var
|
|
||||||
sdist
|
|
||||||
develop-eggs
|
|
||||||
.installed.cfg
|
|
||||||
lib
|
|
||||||
lib64
|
|
||||||
__pycache__
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
.coverage
|
|
||||||
.tox
|
|
||||||
nosetests.xml
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
|
|
||||||
# Mr Developer
|
|
||||||
.mr.developer.cfg
|
|
||||||
.project
|
|
||||||
.pydevproject
|
|
||||||
|
|
||||||
.idea
|
|
||||||
.xpi
|
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
|
yarn.lock
|
||||||
ChromeExtension.pem
|
distribution
|
||||||
browser/scripts/input-area.js
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
64
PROTOCOL.md
64
PROTOCOL.md
@ -23,9 +23,9 @@ The Server responds with a `200` and a content type of `application/json`.
|
|||||||
|
|
||||||
The JSON payload is an object with the following properties:
|
The JSON payload is an object with the following properties:
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
|-------------------|--------|-------------|
|
| ----------------- | ------ | ------------------------------------ |
|
||||||
| `ProtocolVersion` | Number | The protocol version |
|
| `ProtocolVersion` | Number | The protocol version |
|
||||||
| `WebSocketPort` | Number | The port for the listening WebSocket |
|
| `WebSocketPort` | Number | The port for the listening WebSocket |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
@ -53,37 +53,37 @@ Each time the user makes a change in the browser (or on first WebSocket
|
|||||||
connect) the Client sends via the WebSocket a JSON object message with the
|
connect) the Client sends via the WebSocket a JSON object message with the
|
||||||
following properties:
|
following properties:
|
||||||
|
|
||||||
| Property | Value | Description |
|
| Property | Value | Description |
|
||||||
|--------------|------------------------|-------------|
|
| ------------ | ---------------------- | ---------------------------------------------------------------------------------------------- |
|
||||||
| `title` | String | The title of the document |
|
| `title` | String | The title of the document |
|
||||||
| `url` | String | The URL of the document |
|
| `url` | String | The URL of the document |
|
||||||
| `syntax` | String | *Not used* |
|
| `syntax` | String | _Not used_ |
|
||||||
| `text` | String | The value of the textarea/content |
|
| `text` | String | The value of the textarea/content |
|
||||||
| `selections` | Array(SelectionObject) | An array of selection objects that describe the user's current cursor selections in the editor |
|
| `selections` | Array(SelectionObject) | An array of selection objects that describe the user's current cursor selections in the editor |
|
||||||
|
|
||||||
#### Selection Object
|
#### Selection Object
|
||||||
|
|
||||||
Selection objects have the following properties:
|
Selection objects have the following properties:
|
||||||
|
|
||||||
| Property | Value | Description |
|
| Property | Value | Description |
|
||||||
|----------|--------|-------------|
|
| -------- | ------ | ------------------------------ |
|
||||||
| `start` | Number | 0-index start of the selection |
|
| `start` | Number | 0-index start of the selection |
|
||||||
| `end` | Number | 0-index end of the selection |
|
| `end` | Number | 0-index end of the selection |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"title": "Test Document",
|
"title": "Test Document",
|
||||||
"url": "http://example.com/test-document",
|
"url": "http://example.com/test-document",
|
||||||
"syntax": "",
|
"syntax": "",
|
||||||
"text": "Adipisicing excepturi voluptate nostrum quas veritatis?",
|
"text": "Adipisicing excepturi voluptate nostrum quas veritatis?",
|
||||||
"selections": [
|
"selections": [
|
||||||
{
|
{
|
||||||
"start": 10,
|
"start": 10,
|
||||||
"end": 20
|
"end": 20
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -92,22 +92,22 @@ Selection objects have the following properties:
|
|||||||
Each time the user makes a change in the editor the Server sends via the
|
Each time the user makes a change in the editor the Server sends via the
|
||||||
WebSocket a JSON object message with the following properties:
|
WebSocket a JSON object message with the following properties:
|
||||||
|
|
||||||
| Property | Value | Description |
|
| Property | Value | Description |
|
||||||
|--------------|------------------------|-------------|
|
| ------------ | ---------------------- | ---------------------------------------------------------------------------------------------- |
|
||||||
| `text` | String | The temporary file content |
|
| `text` | String | The temporary file content |
|
||||||
| `selections` | Array(SelectionObject) | An array of selection objects that describe the user's current cursor selections in the editor |
|
| `selections` | Array(SelectionObject) | An array of selection objects that describe the user's current cursor selections in the editor |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"text": "Adipisicing ea lorem expedita facere nesciunt",
|
"text": "Adipisicing ea lorem expedita facere nesciunt",
|
||||||
"selections": [
|
"selections": [
|
||||||
{
|
{
|
||||||
"start": 20,
|
"start": 20,
|
||||||
"end": 30
|
"end": 30
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
81
README.md
81
README.md
@ -1,5 +1,8 @@
|
|||||||
# <img src="https://raw.githubusercontent.com/GhostText/GhostText/master/promo/gt_banner.png" height="60" alt="GhostText">
|
# <img src="https://raw.githubusercontent.com/GhostText/GhostText/master/promo/gt_banner.png" height="60" alt="GhostText">
|
||||||
|
|
||||||
|
[link-cws]: https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca 'Version published on Chrome Web Store'
|
||||||
|
[link-amo]: https://addons.mozilla.org/en-US/firefox/addon/ghosttext/ 'Version published on Mozilla Add-ons'
|
||||||
|
|
||||||
<img src="promo/demo.gif" alt="Demo screencast" align="right">
|
<img src="promo/demo.gif" alt="Demo screencast" align="right">
|
||||||
|
|
||||||
Use your text editor to write in your browser. Everything you type in the editor will be instantly updated in the browser (and vice versa).
|
Use your text editor to write in your browser. Everything you type in the editor will be instantly updated in the browser (and vice versa).
|
||||||
@ -9,31 +12,33 @@ Use your text editor to write in your browser. Everything you type in the editor
|
|||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Install your editor extension:
|
1. Install your editor extension:
|
||||||
+ [**Sublime Text** extension](https://sublime.wbond.net/packages/GhostText) - [Repo](https://github.com/GhostText/GhostText-for-SublimeText)
|
|
||||||
+ [**Atom** package](https://github.com/GhostText/GhostText-for-Atom)
|
- [**Sublime Text**](https://sublime.wbond.net/packages/GhostText) ([Repo](https://github.com/GhostText/GhostText-for-SublimeText))
|
||||||
+ [**VS Code** extension](https://marketplace.visualstudio.com/items?itemName=tokoph.ghosttext) - [Repo](https://github.com/jtokoph/ghosttext-vscode) (Third party)
|
- [**Atom**](https://github.com/GhostText/GhostText-for-Atom)
|
||||||
+ [**Emacs** package](https://melpa.org/#/atomic-chrome) - [Repo](https://github.com/alpha22jp/atomic-chrome) (Third party)
|
- [**VS Code**](https://marketplace.visualstudio.com/items?itemName=tokoph.ghosttext) ([Repo](https://github.com/jtokoph/ghosttext-vscode)) (Third party)
|
||||||
+ [**Acme** client](https://github.com/fhs/Ghost) (Third party)
|
- [**Emacs**](https://melpa.org/#/atomic-chrome) ([Repo](https://github.com/alpha22jp/atomic-chrome)) (Third party)
|
||||||
+ <details>
|
- [**Acme**](https://github.com/fhs/Ghost) (Third party)
|
||||||
<summary><b>Vim</b>/<b>Neovim</b> (Third party)</summary>
|
- <details>
|
||||||
<ul>
|
<summary><b>Vim</b>/<b>Neovim</b> (Third party)</summary>
|
||||||
<li><a href="https://github.com/raghur/vim-ghost"><b>Vim</b> (<tt>+python3</tt>) & <b>Neovim</b> (<tt>pynvim</tt>)</a>
|
<ul>
|
||||||
<li><a href="https://github.com/falstro/ghost-text-vim"><b>Vim</b> (<tt>+tcl</tt>)</a>
|
<li><a href="https://github.com/raghur/vim-ghost"><b>Vim</b> (<tt>+python3</tt>) & <b>Neovim</b> (<tt>pynvim</tt>)</a>
|
||||||
<li><a href="https://github.com/pandysong/ghost-text.vim"><b>Vim</b> (<tt>+python3 +channel</tt>)</a>
|
<li><a href="https://github.com/falstro/ghost-text-vim"><b>Vim</b> (<tt>+tcl</tt>)</a>
|
||||||
<li><a href="https://github.com/subnut/nvim-ghost.nvim"><b>Neovim</b></a>
|
<li><a href="https://github.com/pandysong/ghost-text.vim"><b>Vim</b> (<tt>+python3 +channel</tt>)</a>
|
||||||
</ul>
|
<li><a href="https://github.com/subnut/nvim-ghost.nvim"><b>Neovim</b></a>
|
||||||
</details>
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
2. Install your browser extension:
|
2. Install your browser extension:
|
||||||
+ [**Chrome** extension](https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca)
|
|
||||||
+ [**Firefox** add-on](https://addons.mozilla.org/en-US/firefox/addon/ghosttext/)
|
- [**Chrome**][link-cws] [<img valign="middle" src="https://img.shields.io/chrome-web-store/v/godiecgffnchndlihlpaajjcplehddca.svg?label=%20">][link-cws]
|
||||||
+ Opera - Use [this](https://addons.opera.com/en/extensions/details/download-chrome-extension-9/) to install the Chrome extension.
|
- [**Firefox**][link-amo] [<img valign="middle" src="https://img.shields.io/amo/v/ghosttext.svg?label=%20">][link-amo]
|
||||||
|
|
||||||
## Website support
|
## Website support
|
||||||
|
|
||||||
* `<textarea>` elements
|
- `<textarea>` elements
|
||||||
* [`contentEditable`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable) areas: like in Gmail
|
- [`contentEditable`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable) areas: like in Gmail
|
||||||
* [CodeMirror](http://codemirror.net/) editors: used on CodePen, JSFiddle, JS Bin, …
|
- [CodeMirror](http://codemirror.net/) editors: used on CodePen, JSFiddle, JS Bin, …
|
||||||
* [Ace](http://ace.c9.io/) editor: used on Tumblr, …
|
- [Ace](http://ace.c9.io/) editor: used on Tumblr, …
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@ -51,24 +56,24 @@ or
|
|||||||
[like this in Firefox](https://support.mozilla.org/en-US/kb/manage-extension-shortcuts-firefox).
|
[like this in Firefox](https://support.mozilla.org/en-US/kb/manage-extension-shortcuts-firefox).
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>OS</th>
|
<th>OS</th>
|
||||||
<th>Shortcut</th>
|
<th>Shortcut</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Windows</td>
|
<td>Windows</td>
|
||||||
<td><kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>K</kbd></td>
|
<td><kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>K</kbd></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Linux</td>
|
<td>Linux</td>
|
||||||
<td><kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>H</kbd></td>
|
<td><kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>H</kbd></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Mac</td>
|
<td>Mac</td>
|
||||||
<td><kbd>cmd</kbd> + <kbd>shift</kbd> + <kbd>K</kbd></td>
|
<td><kbd>cmd</kbd> + <kbd>shift</kbd> + <kbd>K</kbd></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT © [Federico Brigante](http://twitter.com/bfred_it), Guido Krömer
|
MIT © [Federico Brigante](https://fregante.com)
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
# <img src="https://raw.githubusercontent.com/GhostText/GhostText/master/promo/gt_banner.png" height="60" alt="GhostText">
|
# <img src="https://raw.githubusercontent.com/GhostText/GhostText/master/promo/gt_banner.png" height="60" alt="GhostText">
|
||||||
|
|
||||||
[![Chrome version][badge-cws]][link-cws] [![Firefox version][badge-amo]][link-amo] [![Autodeployment][badge-travis]][link-travis]
|
[![Chrome version][badge-cws]][link-cws] [![Firefox version][badge-amo]][link-amo]
|
||||||
|
|
||||||
[badge-cws]: https://img.shields.io/chrome-web-store/v/godiecgffnchndlihlpaajjcplehddca.svg?label=for%20chrome
|
[badge-cws]: https://img.shields.io/chrome-web-store/v/godiecgffnchndlihlpaajjcplehddca.svg?label=for%20chrome
|
||||||
[badge-amo]: https://img.shields.io/amo/v/ghosttext.svg?label=for%20firefox
|
[badge-amo]: https://img.shields.io/amo/v/ghosttext.svg?label=for%20firefox
|
||||||
[badge-travis]: https://img.shields.io/travis/GhostText/GhostText/master.svg?label=autodeployment
|
[link-cws]: https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca 'Version published on Chrome Web Store'
|
||||||
[link-cws]: https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca "Version published on Chrome Web Store"
|
[link-amo]: https://addons.mozilla.org/en-US/firefox/addon/ghosttext/ 'Version published on Mozilla Add-ons'
|
||||||
[link-amo]: https://addons.mozilla.org/en-US/firefox/addon/ghosttext/ "Version published on Mozilla Add-ons"
|
|
||||||
[link-travis]: https://travis-ci.org/GhostText/GhostText
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
},
|
},
|
||||||
"browser_action": {
|
"browser_action": {
|
||||||
"default_title": "GhostText",
|
"default_title": "GhostText",
|
||||||
"default_icon": {
|
"default_icon": {
|
||||||
"19": "images/icon_19.png",
|
"19": "images/icon_19.png",
|
||||||
"38": "images/icon_48.png"
|
"38": "images/icon_48.png"
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>GhostText options</title>
|
<title>GhostText options</title>
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
label, button, footer {
|
label,
|
||||||
|
button,
|
||||||
|
footer {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
@ -15,7 +17,7 @@
|
|||||||
footer {
|
footer {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: gray
|
color: gray;
|
||||||
}
|
}
|
||||||
footer a {
|
footer a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -24,11 +26,21 @@
|
|||||||
<form id="options-form">
|
<form id="options-form">
|
||||||
<label>
|
<label>
|
||||||
Server Port
|
Server Port
|
||||||
<input name="serverPort" type="number" min="1" max="65536" step="1" placeholder="4001" value="4001" required>
|
<input
|
||||||
|
name="serverPort"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="65536"
|
||||||
|
step="1"
|
||||||
|
placeholder="4001"
|
||||||
|
value="4001"
|
||||||
|
required
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
</form>
|
</form>
|
||||||
<footer>
|
<footer>
|
||||||
Issues? Let’s fix them on <a href="https://github.com/GhostText/GhostText">GhostText’s GitHub repo</a>!
|
Issues? Let’s fix them on
|
||||||
</div>
|
<a href="https://github.com/GhostText/GhostText">GhostText’s GitHub repo</a>!
|
||||||
|
</footer>
|
||||||
<script src="vendor/webext-options-sync.js"></script>
|
<script src="vendor/webext-options-sync.js"></script>
|
||||||
<script src="scripts/options.js"></script>
|
<script src="scripts/options.js"></script>
|
||||||
|
@ -16,7 +16,10 @@ async function handleAction({id}) {
|
|||||||
runAt: 'document_start',
|
runAt: 'document_start',
|
||||||
allFrames: true
|
allFrames: true
|
||||||
};
|
};
|
||||||
const [alreadyInjected] = await browser.tabs.executeScript(id, {...defaults, code: 'typeof window.startGT === "function"'});
|
const [alreadyInjected] = await browser.tabs.executeScript(id, {
|
||||||
|
...defaults,
|
||||||
|
code: 'typeof window.startGT === "function"'
|
||||||
|
});
|
||||||
console.log(alreadyInjected);
|
console.log(alreadyInjected);
|
||||||
if (alreadyInjected) {
|
if (alreadyInjected) {
|
||||||
return browser.tabs.executeScript(id, {...defaults, code: 'startGT()'});
|
return browser.tabs.executeScript(id, {...defaults, code: 'startGT()'});
|
||||||
@ -75,9 +78,9 @@ chrome.runtime.onConnect.addListener(handlePortListenerErrors(async port => {
|
|||||||
socket.addEventListener('message', event => port.postMessage({message: event.data}));
|
socket.addEventListener('message', event => port.postMessage({message: event.data}));
|
||||||
socket.addEventListener('error', event => console.error('error!', event));
|
socket.addEventListener('error', event => console.error('error!', event));
|
||||||
|
|
||||||
port.onMessage.addListener(msg => {
|
port.onMessage.addListener(message => {
|
||||||
console.log('got message from script', msg);
|
console.log('got message from script', message);
|
||||||
socket.send(msg);
|
socket.send(message);
|
||||||
});
|
});
|
||||||
console.log(port);
|
console.log(port);
|
||||||
port.onDisconnect.addListener(() => {
|
port.onDisconnect.addListener(() => {
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
transition: box-shadow 1s cubic-bezier(0.25, 2, 0.5, 1);
|
transition: box-shadow 1s cubic-bezier(0.25, 2, 0.5, 1);
|
||||||
}
|
}
|
||||||
.GT--waiting [data-gt-field] {
|
.GT--waiting [data-gt-field] {
|
||||||
box-shadow: #00F25A 0 0 20px inset;
|
box-shadow: #00f25a 0 0 20px inset;
|
||||||
}
|
}
|
||||||
[data-gt-field="loading"] {
|
[data-gt-field='loading'] {
|
||||||
box-shadow: #FFB600 0 0 20px 5px inset;
|
box-shadow: #ffb600 0 0 20px 5px inset;
|
||||||
}
|
}
|
||||||
[data-gt-field="enabled"] {
|
[data-gt-field='enabled'] {
|
||||||
box-shadow: #00ACEE 0 0 20px 5px inset !important;
|
box-shadow: #00acee 0 0 20px 5px inset !important;
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ const activeFields = new Set();
|
|||||||
let isWaitingForActivation = false;
|
let isWaitingForActivation = false;
|
||||||
|
|
||||||
class ContentEditableWrapper {
|
class ContentEditableWrapper {
|
||||||
constructor(el) {
|
constructor(element) {
|
||||||
this.el = el;
|
this.el = element;
|
||||||
this.dataset = el.dataset;
|
this.dataset = element.dataset;
|
||||||
this.addEventListener = el.addEventListener.bind(el);
|
this.addEventListener = element.addEventListener.bind(element);
|
||||||
this.removeEventListener = el.removeEventListener.bind(el);
|
this.removeEventListener = element.removeEventListener.bind(element);
|
||||||
this.blur = el.blur.bind(el);
|
this.blur = element.blur.bind(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
get value() {
|
get value() {
|
||||||
@ -24,15 +24,17 @@ class ContentEditableWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AdvancedTextWrapper {
|
class AdvancedTextWrapper {
|
||||||
constructor(el, visualEl) {
|
constructor(element, visualElement) {
|
||||||
this.el = el;
|
this.el = element;
|
||||||
this.dataset = visualEl.dataset;
|
this.dataset = visualElement.dataset;
|
||||||
this.el.addEventListener('gt:input', event => {
|
this.el.addEventListener('gt:input', event => {
|
||||||
this._value = event.detail.value;
|
this._value = event.detail.value;
|
||||||
});
|
});
|
||||||
this.el.dispatchEvent(new CustomEvent('gt:get', {
|
this.el.dispatchEvent(
|
||||||
bubbles: true
|
new CustomEvent('gt:get', {
|
||||||
}));
|
bubbles: true
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
blur() {
|
blur() {
|
||||||
@ -63,14 +65,14 @@ class AdvancedTextWrapper {
|
|||||||
function wrapField(field) {
|
function wrapField(field) {
|
||||||
if (field.classList.contains('ace_text-input')) {
|
if (field.classList.contains('ace_text-input')) {
|
||||||
const ace = field.parentNode;
|
const ace = field.parentNode;
|
||||||
const visualEl = ace.querySelector('.ace_scroller');
|
const visualElement = ace.querySelector('.ace_scroller');
|
||||||
return new AdvancedTextWrapper(ace, visualEl);
|
return new AdvancedTextWrapper(ace, visualElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cm = field.closest('.CodeMirror');
|
const cm = field.closest('.CodeMirror');
|
||||||
if (cm) {
|
if (cm) {
|
||||||
const visualEl = cm.querySelector('.CodeMirror-sizer');
|
const visualElement = cm.querySelector('.CodeMirror-sizer');
|
||||||
return new AdvancedTextWrapper(cm, visualEl);
|
return new AdvancedTextWrapper(cm, visualElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.isContentEditable) {
|
if (field.isContentEditable) {
|
||||||
@ -103,13 +105,13 @@ class GhostTextField {
|
|||||||
this.field.dataset.gtField = 'loading';
|
this.field.dataset.gtField = 'loading';
|
||||||
|
|
||||||
this.port = chrome.runtime.connect({name: 'new-field'});
|
this.port = chrome.runtime.connect({name: 'new-field'});
|
||||||
this.port.onMessage.addListener(msg => {
|
this.port.onMessage.addListener(message => {
|
||||||
if (msg.message) {
|
if (message.message) {
|
||||||
this.receive({data: msg.message});
|
this.receive({data: message.message});
|
||||||
} else if (msg.close) {
|
} else if (message.close) {
|
||||||
this.deactivate(false);
|
this.deactivate(false);
|
||||||
updateCount();
|
updateCount();
|
||||||
} else if (msg.ready) {
|
} else if (message.ready) {
|
||||||
notify('log', 'Connected! You can switch to your editor');
|
notify('log', 'Connected! You can switch to your editor');
|
||||||
|
|
||||||
this.field.addEventListener('input', this.send);
|
this.field.addEventListener('input', this.send);
|
||||||
@ -118,8 +120,8 @@ class GhostTextField {
|
|||||||
// Send first value to init tab
|
// Send first value to init tab
|
||||||
this.send();
|
this.send();
|
||||||
updateCount();
|
updateCount();
|
||||||
} else if (msg.error) {
|
} else if (message.error) {
|
||||||
notify('warn', msg.error);
|
notify('warn', message.error);
|
||||||
this.deactivate(false);
|
this.deactivate(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -131,25 +133,25 @@ class GhostTextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.info('sending', this.field.value.length, 'characters');
|
console.info('sending', this.field.value.length, 'characters');
|
||||||
this.port.postMessage(JSON.stringify({
|
this.port.postMessage(
|
||||||
title: document.title, // TODO: move to first fetch
|
JSON.stringify({
|
||||||
url: location.host, // TODO: move to first fetch
|
title: document.title, // TODO: move to first fetch
|
||||||
syntax: '', // TODO: move to first fetch
|
url: location.host, // TODO: move to first fetch
|
||||||
text: this.field.value,
|
syntax: '', // TODO: move to first fetch
|
||||||
selections: [
|
text: this.field.value,
|
||||||
{
|
selections: [
|
||||||
start: this.field.selectionStart || 0,
|
{
|
||||||
end: this.field.selectionEnd || 0
|
start: this.field.selectionStart || 0,
|
||||||
}
|
end: this.field.selectionEnd || 0
|
||||||
]
|
}
|
||||||
}));
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
receive(event) {
|
receive(event) {
|
||||||
const {
|
const {text, selections} = JSON.parse(event.data);
|
||||||
text,
|
|
||||||
selections
|
|
||||||
} = JSON.parse(event.data);
|
|
||||||
if (this.field.value !== text) {
|
if (this.field.value !== text) {
|
||||||
this.field.value = text;
|
this.field.value = text;
|
||||||
|
|
||||||
|
@ -15,9 +15,7 @@ window.unsafeMessenger = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendBack(target, value) {
|
function sendBack(target, value) {
|
||||||
target.dispatchEvent(
|
target.dispatchEvent(new CustomEvent('gt:input', {detail: {value}}));
|
||||||
new CustomEvent('gt:input', {detail: {value}})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function throttle(interval, callback) {
|
function throttle(interval, callback) {
|
||||||
@ -37,11 +35,14 @@ window.unsafeMessenger = function () {
|
|||||||
|
|
||||||
sendBack(target, editor.getValue());
|
sendBack(target, editor.getValue());
|
||||||
|
|
||||||
editor.on('changes', throttle(50, (instance, [{origin}]) => {
|
editor.on(
|
||||||
if (origin !== 'setValue') {
|
'changes',
|
||||||
sendBack(target, editor.getValue());
|
throttle(50, (instance, [{origin}]) => {
|
||||||
}
|
if (origin !== 'setValue') {
|
||||||
}));
|
sendBack(target, editor.getValue());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
target.addEventListener('gt:transfer', () => {
|
target.addEventListener('gt:transfer', () => {
|
||||||
editor.setValue(target.getAttribute('gt-value'));
|
editor.setValue(target.getAttribute('gt-value'));
|
||||||
});
|
});
|
||||||
|
@ -1,45 +1,52 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>GhostText test page</title>
|
<title>GhostText test page</title>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.min.css">
|
<link
|
||||||
<style>
|
rel="stylesheet"
|
||||||
html {
|
href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.min.css"
|
||||||
font-family: sans-serif;
|
/>
|
||||||
max-width: 600px;
|
<style>
|
||||||
color: #333;
|
html {
|
||||||
margin: auto;
|
font-family: sans-serif;
|
||||||
}
|
max-width: 600px;
|
||||||
iframe,
|
color: #333;
|
||||||
textarea,
|
margin: auto;
|
||||||
[contenteditable],
|
}
|
||||||
#ace {
|
iframe,
|
||||||
border: solid 1px silver;
|
textarea,
|
||||||
border-radius: 3px;
|
[contenteditable],
|
||||||
min-height: 100px;
|
#ace {
|
||||||
width: 100%;
|
border: solid 1px silver;
|
||||||
}
|
border-radius: 3px;
|
||||||
.CodeMirror {
|
min-height: 100px;
|
||||||
height: 100px;
|
width: 100%;
|
||||||
}
|
}
|
||||||
textarea {
|
.CodeMirror {
|
||||||
font: inherit;
|
height: 100px;
|
||||||
}
|
}
|
||||||
.flex {
|
textarea {
|
||||||
display: flex;
|
font: inherit;
|
||||||
justify-content: space-between;
|
}
|
||||||
}
|
.flex {
|
||||||
textarea {
|
display: flex;
|
||||||
max-width: 49%;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
iframe {
|
textarea {
|
||||||
opacity: 0.8;
|
max-width: 49%;
|
||||||
height: 200px;
|
}
|
||||||
}
|
iframe {
|
||||||
</style>
|
opacity: 0.8;
|
||||||
</head>
|
height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
<h1>
|
<h1>
|
||||||
<img src="https://raw.githubusercontent.com/GhostText/GhostText/master/promo/gt_banner.png" height="60" alt="GhostText">
|
<img
|
||||||
|
src="https://raw.githubusercontent.com/GhostText/GhostText/master/promo/gt_banner.png"
|
||||||
|
height="60"
|
||||||
|
alt="GhostText"
|
||||||
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<h2><code><textarea></code></h2>
|
<h2><code><textarea></code></h2>
|
||||||
@ -74,10 +81,9 @@
|
|||||||
</pre>
|
</pre>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js"></script>
|
||||||
<script>
|
<script>
|
||||||
window.ace.edit('ace').setOption("maxLines", 30)
|
window.ace.edit('ace').setOption('maxLines', 30);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<h2>Fields inside <code><iframe></code></h2>
|
<h2>Fields inside <code><iframe></code></h2>
|
||||||
<iframe src="." frameborder="0">One level deep, please!</iframe>
|
<iframe src="." frameborder="0">One level deep, please!</iframe>
|
||||||
</html>
|
</html>
|
||||||
|
30240
package-lock.json
generated
30240
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
45
package.json
45
package.json
@ -1,25 +1,24 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"scripts": {
|
||||||
"xo": "^0.37.1"
|
"test": "xo"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"xo": {
|
||||||
"test": "xo"
|
"envs": [
|
||||||
},
|
"browser",
|
||||||
"xo": {
|
"webextensions"
|
||||||
"envs": [
|
],
|
||||||
"browser",
|
"globals": [
|
||||||
"webextensions"
|
"oneEvent"
|
||||||
],
|
],
|
||||||
"rules": {
|
"ignores": [
|
||||||
"unicorn/prevent-abbreviations": 0,
|
"browser/vendor/*"
|
||||||
"no-alert": 0
|
],
|
||||||
},
|
"rules": {
|
||||||
"globals": [
|
"no-alert": "off"
|
||||||
"oneEvent"
|
}
|
||||||
],
|
},
|
||||||
"ignores": [
|
"devDependencies": {
|
||||||
"browser/vendor/*"
|
"xo": "^0.37.1"
|
||||||
]
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user