Fixed local compose and text entryport.
This commit is contained in:
parent
52e5690ee5
commit
65f5ace561
35
Dockerfile
35
Dockerfile
|
@ -1,35 +1,34 @@
|
||||||
FROM node:22-alpine as builder
|
FROM node:22-alpine
|
||||||
|
|
||||||
# Install git and other dependencies
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
|
|
||||||
# Clone the repository
|
|
||||||
RUN git clone --depth 1 https://git.nixc.us/Nixius/hastebin.git /app
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Clean npm cache and install dependencies with better error handling
|
# Copy local files instead of git clone
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
# Create data directory for file storage
|
||||||
|
RUN mkdir -p /app/data
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
RUN npm cache clean --force && \
|
RUN npm cache clean --force && \
|
||||||
npm install --production --no-optional && \
|
npm install --production --no-optional && \
|
||||||
|
npm install mocha && \
|
||||||
chmod +x app.sh
|
chmod +x app.sh
|
||||||
|
|
||||||
# Build assets if needed
|
# Build assets if needed
|
||||||
RUN node update-js.js || echo "No update-js.js script found"
|
RUN node update-js.js || echo "No update-js.js script found"
|
||||||
|
|
||||||
FROM node:22-alpine
|
# Create a simple override config to force file storage
|
||||||
|
RUN echo "var config = require('./config.js'); config.storage = { type: 'file', path: '/app/data' }; module.exports = config;" > /app/config.override.js && \
|
||||||
WORKDIR /app
|
sed -i '1s/^/var config = require(".\/config.override.js"); /' server.js
|
||||||
|
|
||||||
# Copy from builder stage
|
|
||||||
COPY --from=builder /app .
|
|
||||||
|
|
||||||
# Install mocha in the final image
|
|
||||||
RUN npm install mocha
|
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV NODE_ENV=production \
|
ENV NODE_ENV=production \
|
||||||
|
HASTEBIN_STORAGE_TYPE=file \
|
||||||
|
STORAGE_TYPE=file \
|
||||||
|
STORAGE_PATH=/app/data \
|
||||||
|
STORAGE_HOST=localhost \
|
||||||
HASTEBIN_ENABLE_CSP=true \
|
HASTEBIN_ENABLE_CSP=true \
|
||||||
HASTEBIN_ENABLE_HSTS=true \
|
HASTEBIN_ENABLE_HSTS=false \
|
||||||
HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true
|
HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
|
|
325
README.md
325
README.md
|
@ -1,311 +1,56 @@
|
||||||
# Hastebin
|
# Flockitrack
|
||||||
|
|
||||||
Hastebin is an open-source pastebin software written in node.js, which is easily installable in any network. It can be backed by either redis or filesystem, and has a very easy adapter interface for other stores. A publicly available version can be found at [haste.nixc.us](http://haste.nixc.us)
|
Firefox extension for tracking time for tickets in YouTrack in Clockify.
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone the repository
|
|
||||||
git clone https://github.com/seejohnrun/haste-server.git
|
|
||||||
cd haste-server
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# Start with file storage (no Redis needed)
|
|
||||||
npm run start:dev
|
|
||||||
|
|
||||||
# Access in your browser
|
|
||||||
# http://localhost:7777
|
|
||||||
```
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Simple**: Easy to set up and use
|
- Track time directly from YouTrack tickets
|
||||||
- **Secure**: Includes CSP and other security headers
|
- Automatically fill in ticket information
|
||||||
- **Flexible**: Supports multiple storage backends (Redis, File, Postgres, etc.)
|
- Seamless integration with Clockify
|
||||||
- **Customizable**: Configurable via environment variables or config file
|
- Easy-to-use interface
|
||||||
- **Modern**: Self-destructing pastes with syntax highlighting
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Quick Install
|
### Development Installation
|
||||||
|
|
||||||
```bash
|
1. Clone this repository:
|
||||||
# Clone the repository
|
```
|
||||||
git clone https://github.com/seejohnrun/haste-server.git
|
git clone git@git.nixc.us:colin/flockitrack.git
|
||||||
cd haste-server
|
cd flockitrack
|
||||||
|
```
|
||||||
|
|
||||||
# Install dependencies
|
2. Open Firefox and navigate to `about:debugging`
|
||||||
npm install
|
3. Click "This Firefox"
|
||||||
|
4. Click "Load Temporary Add-on..."
|
||||||
|
5. Select the `manifest.json` file from the cloned repository
|
||||||
|
|
||||||
# Start with file storage (no Redis needed)
|
### Production Installation
|
||||||
npm run start:file
|
|
||||||
# OR run directly with environment variables
|
|
||||||
# NODE_ENV=development HASTEBIN_STORAGE_TYPE=file node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running Options
|
The extension will be available on the Firefox Add-ons store once it's published.
|
||||||
|
|
||||||
```bash
|
## Usage
|
||||||
# Start with default settings (requires Redis)
|
|
||||||
npm start
|
|
||||||
|
|
||||||
# Start in development mode with file storage
|
1. Click on the Flockitrack icon in your browser toolbar
|
||||||
npm run start:dev
|
2. Enter your Clockify API key (found in your Clockify user settings)
|
||||||
|
3. Navigate to a YouTrack ticket
|
||||||
|
4. Use the extension to start tracking time for the ticket
|
||||||
|
|
||||||
# Same as start:dev (for backward compatibility)
|
## Development
|
||||||
npm run start:file
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker Installation
|
This extension is a port of the original Chrome extension for Clockify + YouTrack integration, adapted to work with Firefox.
|
||||||
|
|
||||||
```bash
|
### Key Changes from Chrome Version
|
||||||
# Clone the repository
|
|
||||||
git clone https://github.com/seejohnrun/haste-server.git
|
|
||||||
cd haste-server
|
|
||||||
|
|
||||||
# Start with Docker Compose (includes Redis)
|
- Updated manifest to version 2 (Firefox compatible)
|
||||||
docker compose up -d
|
- Added Firefox-specific settings
|
||||||
```
|
- Changed from `action` to `browser_action`
|
||||||
|
- Changed from service worker to background scripts
|
||||||
|
- Moved host permissions into the permissions array
|
||||||
|
|
||||||
The Docker container is configured to use Redis as the storage backend by default. The `docker-compose.yml` file sets up both a Hastebin container and a Redis container, linking them together.
|
## License
|
||||||
|
|
||||||
If you need to customize the Docker setup, you can modify the environment variables in the `docker-compose.yml` file:
|
[MIT License](LICENSE)
|
||||||
|
|
||||||
```yaml
|
## Credits
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- STORAGE_TYPE=redis
|
|
||||||
- STORAGE_HOST=redis
|
|
||||||
- HASTEBIN_ENABLE_CSP=true
|
|
||||||
- HASTEBIN_ENABLE_HSTS=true
|
|
||||||
```
|
|
||||||
|
|
||||||
The container exists at git.nixc.us/colin/haste:haste-production and may be made public eventually.
|
Based on the original Clockify Extension by AE Now.
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
Hastebin can be configured using the following environment variables:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Server configuration
|
|
||||||
HASTEBIN_PORT=7777 # Port to listen on (default: 7777)
|
|
||||||
HASTEBIN_HOST=0.0.0.0 # Host to bind to (default: 0.0.0.0)
|
|
||||||
|
|
||||||
# Storage configuration
|
|
||||||
HASTEBIN_STORAGE_TYPE=file # Storage type: file, redis, postgres, etc.
|
|
||||||
HASTEBIN_STORAGE_PATH=./data # Path for file storage
|
|
||||||
DATABASE_URL=postgres://user:pass@host:5432/db # For postgres storage
|
|
||||||
|
|
||||||
# Docker-specific storage settings
|
|
||||||
STORAGE_TYPE=redis # Storage type in Docker (default: redis)
|
|
||||||
STORAGE_HOST=redis # Redis host in Docker environment
|
|
||||||
STORAGE_PORT=6379 # Redis port
|
|
||||||
STORAGE_PASSWORD= # Redis password if needed
|
|
||||||
STORAGE_DB=0 # Redis database number
|
|
||||||
|
|
||||||
# Security settings
|
|
||||||
HASTEBIN_ENABLE_CSP=true # Enable Content Security Policy
|
|
||||||
HASTEBIN_ENABLE_HSTS=true # Enable HTTP Strict Transport Security
|
|
||||||
HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true # Enable Cross-Origin Isolation
|
|
||||||
HASTEBIN_BYPASS_CSP_IN_DEV=true # Bypass CSP in development mode
|
|
||||||
|
|
||||||
# Other settings
|
|
||||||
NODE_ENV=development # Environment: development or production
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also configure Hastebin by editing the `config.js` file.
|
|
||||||
|
|
||||||
## Security Settings
|
|
||||||
|
|
||||||
The `security` section in the configuration allows you to control various security features, particularly the Content Security Policy (CSP):
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"security": {
|
|
||||||
"csp": true, // Enable/disable CSP entirely
|
|
||||||
"hsts": false, // Enable HTTP Strict Transport Security
|
|
||||||
"scriptSources": [], // Additional allowed script sources
|
|
||||||
"bypassCSPInDev": false, // Use permissive CSP in development mode
|
|
||||||
"allowUnsafeHashes": true, // Allow 'unsafe-hashes' in production for event handlers
|
|
||||||
"enableCrossOriginIsolation": false // Enable strict Cross-Origin isolation headers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Content Security Policy Options
|
|
||||||
|
|
||||||
* `csp` - Enable or disable Content Security Policy headers (default: true)
|
|
||||||
* `hsts` - Enable HTTP Strict Transport Security headers (default: false)
|
|
||||||
* `scriptSources` - Additional script sources to allow - comma-separated list in env vars
|
|
||||||
* `bypassCSPInDev` - In development mode (NODE_ENV=development), use a more permissive CSP that includes 'unsafe-inline' (default: false)
|
|
||||||
* `allowUnsafeHashes` - Allow 'unsafe-hashes' in production mode for DOM event handlers (default: true)
|
|
||||||
* `enableCrossOriginIsolation` - Enable strict Cross-Origin isolation headers (COEP, COOP, CORP) which enhance security but may break certain integrations (default: false)
|
|
||||||
|
|
||||||
### Environment Variables for Security Settings
|
|
||||||
|
|
||||||
You can set these options through environment variables:
|
|
||||||
* `HASTEBIN_ENABLE_CSP` - Enable/disable CSP (true/false)
|
|
||||||
* `HASTEBIN_ENABLE_HSTS` - Enable/disable HSTS (true/false)
|
|
||||||
* `HASTEBIN_SCRIPT_SOURCES` - Additional script sources (comma-separated)
|
|
||||||
* `HASTEBIN_BYPASS_CSP_IN_DEV` - Allow unsafe-inline in development (true/false)
|
|
||||||
* `HASTEBIN_ALLOW_UNSAFE_HASHES` - Allow unsafe-hashes in production (true/false)
|
|
||||||
* `HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION` - Enable Cross-Origin isolation headers (true/false)
|
|
||||||
|
|
||||||
### CSP Implementation Details
|
|
||||||
|
|
||||||
The Content Security Policy implementation in Hastebin uses nonces to secure inline scripts while maintaining functionality:
|
|
||||||
|
|
||||||
1. **Nonces**: A unique cryptographic nonce is generated for each request and applied to all script tags
|
|
||||||
2. **Development Mode**: When running with `NODE_ENV=development`, you can bypass strict CSP checks using the `bypassCSPInDev` option
|
|
||||||
3. **Production Mode**: In production, the CSP is configured to use nonces for all scripts, with optional 'unsafe-hashes' for event handlers
|
|
||||||
4. **Templates**: The template system automatically injects nonces into script tags, so you don't need to manually add them to the HTML
|
|
||||||
|
|
||||||
### Additional Security Headers
|
|
||||||
|
|
||||||
Besides CSP, Hastebin implements several other security headers:
|
|
||||||
|
|
||||||
1. **X-Content-Type-Options**: `nosniff`
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
#### Port Already in Use
|
|
||||||
|
|
||||||
If you see an error like `Error: listen EADDRINUSE: address already in use :::7777`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Find and kill processes using port 7777
|
|
||||||
lsof -i :7777 -t | xargs kill -9 || true
|
|
||||||
|
|
||||||
# Or use a different port
|
|
||||||
HASTEBIN_PORT=8000 npm run start:file
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Redis Connection Issues
|
|
||||||
|
|
||||||
If you're using Redis and see connection errors:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check if Redis is running
|
|
||||||
redis-cli ping
|
|
||||||
|
|
||||||
# Start Redis if needed
|
|
||||||
redis-server
|
|
||||||
|
|
||||||
# Or use file storage instead
|
|
||||||
npm run start:file
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Permission Issues with File Storage
|
|
||||||
|
|
||||||
If you see permission errors when using file storage:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create data directory with proper permissions
|
|
||||||
mkdir -p data
|
|
||||||
chmod 777 data
|
|
||||||
HASTEBIN_STORAGE_PATH=./data npm run start:file
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Test Server Issues
|
|
||||||
|
|
||||||
If tests are failing:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Make sure no server is running
|
|
||||||
lsof -i :7777 -t | xargs kill -9 || true
|
|
||||||
|
|
||||||
# Run tests with clean environment
|
|
||||||
npm run test:all
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
### Quick Test Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start a local test server with file storage
|
|
||||||
npm run start:dev
|
|
||||||
|
|
||||||
# Run all tests
|
|
||||||
npm test
|
|
||||||
|
|
||||||
# Run core functionality tests
|
|
||||||
npm run test:core
|
|
||||||
|
|
||||||
# Run security tests
|
|
||||||
npm run test:security
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Structure
|
|
||||||
|
|
||||||
Hastebin includes a comprehensive test suite covering both core functionality and security features. The tests are organized in the following structure:
|
|
||||||
|
|
||||||
```
|
|
||||||
test/
|
|
||||||
├── core/ # Core functionality tests
|
|
||||||
│ └── core_functionality_spec.js # Tests for basic operations
|
|
||||||
├── security/ # Security-related tests
|
|
||||||
│ ├── security_spec.js # Main security test suite
|
|
||||||
│ └── security_shell_spec.sh # Shell-based security tests
|
|
||||||
├── key_generators/ # Key generator tests
|
|
||||||
├── utils/ # Test utilities
|
|
||||||
│ └── test-local.js # Local test server setup
|
|
||||||
└── document_handler_spec.js # Document handler tests
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running Test Suites
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests (unit + security)
|
|
||||||
npm run test:all
|
|
||||||
|
|
||||||
# Run specific test suites
|
|
||||||
npm run test:core # Run core functionality tests
|
|
||||||
npm run test:security # Run all security tests
|
|
||||||
|
|
||||||
# Run specific security tests
|
|
||||||
npm run test:security:csp # Test CSP configuration
|
|
||||||
npm run test:security:cors # Test CORS settings
|
|
||||||
npm run test:security:combined # Test combined security features
|
|
||||||
```
|
|
||||||
|
|
||||||
## Storage
|
|
||||||
|
|
||||||
## API Usage
|
|
||||||
|
|
||||||
### Creating a Document
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Using curl
|
|
||||||
curl -X POST -d "Hello, world!" http://localhost:7777/documents
|
|
||||||
|
|
||||||
# Response: {"key":"uniquekey"}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Retrieving a Document
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Using curl
|
|
||||||
curl http://localhost:7777/raw/uniquekey
|
|
||||||
|
|
||||||
# Response: Hello, world!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Document Formats
|
|
||||||
|
|
||||||
- `http://localhost:7777/uniquekey` - HTML view with syntax highlighting
|
|
||||||
- `http://localhost:7777/raw/uniquekey` - Raw document content
|
|
||||||
- `http://localhost:7777/documents/uniquekey` - JSON response with document content
|
|
||||||
|
|
||||||
### Client Libraries
|
|
||||||
|
|
||||||
- [haste-client](https://git.nixc.us/Nixius/haste-client) - Command line client for Hastebin
|
|
||||||
- Example usage: `cat file.txt | haste`
|
|
||||||
|
|
||||||
## License Update
|
|
|
@ -1,66 +1,17 @@
|
||||||
services:
|
services:
|
||||||
redis:
|
|
||||||
image: redis:alpine
|
|
||||||
volumes:
|
|
||||||
- redis_data:/data
|
|
||||||
networks:
|
|
||||||
- default
|
|
||||||
deploy:
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == macmini3
|
|
||||||
replicas: 1
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
|
|
||||||
haste:
|
haste:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
volumes:
|
ports:
|
||||||
- public_system:/app/public/system
|
- "7777:7777"
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
|
- HASTEBIN_STORAGE_TYPE=file
|
||||||
|
- STORAGE_TYPE=file
|
||||||
|
- STORAGE_PATH=/app/data
|
||||||
|
- STORAGE_HOST=localhost
|
||||||
- HASTEBIN_ENABLE_CSP=true
|
- HASTEBIN_ENABLE_CSP=true
|
||||||
- HASTEBIN_ENABLE_HSTS=true
|
- HASTEBIN_ENABLE_HSTS=false
|
||||||
- HASTEBIN_ALLOW_UNSAFE_HASHES=true
|
|
||||||
- HASTEBIN_SCRIPT_SOURCES=
|
|
||||||
- HASTEBIN_BYPASS_CSP_IN_DEV=false
|
|
||||||
- HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true
|
- HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true
|
||||||
networks:
|
restart: on-failure
|
||||||
- traefik
|
|
||||||
- default
|
|
||||||
deploy:
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == macmini3
|
|
||||||
labels:
|
|
||||||
homepage.group: apps
|
|
||||||
homepage.name: HasteBin
|
|
||||||
homepage.href: https://haste.nixc.us/
|
|
||||||
homepage.description: HasteBin
|
|
||||||
us.nixc.autodeploy: "true"
|
|
||||||
traefik.enable: "true"
|
|
||||||
traefik.http.routers.production-haste_haste.rule: "Host(`haste.nixc.us`)"
|
|
||||||
traefik.http.routers.production-haste_haste.entrypoints: "websecure"
|
|
||||||
traefik.http.routers.production-haste_haste.tls: "true"
|
|
||||||
traefik.http.routers.production-haste_haste.tls.certresolver: "letsencryptresolver"
|
|
||||||
traefik.http.routers.production-haste_haste.service: "production-haste_haste"
|
|
||||||
traefik.http.services.production-haste_haste.loadbalancer.server.port: "7777"
|
|
||||||
traefik.docker.network: "traefik"
|
|
||||||
|
|
||||||
replicas: 1
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
|
|
||||||
networks:
|
|
||||||
traefik:
|
|
||||||
external: true
|
|
||||||
default:
|
|
||||||
driver: overlay
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
public_system:
|
|
||||||
driver: local
|
|
||||||
redis_data:
|
|
||||||
driver: local
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "Flockitrack",
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "Firefox extension for tracking time for tickets in YouTrack in Clockify",
|
||||||
|
"icons": {
|
||||||
|
"128": "icon_128.png",
|
||||||
|
"48": "icon_48.png",
|
||||||
|
"16": "icon_16.png"
|
||||||
|
},
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "flockitrack@nixc.us",
|
||||||
|
"strict_min_version": "57.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browser_action": {
|
||||||
|
"default_icon": "icon_128.png",
|
||||||
|
"default_popup": "popup.html",
|
||||||
|
"default_title": "Flockitrack"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"matches": ["<all_urls>"],
|
||||||
|
"js": ["content.js", "axios.min.js", "fontawesome.js"],
|
||||||
|
"css": ["modal.css"],
|
||||||
|
"run_at": "document_end"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
"storage",
|
||||||
|
"tabs",
|
||||||
|
"https://pm.aenow.com/*"
|
||||||
|
]
|
||||||
|
}
|
|
@ -2,6 +2,13 @@ body {
|
||||||
background: #002B36;
|
background: #002B36;
|
||||||
padding: 20px 50px;
|
padding: 20px 50px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* textarea */
|
/* textarea */
|
||||||
|
@ -17,6 +24,11 @@ textarea {
|
||||||
outline: none;
|
outline: none;
|
||||||
resize: none;
|
resize: none;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the line numbers */
|
/* the line numbers */
|
||||||
|
@ -226,3 +238,12 @@ textarea {
|
||||||
background-position: 0 bottom;
|
background-position: 0 bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#textarea-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 50px;
|
||||||
|
right: 50px;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,9 @@
|
||||||
|
|
||||||
<div id="linenos"></div>
|
<div id="linenos"></div>
|
||||||
<pre id="box" style="display:none;" class="hljs" tabindex="0"><code></code></pre>
|
<pre id="box" style="display:none;" class="hljs" tabindex="0"><code></code></pre>
|
||||||
<textarea spellcheck="false" style="display:none;"></textarea>
|
<div id="textarea-container" style="position: absolute; top: 20px; left: 50px; right: 50px; bottom: 0; overflow: hidden;">
|
||||||
|
<textarea spellcheck="false" style="display:none;"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue