91 lines
2.1 KiB
Go
91 lines
2.1 KiB
Go
package ultidraw
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// UltiDrawDoc is the on-disk format for Excalidraw drawings in UltiDrive.
|
|
type UltiDrawDoc struct {
|
|
Type string `json:"type"`
|
|
Version int `json:"version"`
|
|
Source string `json:"source,omitempty"`
|
|
Elements json.RawMessage `json:"elements"`
|
|
AppState json.RawMessage `json:"appState,omitempty"`
|
|
Files json.RawMessage `json:"files,omitempty"`
|
|
YjsState string `json:"yjsState,omitempty"`
|
|
UpdatedAt string `json:"updatedAt,omitempty"`
|
|
}
|
|
|
|
func ParseUltiDrawDoc(raw []byte) (UltiDrawDoc, error) {
|
|
var doc UltiDrawDoc
|
|
if err := json.Unmarshal(raw, &doc); err != nil {
|
|
return UltiDrawDoc{}, err
|
|
}
|
|
if doc.Type == "" {
|
|
doc.Type = "excalidraw"
|
|
}
|
|
if doc.Version == 0 {
|
|
doc.Version = 2
|
|
}
|
|
return doc, nil
|
|
}
|
|
|
|
func NewUltiDrawDoc(elements, appState, files json.RawMessage) UltiDrawDoc {
|
|
if len(elements) == 0 {
|
|
elements = json.RawMessage("[]")
|
|
}
|
|
if len(appState) == 0 {
|
|
appState = json.RawMessage(`{"gridSize":null,"viewBackgroundColor":"#ffffff"}`)
|
|
}
|
|
if len(files) == 0 {
|
|
files = json.RawMessage("{}")
|
|
}
|
|
return UltiDrawDoc{
|
|
Type: "excalidraw",
|
|
Version: 2,
|
|
Source: "https://ultidrive",
|
|
Elements: elements,
|
|
AppState: appState,
|
|
Files: files,
|
|
}
|
|
}
|
|
|
|
func (d UltiDrawDoc) Marshal() ([]byte, error) {
|
|
d.UpdatedAt = time.Now().UTC().Format(time.RFC3339)
|
|
return json.Marshal(d)
|
|
}
|
|
|
|
func ApplyUltiDrawPatch(existing UltiDrawDoc, raw []byte) (UltiDrawDoc, error) {
|
|
var patch map[string]json.RawMessage
|
|
if err := json.Unmarshal(raw, &patch); err != nil {
|
|
return UltiDrawDoc{}, err
|
|
}
|
|
doc := existing
|
|
if doc.Type == "" {
|
|
doc = NewUltiDrawDoc(nil, nil, nil)
|
|
}
|
|
if v, ok := patch["elements"]; ok {
|
|
doc.Elements = v
|
|
}
|
|
if v, ok := patch["appState"]; ok {
|
|
doc.AppState = v
|
|
}
|
|
if v, ok := patch["files"]; ok {
|
|
doc.Files = v
|
|
}
|
|
if v, ok := patch["yjsState"]; ok {
|
|
doc.YjsState = strings.Trim(string(v), `"`)
|
|
}
|
|
return doc, nil
|
|
}
|
|
|
|
func isEmptyElements(elements json.RawMessage) bool {
|
|
if len(elements) == 0 {
|
|
return true
|
|
}
|
|
s := strings.TrimSpace(string(elements))
|
|
return s == "" || s == "[]" || s == "null"
|
|
}
|