feat: menus mobile corrigidos, sincronia multi-dispositivo e editor WYSIWYG
- Menus: dropdowns agora com position:fixed posicionado via JS — no celular
o overflow-x:auto da menubar cortava os itens (bug relatado)
- Sincronia celular/desktop: PUT aceita base_hash opcional; divergência →
409 {server_hash} e diálogo "Conflito de edição" (recarregar | salvar por
cima); abas limpas recarregam sozinhas no focus/visibilitychange (debounce)
- WYSIWYG (Ctrl+M): contenteditable com render md→html no servidor e
serialização html→md própria (títulos, negrito/itálico/tachado, listas
com task, citação, código, blocos, links, tabelas, entidades); HTML edita
preservando tags/atributos, sanitizando script/on* na entrada; toolbar
usa execCommand no modo rico; colar é sempre texto puro; txt não aplica
- store/api: ErrConflict + teste de conflito na store e na API
- README: WYSIWYG, sincronia, base_hash, nota do fix de menu
This commit is contained in:
1 parent
8b355e8edb
commit
3b91c1a509
8 files changed
+456
-57
No files matched your search
@@ -49,6 +49,7 @@ var (
|
||||
ErrInvalid = errors.New("dados inválidos")
|
||||
ErrTooLarge = errors.New("conteúdo excede o limite de tamanho")
|
||||
ErrUnchanged = errors.New("conteúdo idêntico à versão atual")
|
||||
ErrConflict = errors.New("a nota foi alterada desde a última sincronização")
|
||||
)
|
||||
|
||||
// Note é o estado atual de uma nota (sem o conteúdo).
|
||||
@@ -617,7 +618,9 @@ func (s *Store) Content(id string) (string, *Note, error) {
|
||||
|
||||
// Update salva metadados e, se o conteúdo mudou, uma nova revisão.
|
||||
// Um conteúdo inalterado atualiza apenas título/categorias/formato.
|
||||
func (s *Store) Update(id, title, format string, categories []string, content, author, message string) (*Note, error) {
|
||||
// baseHash != "" ativa controle otimista de concorrência: se o servidor já
|
||||
// mudou desde essa base, devolve ErrConflict (e a nota atual) em vez de sobrescrever.
|
||||
func (s *Store) Update(id, title, format string, categories []string, content, author, message, baseHash string) (*Note, error) {
|
||||
if err := cleanNoteFields(&title, &format); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -635,6 +638,9 @@ func (s *Store) Update(id, title, format string, categories []string, content, a
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if baseHash != "" && baseHash != n.Hash {
|
||||
return n, ErrConflict
|
||||
}
|
||||
newHash := hashContent(content)
|
||||
contentChanged := newHash != n.Hash
|
||||
if contentChanged {
|
||||
|
||||
Reference in new issue
Block a user