// static/js/main.js

// Проверяем, что 'socket' уже инициализирован
if (!window.socket) {
    console.error('Socket is not initialized!');
}

// Event listener для кнопки 'add-note'
document.getElementById('add-note').addEventListener('click', () => {
    const x = Math.floor(Math.random() * window.innerWidth);
    const y = Math.floor(Math.random() * window.innerHeight);
    const width = 200; // Ширина по умолчанию
    const height = 40; // Высота по умолчанию
    socket.emit('create_note', { text: 'New Comment', x, y, width, height });
});

// Event listener для кнопки 'add-image'
document.getElementById('add-image').addEventListener('click', () => {
    const formHtml = `
        <div id="image-form" style="position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); background:white; padding:20px; border-radius:8px; box-shadow:0 0 10px rgba(0,0,0,0.1); z-index: 1000;">
            <label for="image-url" style="display:block; margin-bottom:8px;">Image URL:</label>
            <input type="text" id="image-url" placeholder="Enter image URL" style="width: calc(100% - 22px); padding:10px; margin-bottom:12px; border:1px solid #ccc; border-radius:4px;"><br>
            <label for="image-file" style="display:block; margin-bottom:8px;">Or Upload File:</label>
            <input type="file" id="image-file" accept="image/*" style="margin-bottom:12px;"><br>
            <button id="add-image-submit" style="padding:10px 20px; background-color:#007bff; color:white; border:none; border-radius:4px; cursor:pointer; margin-right:8px;">Add Image</button>
            <button id="cancel-image" style="padding:10px 20px; background-color:#ccc; color:white; border:none; border-radius:4px; cursor:pointer;">Cancel</button>
        </div>
    `;
    document.body.insertAdjacentHTML('beforeend', formHtml);

    document.getElementById('add-image-submit').addEventListener('click', async () => {
        const url = document.getElementById('image-url').value;
        const fileInput = document.getElementById('image-file');
        let imageUrl;

        if (url) {
            imageUrl = url;
        } else if (fileInput.files.length > 0) {
            const file = fileInput.files[0];
            imageUrl = await uploadFile(file);
        }

        if (imageUrl) {
            const x = Math.floor(Math.random() * window.innerWidth);
            const y = Math.floor(Math.random() * window.innerHeight);
            const img = new Image();
            img.src = imageUrl;
            img.onload = () => {
                const maxWidth = 720;
                const maxHeight = 720;
                let width = img.naturalWidth;
                let height = img.naturalHeight;

                if (width > maxWidth || height > maxHeight) {
                    const ratio = Math.min(maxWidth / width, maxHeight / height);
                    width *= ratio;
                    height *= ratio;
                }

                socket.emit('create_image', { url: imageUrl, x, y, width, height });
                closeModal();
            };
        }
    });

    document.getElementById('cancel-image').addEventListener('click', closeModal);

    function closeModal() {
        const form = document.getElementById('image-form');
        if (form) {
            form.remove();
        }
    }
});

// Обработка существующих заметок и изображений после загрузки страницы
document.addEventListener('DOMContentLoaded', () => {
    handleExistingNotes();
    handleExistingImages();
});

from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit
from flask_sqlalchemy import SQLAlchemy
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///notes.db'
db = SQLAlchemy(app)
socketio = SocketIO(app)

UPLOAD_FOLDER = 'static/uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER


class Note(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String(500), nullable=False)
    x = db.Column(db.Integer, nullable=False)
    y = db.Column(db.Integer, nullable=False)
    width = db.Column(db.Integer, nullable=False)
    height = db.Column(db.Integer, nullable=False)


class Image(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(500), nullable=False)
    x = db.Column(db.Integer, nullable=False)
    y = db.Column(db.Integer, nullable=False)
    width = db.Column(db.Integer, nullable=False)
    height = db.Column(db.Integer, nullable=False)


@app.route('/')
def index():
    notes = Note.query.all()
    images = Image.query.all()
    return render_template('index.html', notes=notes, images=images)


@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify({'error': 'No file part'}), 400

    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400

    filename = file.filename
    filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    file.save(filepath)

    return jsonify({'url': os.path.join('/', app.config['UPLOAD_FOLDER'], filename)})


@socketio.on('create_note')
def handle_create_note(data):
    text = data['text']
    x = data['x']
    y = data['y']
    width = data['width']
    height = data['height']
    new_note = Note(text=text, x=x, y=y, width=width, height=height)
    db.session.add(new_note)
    db.session.commit()
    emit('new_note', {'id': new_note.id, 'text': text, 'x': x, 'y': y, 'width': width, 'height': height},
         broadcast=True)


@socketio.on('update_note')
def handle_update_note(data):
    note = Note.query.get(data['id'])
    note.text = data['text']
    note.x = data['x']
    note.y = data['y']
    note.width = data['width']
    note.height = data['height']
    db.session.commit()
    emit('updated_note',
         {'id': note.id, 'text': note.text, 'x': note.x, 'y': note.y, 'width': note.width, 'height': note.height},
         broadcast=True)


@socketio.on('create_image')
def handle_create_image(data):
    url = data.get('url')
    x = data.get('x')
    y = data.get('y')
    width = data.get('width')
    height = data.get('height')

    if not url or not x or not y or not width or not height:
        return jsonify({'error': 'Missing required data'}), 400

    new_image = Image(url=url, x=x, y=y, width=width, height=height)
    db.session.add(new_image)
    db.session.commit()
    emit('new_image', {'id': new_image.id, 'url': url, 'x': x, 'y': y, 'width': width, 'height': height},
         broadcast=True)


@socketio.on('update_image')
def handle_update_image(data):
    image = Image.query.get(data['id'])
    image.url = data.get('url', image.url)
    image.x = data.get('x', image.x)
    image.y = data.get('y', image.y)
    image.width = data.get('width', image.width)
    image.height = data.get('height', image.height)
    db.session.commit()
    emit('updated_image',
         {'id': image.id, 'url': image.url, 'x': image.x, 'y': image.y, 'width': image.width, 'height': image.height},
         broadcast=True)


@socketio.on('delete_element')
def handle_delete_element(data):
    element_id = data['id']
    element_type = data.get('type')  # Добавляем тип элемента (note или image)

    if element_type == 'note':
        element = Note.query.get(element_id)
    elif element_type == 'image':
        element = Image.query.get(element_id)
    else:
        return jsonify({'error': 'Invalid element type'}), 400

    if element:
        db.session.delete(element)
        db.session.commit()
        emit('element_deleted', {'id': element_id, 'type': element_type}, broadcast=True)
    else:
        return jsonify({'error': 'Element not found'}), 404


if __name__ == '__main__':
    with app.app_context():
        if not os.path.exists('notes.db'):
            db.create_all()
    socketio.run(app, host='192.168.0.105', port=7846, debug=True, allow_unsafe_werkzeug=True)


Как мне при удалении изображения удалять его так же в папке