diff --git a/app/pb.go b/app/pb.go index 47cc8f6..1c5679d 100644 --- a/app/pb.go +++ b/app/pb.go @@ -11,6 +11,7 @@ import ( "time" "github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels" + "github.com/Theodor-Springmann-Stiftung/musenalm/helpers/imports" "github.com/Theodor-Springmann-Stiftung/musenalm/middleware" "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" "github.com/Theodor-Springmann-Stiftung/musenalm/templating" @@ -32,18 +33,18 @@ type BootFunc = func(e *core.BootstrapEvent) error // INFO: this is the main application that mainly is a pocketbase wrapper type App struct { - PB *pocketbase.PocketBase - MAConfig Config - Pages []pagemodels.IPage - dataCache *PrefixCache - dataMutex sync.RWMutex - htmlCache *PrefixCache - htmlMutex sync.RWMutex - pagesCache map[string]PageMetaData - pagesMutex sync.RWMutex - imagesCache map[string]*dbmodels.Image - imagesMutex sync.RWMutex - baendeCache *BaendeCache + PB *pocketbase.PocketBase + MAConfig Config + Pages []pagemodels.IPage + dataCache *PrefixCache + dataMutex sync.RWMutex + htmlCache *PrefixCache + htmlMutex sync.RWMutex + pagesCache map[string]PageMetaData + pagesMutex sync.RWMutex + imagesCache map[string]*dbmodels.Image + imagesMutex sync.RWMutex + baendeCache *BaendeCache baendeCacheMutex sync.RWMutex } @@ -91,6 +92,7 @@ func (bc *BaendeCache) GetItems() interface{} { func (bc *BaendeCache) GetUsers() interface{} { return bc.Users } + const ( TEST_SUPERUSER_MAIL = "demo@example.com" TEST_SUPERUSER_PASS = "password" @@ -195,6 +197,10 @@ func (app *App) Serve() error { // INFO: we use OnServe, but here is also OnBootstrap app.PB.OnServe().BindFunc(app.bindPages(engine)) + app.PB.OnServe().BindFunc(func(e *core.ServeEvent) error { + imports.MarkInterruptedFTS5Rebuild(e.App) + return e.Next() + }) return app.PB.Start() } @@ -210,8 +216,8 @@ func (app *App) createEngine() (*templating.Engine, error) { "site": map[string]interface{}{ "title": "Musenalm", "lang": "de", - "desc": "Bibliographie deutscher Almanache des 18. und 19. Jahrhunderts", - }}) + "desc": "Bibliographie deutscher Almanache des 18. und 19. Jahrhunderts", + }}) app.ResetDataCache() engine.AddFunc("data", func(key string) any { diff --git a/controllers/exports_admin.go b/controllers/exports_admin.go index 194b9f0..4ce12b3 100644 --- a/controllers/exports_admin.go +++ b/controllers/exports_admin.go @@ -121,19 +121,16 @@ func (p *ExportsAdmin) fts5RunHandler(app core.App) HandleFunc { return e.JSON(http.StatusUnauthorized, map[string]any{"error": err.Error()}) } - status, err := imports.StartFTS5Rebuild(app, true) - if err != nil { - return e.JSON(http.StatusInternalServerError, map[string]any{"error": err.Error()}) - } + go func() { + status, err := imports.StartFTS5Rebuild(app, true) + if err != nil { + app.Logger().Error("FTS5 rebuild start failed", "error", err) + return + } + app.Logger().Info("FTS5 rebuild triggered", "status", status) + }() - if status == "running" { - return e.JSON(http.StatusConflict, map[string]any{"error": "FTS5-Neuaufbau läuft bereits."}) - } - if status == "restarting" { - return e.JSON(http.StatusOK, map[string]any{"success": true, "status": "restarting"}) - } - - return e.JSON(http.StatusOK, map[string]any{"success": true, "status": "started"}) + return e.JSON(http.StatusAccepted, map[string]any{"success": true, "status": "queued"}) } } @@ -153,6 +150,16 @@ func (p *ExportsAdmin) fts5StatusHandler(app core.App) HandleFunc { if setting, err := dbmodels.Settings_Key(app, "fts5_rebuild_total"); err == nil && setting != nil { total = parseSettingInt(setting.Value()) } + + if snapshot, ok := imports.FTS5Status(); ok { + if imports.FTS5IsRunning() || status == "" || status == "idle" || status == "running" || status == "restarting" { + status = snapshot.Status + message = normalizeGermanMessage(snapshot.Message) + errMsg = normalizeGermanMessage(snapshot.Error) + done = snapshot.Done + total = snapshot.Total + } + } lastRebuild := formatLastRebuild(app) return e.JSON(http.StatusOK, map[string]any{ diff --git a/dbmodels/fts5.go b/dbmodels/fts5.go index 21f6de2..f2e73a0 100644 --- a/dbmodels/fts5.go +++ b/dbmodels/fts5.go @@ -4,6 +4,7 @@ import ( "errors" "strconv" "strings" + "sync" "unicode" "github.com/Theodor-Springmann-Stiftung/musenalm/helpers/datatypes" @@ -566,12 +567,71 @@ func InsertFTS5Record(query *dbx.Query, id string, fields []string, values ...st return errors.New("fields and values must have the same length") } - params := dbx.Params{ID_FIELD: id} + params := fts5ParamsPool.Get().(dbx.Params) + for key := range params { + delete(params, key) + } + params[ID_FIELD] = id for i, v := range fields { params[v] = values[i] } - _, err := query.Bind(params).Execute() + for key := range params { + delete(params, key) + } + fts5ParamsPool.Put(params) + return err +} + +type FTS5Row struct { + Id string + Values []string +} + +var fts5ParamsPool = sync.Pool{ + New: func() any { + return dbx.Params{} + }, +} + +func InsertFTS5Batch(dbBuilder dbx.Builder, table string, fields []string, rows []FTS5Row) error { + if len(rows) == 0 { + return nil + } + query := strings.Builder{} + query.WriteString("INSERT INTO ") + query.WriteString(FTS5TableName(table)) + query.WriteString(" (") + query.WriteString(ID_FIELD) + query.WriteString(", ") + query.WriteString(strings.Join(fields, ", ")) + query.WriteString(") VALUES ") + + params := dbx.Params{} + for i := 0; i < len(rows); i++ { + if i > 0 { + query.WriteString(", ") + } + row := rows[i] + if len(row.Values) != len(fields) { + return errors.New("fields and values must have the same length") + } + idKey := "id_" + strconv.Itoa(i) + params[idKey] = row.Id + query.WriteString("({:") + query.WriteString(idKey) + query.WriteString("}") + for j, field := range fields { + key := field + "_" + strconv.Itoa(i) + params[key] = row.Values[j] + query.WriteString(", {:") + query.WriteString(key) + query.WriteString("}") + } + query.WriteString(")") + } + + _, err := dbBuilder.NewQuery(query.String()).Bind(params).Execute() return err } diff --git a/helpers/imports/fts.go b/helpers/imports/fts.go index 8ed0691..849f3f1 100644 --- a/helpers/imports/fts.go +++ b/helpers/imports/fts.go @@ -18,8 +18,55 @@ var ( fts5Running bool fts5Cancel context.CancelFunc fts5RestartRequested bool + fts5StatusMu sync.RWMutex + fts5StatusSnapshot FTS5StatusSnapshot + fts5SuppressSettings bool ) +type FTS5StatusSnapshot struct { + Status string + Message string + Error string + Done int + Total int +} + +func FTS5Status() (FTS5StatusSnapshot, bool) { + fts5StatusMu.RLock() + defer fts5StatusMu.RUnlock() + if fts5StatusSnapshot.Status == "" { + return FTS5StatusSnapshot{}, false + } + return fts5StatusSnapshot, true +} + +func FTS5IsRunning() bool { + fts5Mu.Lock() + defer fts5Mu.Unlock() + return fts5Running +} + +func MarkInterruptedFTS5Rebuild(app core.App) { + if app == nil { + return + } + statusSetting, err := dbmodels.Settings_Key(app, "fts5_rebuild_status") + if err != nil || statusSetting == nil { + return + } + statusVal, ok := statusSetting.Value().(string) + if !ok { + statusVal = fmt.Sprintf("%v", statusSetting.Value()) + } + status := strings.Trim(statusVal, "\"") + if status != "running" && status != "restarting" { + return + } + done := getSettingInt(app, "fts5_rebuild_done") + total := getSettingInt(app, "fts5_rebuild_total") + setFTS5RebuildState(app, "aborted", "Neuaufbau wurde unterbrochen.", done, total, "") +} + func StartFTS5Rebuild(app core.App, allowRestart bool) (string, error) { fts5Mu.Lock() if fts5Running { @@ -44,6 +91,7 @@ func StartFTS5Rebuild(app core.App, allowRestart bool) (string, error) { fts5Mu.Unlock() go func() { + app.Logger().Info("FTS5 rebuild started") err := rebuildFTSFromScratchWithContext(app, ctx) fts5Mu.Lock() restart := fts5RestartRequested @@ -53,13 +101,20 @@ func StartFTS5Rebuild(app core.App, allowRestart bool) (string, error) { fts5Mu.Unlock() if restart { + app.Logger().Info("FTS5 rebuild restarting") _, _ = StartFTS5Rebuild(app, false) return } if errors.Is(err, context.Canceled) { + app.Logger().Info("FTS5 rebuild canceled") return } + if err != nil { + app.Logger().Error("FTS5 rebuild failed", "error", err) + return + } + app.Logger().Info("FTS5 rebuild finished") }() return "started", nil @@ -98,178 +153,287 @@ func rebuildFTSFromScratchWithContext(app core.App, ctx context.Context) error { } func rebuildFTSWithContext(app core.App, clearExisting bool, ctx context.Context) error { - fail := func(err error, done, total int) error { - setFTS5RebuildState(app, "error", "Neuaufbau fehlgeschlagen.", done, total, err.Error()) - return err - } - if clearExisting { if err := dbmodels.DeleteFTS5Data(app); err != nil { + setFTS5RebuildState(app, "error", "Neuaufbau fehlgeschlagen.", 0, 0, err.Error()) + return err + } + } + + done := 0 + total := 0 + app.Logger().Info("FTS5 rebuild transaction start") + setFTS5RebuildState(app, "running", "FTS5-Neuaufbau läuft.", 0, 0, "") + _ = upsertSetting(app, "fts5_rebuild_started_at", types.NowDateTime()) + fts5StatusMu.Lock() + fts5SuppressSettings = true + fts5StatusMu.Unlock() + defer func() { + fts5StatusMu.Lock() + fts5SuppressSettings = false + fts5StatusMu.Unlock() + }() + txErr := app.RunInTransaction(func(txApp core.App) error { + fail := func(err error, done, total int) error { + setFTS5RebuildState(txApp, "error", "Neuaufbau fehlgeschlagen.", done, total, err.Error()) + return err + } + + places := []*dbmodels.Place{} + if err := txApp.RecordQuery(dbmodels.PLACES_TABLE).All(&places); err != nil { return fail(err, 0, 0) } - } - - places := []*dbmodels.Place{} - if err := app.RecordQuery(dbmodels.PLACES_TABLE).All(&places); err != nil { - return fail(err, 0, 0) - } - agents := []*dbmodels.Agent{} - if err := app.RecordQuery(dbmodels.AGENTS_TABLE).All(&agents); err != nil { - return fail(err, 0, 0) - } - series := []*dbmodels.Series{} - if err := app.RecordQuery(dbmodels.SERIES_TABLE).All(&series); err != nil { - return fail(err, 0, 0) - } - items := []*dbmodels.Item{} - if err := app.RecordQuery(dbmodels.ITEMS_TABLE).All(&items); err != nil { - return fail(err, 0, 0) - } - entries := []*dbmodels.Entry{} - if err := app.RecordQuery(dbmodels.ENTRIES_TABLE).All(&entries); err != nil { - return fail(err, 0, 0) - } - contents := []*dbmodels.Content{} - if err := app.RecordQuery(dbmodels.CONTENTS_TABLE).All(&contents); err != nil { - return fail(err, 0, 0) - } - - entriesSeries := []*dbmodels.REntriesSeries{} - if err := app.RecordQuery(dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.SERIES_TABLE)).All(&entriesSeries); err != nil { - return fail(err, 0, 0) - } - entriesAgents := []*dbmodels.REntriesAgents{} - if err := app.RecordQuery(dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.AGENTS_TABLE)).All(&entriesAgents); err != nil { - return fail(err, 0, 0) - } - contentsAgents := []*dbmodels.RContentsAgents{} - if err := app.RecordQuery(dbmodels.RelationTableName(dbmodels.CONTENTS_TABLE, dbmodels.AGENTS_TABLE)).All(&contentsAgents); err != nil { - return fail(err, 0, 0) - } - - total := len(places) + len(agents) + len(series) + len(items) + len(entries) + len(contents) - done := 0 - setFTS5RebuildState(app, "running", "FTS5-Neuaufbau läuft.", done, total, "") - if err := checkFTS5Canceled(app, ctx, done, total); err != nil { - return err - } - - placesById := map[string]*dbmodels.Place{} - for _, place := range places { - placesById[place.Id] = place - } - agentsById := map[string]*dbmodels.Agent{} - for _, agent := range agents { - agentsById[agent.Id] = agent - } - seriesById := map[string]*dbmodels.Series{} - for _, s := range series { - seriesById[s.Id] = s - } - entriesById := map[string]*dbmodels.Entry{} - for _, entry := range entries { - entriesById[entry.Id] = entry - } - - entriesSeriesMap := map[string][]*dbmodels.Series{} - for _, rel := range entriesSeries { - if series := seriesById[rel.Series()]; series != nil { - entriesSeriesMap[rel.Entry()] = append(entriesSeriesMap[rel.Entry()], series) + agents := []*dbmodels.Agent{} + if err := txApp.RecordQuery(dbmodels.AGENTS_TABLE).All(&agents); err != nil { + return fail(err, 0, 0) } - } - entriesAgentsMap := map[string][]*dbmodels.Agent{} - for _, rel := range entriesAgents { - if agent := agentsById[rel.Agent()]; agent != nil { - entriesAgentsMap[rel.Entry()] = append(entriesAgentsMap[rel.Entry()], agent) + series := []*dbmodels.Series{} + if err := txApp.RecordQuery(dbmodels.SERIES_TABLE).All(&series); err != nil { + return fail(err, 0, 0) } - } - contentsAgentsMap := map[string][]*dbmodels.Agent{} - for _, rel := range contentsAgents { - if agent := agentsById[rel.Agent()]; agent != nil { - contentsAgentsMap[rel.Content()] = append(contentsAgentsMap[rel.Content()], agent) + items := []*dbmodels.Item{} + if err := txApp.RecordQuery(dbmodels.ITEMS_TABLE).All(&items); err != nil { + return fail(err, 0, 0) + } + entries := []*dbmodels.Entry{} + if err := txApp.RecordQuery(dbmodels.ENTRIES_TABLE).All(&entries); err != nil { + return fail(err, 0, 0) + } + contents := []*dbmodels.Content{} + if err := txApp.RecordQuery(dbmodels.CONTENTS_TABLE).All(&contents); err != nil { + return fail(err, 0, 0) } - } - qp := dbmodels.FTS5InsertQuery(app, dbmodels.PLACES_TABLE, dbmodels.PLACES_FTS5_FIELDS) - qa := dbmodels.FTS5InsertQuery(app, dbmodels.AGENTS_TABLE, dbmodels.AGENTS_FTS5_FIELDS) - qs := dbmodels.FTS5InsertQuery(app, dbmodels.SERIES_TABLE, dbmodels.SERIES_FTS5_FIELDS) - qi := dbmodels.FTS5InsertQuery(app, dbmodels.ITEMS_TABLE, dbmodels.ITEMS_FTS5_FIELDS) - qe := dbmodels.FTS5InsertQuery(app, dbmodels.ENTRIES_TABLE, dbmodels.ENTRIES_FTS5_FIELDS) - qc := dbmodels.FTS5InsertQuery(app, dbmodels.CONTENTS_TABLE, dbmodels.CONTENTS_FTS5_FIELDS) + entriesSeries := []*dbmodels.REntriesSeries{} + if err := txApp.RecordQuery(dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.SERIES_TABLE)).All(&entriesSeries); err != nil { + return fail(err, 0, 0) + } + entriesAgents := []*dbmodels.REntriesAgents{} + if err := txApp.RecordQuery(dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.AGENTS_TABLE)).All(&entriesAgents); err != nil { + return fail(err, 0, 0) + } + contentsAgents := []*dbmodels.RContentsAgents{} + if err := txApp.RecordQuery(dbmodels.RelationTableName(dbmodels.CONTENTS_TABLE, dbmodels.AGENTS_TABLE)).All(&contentsAgents); err != nil { + return fail(err, 0, 0) + } - for _, place := range places { + total = len(places) + len(agents) + len(series) + len(items) + len(entries) + len(contents) + done = 0 + setFTS5RebuildState(txApp, "running", "FTS5-Neuaufbau läuft.", done, total, "") if err := checkFTS5Canceled(app, ctx, done, total); err != nil { return err } - if err := dbmodels.BulkInsertFTS5Place(qp, place); err != nil { - return fail(err, done, total) - } - done++ - maybeUpdateFTS5Progress(app, ctx, done, total) - } - for _, agent := range agents { - if err := checkFTS5Canceled(app, ctx, done, total); err != nil { - return err - } - if err := dbmodels.BulkInsertFTS5Agent(qa, agent); err != nil { - return fail(err, done, total) - } - done++ - maybeUpdateFTS5Progress(app, ctx, done, total) - } - for _, s := range series { - if err := checkFTS5Canceled(app, ctx, done, total); err != nil { - return err - } - if err := dbmodels.BulkInsertFTS5Series(qs, s); err != nil { - return fail(err, done, total) - } - done++ - maybeUpdateFTS5Progress(app, ctx, done, total) - } - for _, item := range items { - if err := checkFTS5Canceled(app, ctx, done, total); err != nil { - return err - } - if err := dbmodels.BulkInsertFTS5Item(qi, item); err != nil { - return fail(err, done, total) - } - done++ - maybeUpdateFTS5Progress(app, ctx, done, total) - } + app.Logger().Info("FTS5 rebuild data loaded", "places", len(places), "agents", len(agents), "series", len(series), "items", len(items), "entries", len(entries), "contents", len(contents)) - for _, entry := range entries { - if err := checkFTS5Canceled(app, ctx, done, total); err != nil { - return err + placesById := map[string]*dbmodels.Place{} + for _, place := range places { + placesById[place.Id] = place } - entryPlaces := []*dbmodels.Place{} - for _, placeId := range entry.Places() { - if place := placesById[placeId]; place != nil { - entryPlaces = append(entryPlaces, place) + agentsById := map[string]*dbmodels.Agent{} + for _, agent := range agents { + agentsById[agent.Id] = agent + } + seriesById := map[string]*dbmodels.Series{} + for _, s := range series { + seriesById[s.Id] = s + } + entriesById := map[string]*dbmodels.Entry{} + for _, entry := range entries { + entriesById[entry.Id] = entry + } + + entriesSeriesMap := map[string][]*dbmodels.Series{} + for _, rel := range entriesSeries { + if series := seriesById[rel.Series()]; series != nil { + entriesSeriesMap[rel.Entry()] = append(entriesSeriesMap[rel.Entry()], series) } } - entryAgents := entriesAgentsMap[entry.Id] - entrySeries := entriesSeriesMap[entry.Id] - if err := dbmodels.BulkInsertFTS5Entry(qe, entry, entryPlaces, entryAgents, entrySeries); err != nil { - return fail(err, done, total) + entriesAgentsMap := map[string][]*dbmodels.Agent{} + for _, rel := range entriesAgents { + if agent := agentsById[rel.Agent()]; agent != nil { + entriesAgentsMap[rel.Entry()] = append(entriesAgentsMap[rel.Entry()], agent) + } + } + contentsAgentsMap := map[string][]*dbmodels.Agent{} + for _, rel := range contentsAgents { + if agent := agentsById[rel.Agent()]; agent != nil { + contentsAgentsMap[rel.Content()] = append(contentsAgentsMap[rel.Content()], agent) + } } - done++ - maybeUpdateFTS5Progress(app, ctx, done, total) - } - for _, content := range contents { - if err := checkFTS5Canceled(app, ctx, done, total); err != nil { - return err + builder := txApp.DB() + batchSizeFor := func(fieldCount int) int { + const maxParams = 900 + size := maxParams / (fieldCount + 1) + if size < 1 { + size = 1 + } + return size } - entry := entriesById[content.Entry()] - contentAgents := contentsAgentsMap[content.Id] - if err := dbmodels.BulkInsertFTS5Content(qc, content, entry, contentAgents); err != nil { - return fail(err, done, total) - } - done++ - maybeUpdateFTS5Progress(app, ctx, done, total) - } + app.Logger().Info("FTS5 rebuild insert places", "count", len(places)) + placeBatchSize := batchSizeFor(len(dbmodels.PLACES_FTS5_FIELDS)) + placeRows := make([]dbmodels.FTS5Row, 0, placeBatchSize) + for _, place := range places { + if err := checkFTS5Canceled(app, ctx, done, total); err != nil { + return err + } + placeRows = append(placeRows, dbmodels.FTS5Row{Id: place.Id, Values: dbmodels.FTS5ValuesPlace(place)}) + done++ + maybeUpdateFTS5Progress(app, ctx, done, total) + if len(placeRows) >= placeBatchSize { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.PLACES_TABLE, dbmodels.PLACES_FTS5_FIELDS, placeRows); err != nil { + return fail(err, done, total) + } + placeRows = placeRows[:0] + } + } + if len(placeRows) > 0 { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.PLACES_TABLE, dbmodels.PLACES_FTS5_FIELDS, placeRows); err != nil { + return fail(err, done, total) + } + } + + app.Logger().Info("FTS5 rebuild insert agents", "count", len(agents)) + agentBatchSize := batchSizeFor(len(dbmodels.AGENTS_FTS5_FIELDS)) + agentRows := make([]dbmodels.FTS5Row, 0, agentBatchSize) + for _, agent := range agents { + if err := checkFTS5Canceled(app, ctx, done, total); err != nil { + return err + } + agentRows = append(agentRows, dbmodels.FTS5Row{Id: agent.Id, Values: dbmodels.FTS5ValuesAgent(agent)}) + done++ + maybeUpdateFTS5Progress(app, ctx, done, total) + if len(agentRows) >= agentBatchSize { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.AGENTS_TABLE, dbmodels.AGENTS_FTS5_FIELDS, agentRows); err != nil { + return fail(err, done, total) + } + agentRows = agentRows[:0] + } + } + if len(agentRows) > 0 { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.AGENTS_TABLE, dbmodels.AGENTS_FTS5_FIELDS, agentRows); err != nil { + return fail(err, done, total) + } + } + + app.Logger().Info("FTS5 rebuild insert series", "count", len(series)) + seriesBatchSize := batchSizeFor(len(dbmodels.SERIES_FTS5_FIELDS)) + seriesRows := make([]dbmodels.FTS5Row, 0, seriesBatchSize) + for _, s := range series { + if err := checkFTS5Canceled(app, ctx, done, total); err != nil { + return err + } + seriesRows = append(seriesRows, dbmodels.FTS5Row{Id: s.Id, Values: dbmodels.FTS5ValuesSeries(s)}) + done++ + maybeUpdateFTS5Progress(app, ctx, done, total) + if len(seriesRows) >= seriesBatchSize { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.SERIES_TABLE, dbmodels.SERIES_FTS5_FIELDS, seriesRows); err != nil { + return fail(err, done, total) + } + seriesRows = seriesRows[:0] + } + } + if len(seriesRows) > 0 { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.SERIES_TABLE, dbmodels.SERIES_FTS5_FIELDS, seriesRows); err != nil { + return fail(err, done, total) + } + } + + app.Logger().Info("FTS5 rebuild insert items", "count", len(items)) + itemBatchSize := batchSizeFor(len(dbmodels.ITEMS_FTS5_FIELDS)) + itemRows := make([]dbmodels.FTS5Row, 0, itemBatchSize) + for _, item := range items { + if err := checkFTS5Canceled(app, ctx, done, total); err != nil { + return err + } + itemRows = append(itemRows, dbmodels.FTS5Row{Id: item.Id, Values: dbmodels.FTS5ValuesItem(item)}) + done++ + maybeUpdateFTS5Progress(app, ctx, done, total) + if len(itemRows) >= itemBatchSize { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.ITEMS_TABLE, dbmodels.ITEMS_FTS5_FIELDS, itemRows); err != nil { + return fail(err, done, total) + } + itemRows = itemRows[:0] + } + } + if len(itemRows) > 0 { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.ITEMS_TABLE, dbmodels.ITEMS_FTS5_FIELDS, itemRows); err != nil { + return fail(err, done, total) + } + } + + app.Logger().Info("FTS5 rebuild insert entries", "count", len(entries)) + entryBatchSize := batchSizeFor(len(dbmodels.ENTRIES_FTS5_FIELDS)) + entryRows := make([]dbmodels.FTS5Row, 0, entryBatchSize) + for _, entry := range entries { + if err := checkFTS5Canceled(app, ctx, done, total); err != nil { + return err + } + entryPlaces := []*dbmodels.Place{} + for _, placeId := range entry.Places() { + if place := placesById[placeId]; place != nil { + entryPlaces = append(entryPlaces, place) + } + } + entryAgents := entriesAgentsMap[entry.Id] + entrySeries := entriesSeriesMap[entry.Id] + entryRows = append(entryRows, dbmodels.FTS5Row{ + Id: entry.Id, + Values: dbmodels.FTS5ValuesEntry(entry, entryPlaces, entryAgents, entrySeries), + }) + done++ + maybeUpdateFTS5Progress(app, ctx, done, total) + if len(entryRows) >= entryBatchSize { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.ENTRIES_TABLE, dbmodels.ENTRIES_FTS5_FIELDS, entryRows); err != nil { + return fail(err, done, total) + } + entryRows = entryRows[:0] + } + } + if len(entryRows) > 0 { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.ENTRIES_TABLE, dbmodels.ENTRIES_FTS5_FIELDS, entryRows); err != nil { + return fail(err, done, total) + } + } + + app.Logger().Info("FTS5 rebuild insert contents", "count", len(contents)) + contentBatchSize := batchSizeFor(len(dbmodels.CONTENTS_FTS5_FIELDS)) + contentRows := make([]dbmodels.FTS5Row, 0, contentBatchSize) + for _, content := range contents { + if err := checkFTS5Canceled(app, ctx, done, total); err != nil { + return err + } + entry := entriesById[content.Entry()] + contentAgents := contentsAgentsMap[content.Id] + contentRows = append(contentRows, dbmodels.FTS5Row{ + Id: content.Id, + Values: dbmodels.FTS5ValuesContent(content, entry, contentAgents), + }) + done++ + maybeUpdateFTS5Progress(app, ctx, done, total) + if len(contentRows) >= contentBatchSize { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.CONTENTS_TABLE, dbmodels.CONTENTS_FTS5_FIELDS, contentRows); err != nil { + return fail(err, done, total) + } + contentRows = contentRows[:0] + } + } + if len(contentRows) > 0 { + if err := dbmodels.InsertFTS5Batch(builder, dbmodels.CONTENTS_TABLE, dbmodels.CONTENTS_FTS5_FIELDS, contentRows); err != nil { + return fail(err, done, total) + } + } + + return nil + }) + + if txErr != nil { + app.Logger().Error("FTS5 rebuild transaction failed", "error", txErr) + setFTS5RebuildState(app, "error", "Neuaufbau fehlgeschlagen.", done, total, txErr.Error()) + return txErr + } + app.Logger().Info("FTS5 rebuild transaction complete") setFTS5RebuildState(app, "complete", "FTS5-Neuaufbau abgeschlossen.", done, total, "") return nil } @@ -336,6 +500,21 @@ func isRecordNotFound(err error) bool { } func setFTS5RebuildState(app core.App, status, message string, done, total int, errMsg string) { + fts5StatusMu.Lock() + fts5StatusSnapshot = FTS5StatusSnapshot{ + Status: status, + Message: message, + Error: errMsg, + Done: done, + Total: total, + } + suppress := fts5SuppressSettings + fts5StatusMu.Unlock() + + if suppress || app.IsTransactional() { + return + } + _ = upsertSetting(app, "fts5_rebuild_status", status) _ = upsertSetting(app, "fts5_rebuild_message", message) _ = upsertSetting(app, "fts5_rebuild_done", done) diff --git a/views/assets/scripts.js b/views/assets/scripts.js index f899dff..1c00fd7 100644 --- a/views/assets/scripts.js +++ b/views/assets/scripts.js @@ -97,7 +97,7 @@ const ui = "\uFEFF", St = " ", Yr = function(s) { }, Y = (s) => { var t; return s == null || (t = s.tagName) === null || t === void 0 ? void 0 : t.toLowerCase(); -}, x = function(s) { +}, E = function(s) { let t, e, i = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; typeof s == "object" ? (i = s, s = i.tagName) : i = { attributes: i }; const n = document.createElement(s); @@ -111,7 +111,7 @@ const ui = "\uFEFF", St = " ", Yr = function(s) { }), n; }; let ue; -const Ee = function() { +const xe = function() { if (ue != null) return ue; ue = []; for (const s in X) { @@ -122,15 +122,15 @@ const Ee = function() { }, Pi = (s) => ee(s == null ? void 0 : s.firstChild), vs = function(s) { let { strict: t } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : { strict: !0 }; return t ? ee(s) : ee(s) || !ee(s.firstChild) && function(e) { - return Ee().includes(Y(e)) && !Ee().includes(Y(e.firstChild)); + return xe().includes(Y(e)) && !xe().includes(Y(e.firstChild)); }(s); }, ee = (s) => ro(s) && (s == null ? void 0 : s.data) === "block", ro = (s) => (s == null ? void 0 : s.nodeType) === Node.COMMENT_NODE, ie = function(s) { let { name: t } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; - if (s) return xe(s) ? s.data === ui ? !t || s.parentNode.dataset.trixCursorTarget === t : void 0 : ie(s.firstChild); -}, Nt = (s) => Qr(s, Mt), Zr = (s) => xe(s) && (s == null ? void 0 : s.data) === "", xe = (s) => (s == null ? void 0 : s.nodeType) === Node.TEXT_NODE, Hn = { level2Enabled: !0, getLevel() { + if (s) return Ee(s) ? s.data === ui ? !t || s.parentNode.dataset.trixCursorTarget === t : void 0 : ie(s.firstChild); +}, Nt = (s) => Qr(s, Mt), Zr = (s) => Ee(s) && (s == null ? void 0 : s.data) === "", Ee = (s) => (s == null ? void 0 : s.nodeType) === Node.TEXT_NODE, Hn = { level2Enabled: !0, getLevel() { return this.level2Enabled && Oe.supportsInputEvents ? 2 : 0; }, pickFiles(s) { - const t = x("input", { type: "file", multiple: !0, hidden: !0, id: this.fileInputId }); + const t = E("input", { type: "file", multiple: !0, hidden: !0, id: this.fileInputId }); t.addEventListener("change", () => { s(t.files), Ct(t); }), Ct(document.getElementById(this.fileInputId)), document.body.appendChild(t), t.click(); @@ -208,19 +208,19 @@ class ke extends H { return t instanceof this ? t : this.fromUCS2String(t == null ? void 0 : t.toString()); } static fromUCS2String(t) { - return new this(t, En(t)); + return new this(t, xn(t)); } static fromCodepoints(t) { - return new this(xn(t), t); + return new this(En(t), t); } constructor(t, e) { super(...arguments), this.ucs2String = t, this.codepoints = e, this.length = this.codepoints.length, this.ucs2Length = this.ucs2String.length; } offsetToUCS2Offset(t) { - return xn(this.codepoints.slice(0, Math.max(0, t))).length; + return En(this.codepoints.slice(0, Math.max(0, t))).length; } offsetFromUCS2Offset(t) { - return En(this.ucs2String.slice(0, Math.max(0, t))).length; + return xn(this.ucs2String.slice(0, Math.max(0, t))).length; } slice() { return this.constructor.fromCodepoints(this.codepoints.slice(...arguments)); @@ -242,8 +242,8 @@ class ke extends H { } } const lo = ((Fi = Array.from) === null || Fi === void 0 ? void 0 : Fi.call(Array, "👼").length) === 1, co = ((qi = " ".codePointAt) === null || qi === void 0 ? void 0 : qi.call(" ", 0)) != null, ho = ((Hi = String.fromCodePoint) === null || Hi === void 0 ? void 0 : Hi.call(String, 32, 128124)) === " 👼"; -let En, xn; -En = lo && co ? (s) => Array.from(s).map((t) => t.codePointAt(0)) : function(s) { +let xn, En; +xn = lo && co ? (s) => Array.from(s).map((t) => t.codePointAt(0)) : function(s) { const t = []; let e = 0; const { length: i } = s; @@ -256,7 +256,7 @@ En = lo && co ? (s) => Array.from(s).map((t) => t.codePointAt(0)) : function(s) t.push(n); } return t; -}, xn = ho ? (s) => String.fromCodePoint(...Array.from(s || [])) : function(s) { +}, En = ho ? (s) => String.fromCodePoint(...Array.from(s || [])) : function(s) { return (() => { const t = []; return Array.from(s).forEach((e) => { @@ -310,7 +310,7 @@ const qt = function() { for (var e = arguments.length, i = new Array(e > 1 ? e - 1 : 0), n = 1; n < e; n++) i[n - 1] = arguments[n]; return t.splice(...i), t; }, mo = /[\u05BE\u05C0\u05C3\u05D0-\u05EA\u05F0-\u05F4\u061B\u061F\u0621-\u063A\u0640-\u064A\u066D\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D5\u06E5\u06E6\u200F\u202B\u202E\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE72\uFE74\uFE76-\uFEFC]/, go = function() { - const s = x("input", { dir: "auto", name: "x", dirName: "x.dir" }), t = x("textarea", { dir: "auto", name: "y", dirName: "y.dir" }), e = x("form"); + const s = E("input", { dir: "auto", name: "x", dirName: "x.dir" }), t = E("textarea", { dir: "auto", name: "y", dirName: "y.dir" }), e = E("form"); e.appendChild(s), e.appendChild(t); const i = function() { try { @@ -348,7 +348,7 @@ const Sn = () => ($i || ($i = fo().concat(po())), $i), F = (s) => X[s], po = () const { nonce: t, content: e } = s; return t == "" ? e : t; } -}, As = (s) => document.head.querySelector("meta[name=".concat(s, "]")), Es = { "application/x-trix-feature-detection": "test" }, ia = function(s) { +}, As = (s) => document.head.querySelector("meta[name=".concat(s, "]")), xs = { "application/x-trix-feature-detection": "test" }, ia = function(s) { const t = s.getData("text/plain"), e = s.getData("text/html"); if (!t || !e) return t == null ? void 0 : t.length; { @@ -370,7 +370,7 @@ const Sn = () => ($i || ($i = fo().concat(po())), $i), F = (s) => X[s], po = () if (s[e] !== t[e]) return !1; return !0; }, k = function(s) { - if (s != null) return Array.isArray(s) || (s = [s, s]), [xs(s[0]), xs(s[1] != null ? s[1] : s[0])]; + if (s != null) return Array.isArray(s) || (s = [s, s]), [Es(s[0]), Es(s[1] != null ? s[1] : s[0])]; }, vt = function(s) { if (s == null) return; const [t, e] = k(s); @@ -379,7 +379,7 @@ const Sn = () => ($i || ($i = fo().concat(po())), $i), F = (s) => X[s], po = () if (s == null || t == null) return; const [e, i] = k(s), [n, r] = k(t); return Cn(e, n) && Cn(i, r); -}, xs = function(s) { +}, Es = function(s) { return typeof s == "number" ? s : sa(s); }, Cn = function(s, t) { return typeof s == "number" ? s === t : re(s, t); @@ -464,7 +464,7 @@ class et extends $t { return t in this.values; } merge(t) { - return new et(Ao(this.values, Eo(t))); + return new et(Ao(this.values, xo(t))); } slice(t) { const e = {}; @@ -522,7 +522,7 @@ const yo = function(s, t) { }), e; }, me = function(s) { return s instanceof et ? s : new et(s); -}, Eo = function(s) { +}, xo = function(s) { return s instanceof et ? s.values : s; }; class Wn { @@ -557,7 +557,7 @@ class Wn { }), t.join("/"); } } -class xo extends H { +class Eo extends H { constructor() { let t = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : []; super(...arguments), this.objects = {}, Array.from(t).forEach((e) => { @@ -791,7 +791,7 @@ var Ie = function s() { const d = i.createElement("template"); d.content && d.content.ownerDocument && (i = d.content.ownerDocument); } - let S, E = ""; + let S, x = ""; const { implementation: z, createNodeIterator: ct, createDocumentFragment: wt, getElementsByTagName: mt } = i, { importNode: bi } = n; let V = { afterSanitizeAttributes: [], afterSanitizeElements: [], afterSanitizeShadowDOM: [], beforeSanitizeAttributes: [], beforeSanitizeElements: [], beforeSanitizeShadowDOM: [], uponSanitizeAttribute: [], uponSanitizeElement: [], uponSanitizeShadowNode: [] }; e.isSupported = typeof la == "function" && typeof _ == "function" && z && z.createHTMLDocument !== void 0; @@ -800,7 +800,7 @@ var Ie = function s() { const q = L({}, [...Is, ...Ki, ...Gi, ...Ji, ...Rs]); let D = null; const Gn = L({}, [...Ds, ...Yi, ...Os, ...Ke]); - let N = Object.seal(da(null, { tagNameCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, attributeNameCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, allowCustomizedBuiltInElements: { writable: !0, configurable: !1, enumerable: !0, value: !1 } })), le = null, Ei = null, Jn = !0, xi = !0, Yn = !1, Xn = !0, Wt = !1, Ne = !0, kt = !1, Si = !1, Li = !1, zt = !1, Pe = !1, Fe = !1, Qn = !0, Zn = !1, Ci = !0, de = !1, Kt = {}, Gt = null; + let N = Object.seal(da(null, { tagNameCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, attributeNameCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, allowCustomizedBuiltInElements: { writable: !0, configurable: !1, enumerable: !0, value: !1 } })), le = null, xi = null, Jn = !0, Ei = !0, Yn = !1, Xn = !0, Wt = !1, Ne = !0, kt = !1, Si = !1, Li = !1, zt = !1, Pe = !1, Fe = !1, Qn = !0, Zn = !1, Ci = !0, de = !1, Kt = {}, Gt = null; const ts = L({}, ["annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", "style", "svg", "template", "thead", "title", "video", "xmp"]); let es = null; const is = L({}, ["audio", "video", "img", "source", "image", "track"]); @@ -818,10 +818,10 @@ var Ie = function s() { }, Ii = function() { let d = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; if (!Yt || Yt !== d) { - if (d && typeof d == "object" || (d = {}), d = ft(d), ce = Xa.indexOf(d.PARSER_MEDIA_TYPE) === -1 ? "text/html" : d.PARSER_MEDIA_TYPE, W = ce === "application/xhtml+xml" ? Wi : si, M = lt(d, "ALLOWED_TAGS") ? L({}, d.ALLOWED_TAGS, W) : q, D = lt(d, "ALLOWED_ATTR") ? L({}, d.ALLOWED_ATTR, W) : Gn, ki = lt(d, "ALLOWED_NAMESPACES") ? L({}, d.ALLOWED_NAMESPACES, Wi) : Ja, wi = lt(d, "ADD_URI_SAFE_ATTR") ? L(ft(ns), d.ADD_URI_SAFE_ATTR, W) : ns, es = lt(d, "ADD_DATA_URI_TAGS") ? L(ft(is), d.ADD_DATA_URI_TAGS, W) : is, Gt = lt(d, "FORBID_CONTENTS") ? L({}, d.FORBID_CONTENTS, W) : ts, le = lt(d, "FORBID_TAGS") ? L({}, d.FORBID_TAGS, W) : ft({}), Ei = lt(d, "FORBID_ATTR") ? L({}, d.FORBID_ATTR, W) : ft({}), Kt = !!lt(d, "USE_PROFILES") && d.USE_PROFILES, Jn = d.ALLOW_ARIA_ATTR !== !1, xi = d.ALLOW_DATA_ATTR !== !1, Yn = d.ALLOW_UNKNOWN_PROTOCOLS || !1, Xn = d.ALLOW_SELF_CLOSE_IN_ATTR !== !1, Wt = d.SAFE_FOR_TEMPLATES || !1, Ne = d.SAFE_FOR_XML !== !1, kt = d.WHOLE_DOCUMENT || !1, zt = d.RETURN_DOM || !1, Pe = d.RETURN_DOM_FRAGMENT || !1, Fe = d.RETURN_TRUSTED_TYPE || !1, Li = d.FORCE_BODY || !1, Qn = d.SANITIZE_DOM !== !1, Zn = d.SANITIZE_NAMED_PROPS || !1, Ci = d.KEEP_CONTENT !== !1, de = d.IN_PLACE || !1, oe = d.ALLOWED_URI_REGEXP || ca, Jt = d.NAMESPACE || gt, $e = d.MATHML_TEXT_INTEGRATION_POINTS || $e, Ue = d.HTML_INTEGRATION_POINTS || Ue, N = d.CUSTOM_ELEMENT_HANDLING || {}, d.CUSTOM_ELEMENT_HANDLING && ss(d.CUSTOM_ELEMENT_HANDLING.tagNameCheck) && (N.tagNameCheck = d.CUSTOM_ELEMENT_HANDLING.tagNameCheck), d.CUSTOM_ELEMENT_HANDLING && ss(d.CUSTOM_ELEMENT_HANDLING.attributeNameCheck) && (N.attributeNameCheck = d.CUSTOM_ELEMENT_HANDLING.attributeNameCheck), d.CUSTOM_ELEMENT_HANDLING && typeof d.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements == "boolean" && (N.allowCustomizedBuiltInElements = d.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements), Wt && (xi = !1), Pe && (zt = !0), Kt && (M = L({}, Rs), D = [], Kt.html === !0 && (L(M, Is), L(D, Ds)), Kt.svg === !0 && (L(M, Ki), L(D, Yi), L(D, Ke)), Kt.svgFilters === !0 && (L(M, Gi), L(D, Yi), L(D, Ke)), Kt.mathMl === !0 && (L(M, Ji), L(D, Os), L(D, Ke))), d.ADD_TAGS && (M === q && (M = ft(M)), L(M, d.ADD_TAGS, W)), d.ADD_ATTR && (D === Gn && (D = ft(D)), L(D, d.ADD_ATTR, W)), d.ADD_URI_SAFE_ATTR && L(wi, d.ADD_URI_SAFE_ATTR, W), d.FORBID_CONTENTS && (Gt === ts && (Gt = ft(Gt)), L(Gt, d.FORBID_CONTENTS, W)), Ci && (M["#text"] = !0), kt && L(M, ["html", "head", "body"]), M.table && (L(M, ["tbody"]), delete le.tbody), d.TRUSTED_TYPES_POLICY) { + if (d && typeof d == "object" || (d = {}), d = ft(d), ce = Xa.indexOf(d.PARSER_MEDIA_TYPE) === -1 ? "text/html" : d.PARSER_MEDIA_TYPE, W = ce === "application/xhtml+xml" ? Wi : si, M = lt(d, "ALLOWED_TAGS") ? L({}, d.ALLOWED_TAGS, W) : q, D = lt(d, "ALLOWED_ATTR") ? L({}, d.ALLOWED_ATTR, W) : Gn, ki = lt(d, "ALLOWED_NAMESPACES") ? L({}, d.ALLOWED_NAMESPACES, Wi) : Ja, wi = lt(d, "ADD_URI_SAFE_ATTR") ? L(ft(ns), d.ADD_URI_SAFE_ATTR, W) : ns, es = lt(d, "ADD_DATA_URI_TAGS") ? L(ft(is), d.ADD_DATA_URI_TAGS, W) : is, Gt = lt(d, "FORBID_CONTENTS") ? L({}, d.FORBID_CONTENTS, W) : ts, le = lt(d, "FORBID_TAGS") ? L({}, d.FORBID_TAGS, W) : ft({}), xi = lt(d, "FORBID_ATTR") ? L({}, d.FORBID_ATTR, W) : ft({}), Kt = !!lt(d, "USE_PROFILES") && d.USE_PROFILES, Jn = d.ALLOW_ARIA_ATTR !== !1, Ei = d.ALLOW_DATA_ATTR !== !1, Yn = d.ALLOW_UNKNOWN_PROTOCOLS || !1, Xn = d.ALLOW_SELF_CLOSE_IN_ATTR !== !1, Wt = d.SAFE_FOR_TEMPLATES || !1, Ne = d.SAFE_FOR_XML !== !1, kt = d.WHOLE_DOCUMENT || !1, zt = d.RETURN_DOM || !1, Pe = d.RETURN_DOM_FRAGMENT || !1, Fe = d.RETURN_TRUSTED_TYPE || !1, Li = d.FORCE_BODY || !1, Qn = d.SANITIZE_DOM !== !1, Zn = d.SANITIZE_NAMED_PROPS || !1, Ci = d.KEEP_CONTENT !== !1, de = d.IN_PLACE || !1, oe = d.ALLOWED_URI_REGEXP || ca, Jt = d.NAMESPACE || gt, $e = d.MATHML_TEXT_INTEGRATION_POINTS || $e, Ue = d.HTML_INTEGRATION_POINTS || Ue, N = d.CUSTOM_ELEMENT_HANDLING || {}, d.CUSTOM_ELEMENT_HANDLING && ss(d.CUSTOM_ELEMENT_HANDLING.tagNameCheck) && (N.tagNameCheck = d.CUSTOM_ELEMENT_HANDLING.tagNameCheck), d.CUSTOM_ELEMENT_HANDLING && ss(d.CUSTOM_ELEMENT_HANDLING.attributeNameCheck) && (N.attributeNameCheck = d.CUSTOM_ELEMENT_HANDLING.attributeNameCheck), d.CUSTOM_ELEMENT_HANDLING && typeof d.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements == "boolean" && (N.allowCustomizedBuiltInElements = d.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements), Wt && (Ei = !1), Pe && (zt = !0), Kt && (M = L({}, Rs), D = [], Kt.html === !0 && (L(M, Is), L(D, Ds)), Kt.svg === !0 && (L(M, Ki), L(D, Yi), L(D, Ke)), Kt.svgFilters === !0 && (L(M, Gi), L(D, Yi), L(D, Ke)), Kt.mathMl === !0 && (L(M, Ji), L(D, Os), L(D, Ke))), d.ADD_TAGS && (M === q && (M = ft(M)), L(M, d.ADD_TAGS, W)), d.ADD_ATTR && (D === Gn && (D = ft(D)), L(D, d.ADD_ATTR, W)), d.ADD_URI_SAFE_ATTR && L(wi, d.ADD_URI_SAFE_ATTR, W), d.FORBID_CONTENTS && (Gt === ts && (Gt = ft(Gt)), L(Gt, d.FORBID_CONTENTS, W)), Ci && (M["#text"] = !0), kt && L(M, ["html", "head", "body"]), M.table && (L(M, ["tbody"]), delete le.tbody), d.TRUSTED_TYPES_POLICY) { if (typeof d.TRUSTED_TYPES_POLICY.createHTML != "function") throw fe('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.'); if (typeof d.TRUSTED_TYPES_POLICY.createScriptURL != "function") throw fe('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.'); - S = d.TRUSTED_TYPES_POLICY, E = S.createHTML(""); + S = d.TRUSTED_TYPES_POLICY, x = S.createHTML(""); } else S === void 0 && (S = function(b, g) { if (typeof b != "object" || typeof b.createPolicy != "function") return null; let C = null; @@ -833,7 +833,7 @@ var Ie = function s() { } catch { return console.warn("TrustedTypes policy " + y + " could not be created."), null; } - }(f, r)), S !== null && typeof E == "string" && (E = S.createHTML("")); + }(f, r)), S !== null && typeof x == "string" && (x = S.createHTML("")); Q && Q(d), Yt = d; } }, rs = L({}, [...Ki, ...Gi, ...Bo]), as = L({}, [...Ji, ...Mo]), ht = function(d) { @@ -873,7 +873,7 @@ var Ie = function s() { if (!b || !b.documentElement) { b = z.createDocument(Jt, "template", null); try { - b.documentElement.innerHTML = Ti ? E : C; + b.documentElement.innerHTML = Ti ? x : C; } catch { } } @@ -919,9 +919,9 @@ var Ie = function s() { }), d.textContent !== b && (ge(e.removed, { element: d.cloneNode() }), d.textContent = b)), pt(V.afterSanitizeElements, d, null), !1) : (ht(d), !0); }, hs = function(d, b, g) { if (Qn && (b === "id" || b === "name") && (g in i || g in Qa)) return !1; - if (!(xi && !Ei[b] && J(_i, b))) { + if (!(Ei && !xi[b] && J(_i, b))) { if (!(Jn && J(vi, b))) { - if (!D[b] || Ei[b]) { + if (!D[b] || xi[b]) { if (!(us(d) && (N.tagNameCheck instanceof RegExp && J(N.tagNameCheck, d) || N.tagNameCheck instanceof Function && N.tagNameCheck(d)) && (N.attributeNameCheck instanceof RegExp && J(N.attributeNameCheck, b) || N.attributeNameCheck instanceof Function && N.attributeNameCheck(b, d)) || b === "is" && N.allowCustomizedBuiltInElements && (N.tagNameCheck instanceof RegExp && J(N.tagNameCheck, g) || N.tagNameCheck instanceof Function && N.tagNameCheck(g)))) return !1; } else if (!wi[b]) { if (!J(oe, pe(g, Me, ""))) { @@ -1002,7 +1002,7 @@ var Ie = function s() { } else if (d instanceof l) g = os(""), C = g.ownerDocument.importNode(d, !0), C.nodeType === jo && C.nodeName === "BODY" || C.nodeName === "HTML" ? g = C : g.appendChild(C); else { if (!zt && !Wt && !kt && d.indexOf("<") === -1) return S && Fe ? S.createHTML(d) : d; - if (g = os(d), !g) return zt ? null : Fe ? E : ""; + if (g = os(d), !g) return zt ? null : Fe ? x : ""; } g && Li && ht(g.firstChild); const j = ls(de ? d : g); @@ -1121,24 +1121,24 @@ class zn extends Ut { } createNodes() { let t; - const e = t = x({ tagName: "figure", className: this.getClassName(), data: this.getData(), editable: !1 }), i = this.getHref(); - return i && (t = x({ tagName: "a", editable: !1, attributes: { href: i, tabindex: -1 } }), e.appendChild(t)), this.attachment.hasContent() ? mi.setHTML(t, this.attachment.getContent()) : this.createContentNodes().forEach((n) => { + const e = t = E({ tagName: "figure", className: this.getClassName(), data: this.getData(), editable: !1 }), i = this.getHref(); + return i && (t = E({ tagName: "a", editable: !1, attributes: { href: i, tabindex: -1 } }), e.appendChild(t)), this.attachment.hasContent() ? mi.setHTML(t, this.attachment.getContent()) : this.createContentNodes().forEach((n) => { t.appendChild(n); - }), t.appendChild(this.createCaptionElement()), this.attachment.isPending() && (this.progressElement = x({ tagName: "progress", attributes: { class: At.attachmentProgress, value: this.attachment.getUploadProgress(), max: 100 }, data: { trixMutable: !0, trixStoreKey: ["progressElement", this.attachment.id].join("/") } }), e.appendChild(this.progressElement)), [Ms("left"), e, Ms("right")]; + }), t.appendChild(this.createCaptionElement()), this.attachment.isPending() && (this.progressElement = E({ tagName: "progress", attributes: { class: At.attachmentProgress, value: this.attachment.getUploadProgress(), max: 100 }, data: { trixMutable: !0, trixStoreKey: ["progressElement", this.attachment.id].join("/") } }), e.appendChild(this.progressElement)), [Ms("left"), e, Ms("right")]; } createCaptionElement() { - const t = x({ tagName: "figcaption", className: At.attachmentCaption }), e = this.attachmentPiece.getCaption(); + const t = E({ tagName: "figcaption", className: At.attachmentCaption }), e = this.attachmentPiece.getCaption(); if (e) t.classList.add("".concat(At.attachmentCaption, "--edited")), t.textContent = e; else { let i, n; const r = this.getCaptionConfig(); if (r.name && (i = this.attachment.getFilename()), r.size && (n = this.attachment.getFormattedFilesize()), i) { - const a = x({ tagName: "span", className: At.attachmentName, textContent: i }); + const a = E({ tagName: "span", className: At.attachmentName, textContent: i }); t.appendChild(a); } if (n) { i && t.appendChild(document.createTextNode(" ")); - const a = x({ tagName: "span", className: At.attachmentSize, textContent: n }); + const a = E({ tagName: "span", className: At.attachmentSize, textContent: n }); t.appendChild(a); } } @@ -1172,8 +1172,8 @@ class zn extends Ut { e && (e.value = t); } } -const Ms = (s) => x({ tagName: "span", textContent: ui, data: { trixCursorTarget: s, trixSerialize: !1 } }), tl = function(s, t) { - const e = x("div"); +const Ms = (s) => E({ tagName: "span", textContent: ui, data: { trixCursorTarget: s, trixSerialize: !1 } }), tl = function(s, t) { + const e = E("div"); return mi.setHTML(e, s || ""), e.querySelector(t); }; class ua extends zn { @@ -1181,7 +1181,7 @@ class ua extends zn { super(...arguments), this.attachment.previewDelegate = this; } createContentNodes() { - return this.image = x({ tagName: "img", attributes: { src: "" }, data: { trixMutable: !0 } }), this.refresh(this.image), [this.image]; + return this.image = E({ tagName: "img", attributes: { src: "" }, data: { trixMutable: !0 } }), this.refresh(this.image), [this.image]; } createCaptionElement() { const t = super.createCaptionElement(...arguments); @@ -1241,7 +1241,7 @@ class ma extends Ut { for (let n = 0; n < i.length; n++) { const r = i[n]; if (n > 0) { - const a = x("br"); + const a = E("br"); e.push(a); } if (r.length) { @@ -1261,13 +1261,13 @@ class ma extends Ut { if (a) { if (a.tagName) { var r; - const o = x(a.tagName); + const o = E(a.tagName); r ? (r.appendChild(o), r = o) : t = r = o; } if (a.styleProperty && (n[a.styleProperty] = i), a.style) for (e in a.style) i = a.style[e], n[e] = i; } } - if (Object.keys(n).length) for (e in t || (t = x("span")), n) i = n[e], t.style[e] = i; + if (Object.keys(n).length) for (e in t || (t = E("span")), n) i = n[e], t.style[e] = i; return t; } createContainerElement() { @@ -1275,7 +1275,7 @@ class ma extends Ut { const e = this.attributes[t], i = Ln(t); if (i && i.groupTagName) { const n = {}; - return n[t] = e, x(i.groupTagName, n); + return n[t] = e, E(i.groupTagName, n); } } } @@ -1309,18 +1309,18 @@ class pa extends Ut { } createNodes() { const t = [document.createComment("block")]; - if (this.block.isEmpty()) t.push(x("br")); + if (this.block.isEmpty()) t.push(E("br")); else { var e; const i = (e = F(this.block.getLastAttribute())) === null || e === void 0 ? void 0 : e.text, n = this.findOrCreateCachedChildView(ga, this.block.text, { textConfig: i }); - t.push(...Array.from(n.getNodes() || [])), this.shouldAddExtraNewlineElement() && t.push(x("br")); + t.push(...Array.from(n.getNodes() || [])), this.shouldAddExtraNewlineElement() && t.push(E("br")); } if (this.attributes.length) return t; { let i; const { tagName: n } = X.default; this.block.isRTL() && (i = { dir: "rtl" }); - const r = x({ tagName: n, attributes: i }); + const r = E({ tagName: n, attributes: i }); return t.forEach((a) => r.appendChild(a)), [r]; } } @@ -1335,7 +1335,7 @@ class pa extends Ut { return Object.entries(this.block.htmlAttributes).forEach((o) => { let [l, c] = o; a.includes(l) && (e[l] = c); - }), x({ tagName: r, className: i, attributes: e }); + }), E({ tagName: r, className: i, attributes: e }); } shouldAddExtraNewlineElement() { return /\n\n$/.test(this.block.toString()); @@ -1343,7 +1343,7 @@ class pa extends Ut { } class gi extends Ut { static render(t) { - const e = x("div"), i = new this(t, { element: e }); + const e = E("div"), i = new this(t, { element: e }); return i.render(), i.sync(), e; } constructor() { @@ -1353,7 +1353,7 @@ class gi extends Ut { t.isEqualTo(this.document) || (this.document = this.object = t); } render() { - if (this.childViews = [], this.shadowElement = x("div"), !this.document.isEmpty()) { + if (this.childViews = [], this.shadowElement = E("div"), !this.document.isEmpty()) { const t = Wn.groupObjects(this.document.getBlocks(), { asTree: !0 }); Array.from(t).forEach((e) => { const i = this.findOrCreateCachedChildView(pa, e); @@ -2229,7 +2229,7 @@ class nt extends $t { return new this.constructor(t); } copyUsingObjectsFromDocument(t) { - const e = new xo(t.getObjects()); + const e = new Eo(t.getObjects()); return this.copyUsingObjectMap(e); } copyUsingObjectMap(t) { @@ -2643,7 +2643,7 @@ class Re extends H { } } createHiddenContainer() { - return this.referenceElement ? (this.containerElement = this.referenceElement.cloneNode(!1), this.containerElement.removeAttribute("id"), this.containerElement.setAttribute("data-trix-internal", ""), this.containerElement.style.display = "none", this.referenceElement.parentNode.insertBefore(this.containerElement, this.referenceElement.nextSibling)) : (this.containerElement = x({ tagName: "div", style: { display: "none" } }), document.body.appendChild(this.containerElement)); + return this.referenceElement ? (this.containerElement = this.referenceElement.cloneNode(!1), this.containerElement.removeAttribute("id"), this.containerElement.setAttribute("data-trix-internal", ""), this.containerElement.style.display = "none", this.referenceElement.parentNode.insertBefore(this.containerElement, this.referenceElement.nextSibling)) : (this.containerElement = E({ tagName: "div", style: { display: "none" } }), document.body.appendChild(this.containerElement)); } removeHiddenContainer() { return Ct(this.containerElement); @@ -2805,12 +2805,12 @@ class Re extends H { const e = []; for (; t && t !== this.containerElement; ) { const i = Y(t); - Ee().includes(i) && e.push(t), t = t.parentNode; + xe().includes(i) && e.push(t), t = t.parentNode; } return e; } isBlockElement(t) { - if ((t == null ? void 0 : t.nodeType) === Node.ELEMENT_NODE && !Nt(t) && !Lt(t, { matchingSelector: "td", untilNode: this.containerElement })) return Ee().includes(Y(t)) || window.getComputedStyle(t).display === "block"; + if ((t == null ? void 0 : t.nodeType) === Node.ELEMENT_NODE && !Nt(t) && !Lt(t, { matchingSelector: "td", untilNode: this.containerElement })) return xe().includes(Y(t)) || window.getComputedStyle(t).display === "block"; } isInsignificantTextNode(t) { if ((t == null ? void 0 : t.nodeType) !== Node.TEXT_NODE || !bl(t.data)) return; @@ -2839,10 +2839,10 @@ class Re extends H { } getMarginOfBlockElementAtIndex(t) { const e = this.blockElements[t]; - if (e && e.textContent && !Ee().includes(Y(e)) && !this.processedElements.includes(e)) return Ws(e); + if (e && e.textContent && !xe().includes(Y(e)) && !this.processedElements.includes(e)) return Ws(e); } getMarginOfDefaultBlockElement() { - const t = x(X.default.tagName); + const t = E(X.default.tagName); return this.containerElement.appendChild(t), Ws(t); } } @@ -2887,7 +2887,7 @@ const js = function(s) { } }), t.innerHTML.replace(yl, ""); } }; -var El = Object.freeze({ __proto__: null }); +var xl = Object.freeze({ __proto__: null }); class O extends H { constructor(t, e) { super(...arguments), this.attachmentManager = t, this.attachment = e, this.id = this.attachment.id, this.file = this.attachment.file; @@ -2927,7 +2927,7 @@ class Aa extends H { return delete this.managedAttachments[t.id], e; } } -class Ea { +class xa { constructor(t) { this.composition = t, this.document = this.composition.document; const e = this.composition.getSelectedRange(); @@ -2952,7 +2952,7 @@ class Ea { return this.block.hasAttributes() && !this.block.isListItem() && this.block.isEmpty(); } } -class xt extends H { +class Et extends H { constructor() { super(...arguments), this.document = new nt(), this.attachments = [], this.currentAttributes = {}, this.revision = 0; } @@ -2998,7 +2998,7 @@ class xt extends H { return this.setSelection(i), this.notifyDelegateOfInsertionAtRange([e, i]); } insertLineBreak() { - const t = new Ea(this); + const t = new xa(this); if (t.shouldDecreaseListLevel()) return this.decreaseListLevel(), this.setSelection(t.startPosition); if (t.shouldPrependListItem()) { const e = new nt([t.block.copyWithoutText()]); @@ -3399,7 +3399,7 @@ class xt extends H { return i.offsetToUCS2Offset(n + e); } } -xt.proxyMethod("getSelectionManager().getPointRange"), xt.proxyMethod("getSelectionManager().setLocationRangeFromPointRange"), xt.proxyMethod("getSelectionManager().createLocationRangeFromDOMRange"), xt.proxyMethod("getSelectionManager().locationIsCursorTarget"), xt.proxyMethod("getSelectionManager().selectionIsExpanded"), xt.proxyMethod("delegate?.getSelectionManager"); +Et.proxyMethod("getSelectionManager().getPointRange"), Et.proxyMethod("getSelectionManager().setLocationRangeFromPointRange"), Et.proxyMethod("getSelectionManager().createLocationRangeFromDOMRange"), Et.proxyMethod("getSelectionManager().locationIsCursorTarget"), Et.proxyMethod("getSelectionManager().selectionIsExpanded"), Et.proxyMethod("delegate?.getSelectionManager"); class In extends H { constructor(t) { super(...arguments), this.composition = t, this.undoEntries = [], this.redoEntries = []; @@ -3407,7 +3407,7 @@ class In extends H { recordUndoEntry(t) { let { context: e, consolidatable: i } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; const n = this.undoEntries.slice(-1)[0]; - if (!i || !xl(n, t, e)) { + if (!i || !El(n, t, e)) { const r = this.createEntry({ description: t, context: e }); this.undoEntries.push(r), this.redoEntries = []; } @@ -3437,8 +3437,8 @@ class In extends H { return { description: t == null ? void 0 : t.toString(), context: JSON.stringify(e), snapshot: this.composition.getSnapshot() }; } } -const xl = (s, t, e) => (s == null ? void 0 : s.description) === (t == null ? void 0 : t.toString()) && (s == null ? void 0 : s.context) === JSON.stringify(e), Qi = "attachmentGallery"; -class xa { +const El = (s, t, e) => (s == null ? void 0 : s.description) === (t == null ? void 0 : t.toString()) && (s == null ? void 0 : s.context) === JSON.stringify(e), Qi = "attachmentGallery"; +class Ea { constructor(t) { this.document = t.document, this.selectedRange = t.selectedRange; } @@ -3470,7 +3470,7 @@ class xa { } } const Sa = function(s) { - const t = new xa(s); + const t = new Ea(s); return t.perform(), t.getSnapshot(); }, Sl = [Sa]; class La { @@ -3609,7 +3609,7 @@ class Ca { const l = ri(this.element, { usingFilter: wa }); for (; l.nextNode(); ) { const c = l.currentNode; - if (c === t && xe(t)) { + if (c === t && Ee(t)) { ie(c) || (a.offset += e); break; } @@ -3631,7 +3631,7 @@ class Ca { } let [n, r] = this.findNodeAndOffsetFromLocation(t); if (n) { - if (xe(n)) Zi(n) === 0 ? (e = n.parentNode.parentNode, i = Ni(n.parentNode), ie(n, { name: "right" }) && i++) : (e = n, i = t.offset - r); + if (Ee(n)) Zi(n) === 0 ? (e = n.parentNode.parentNode, i = Ni(n.parentNode), ie(n, { name: "right" }) && i++) : (e = n, i = t.offset - r); else { if (e = n.parentNode, !vs(n.previousSibling) && !Pi(e)) for (; n === e.lastChild && (n = e, e = e.parentNode, !Pi(e)); ) ; i = Ni(n), t.offset !== 0 && i++; @@ -3643,7 +3643,7 @@ class Ca { let e, i, n = 0; for (const r of this.getSignificantNodesForIndex(t.index)) { const a = Zi(r); - if (t.offset <= n + a) if (xe(r)) { + if (t.offset <= n + a) if (Ee(r)) { if (e = r, i = n, t.offset === i && ie(e)) break; } else e || (e = r, i = n); if (n += a, n > t.offset) break; @@ -3793,7 +3793,7 @@ class Dt extends H { } } Dt.proxyMethod("locationMapper.findLocationFromContainerAndOffset"), Dt.proxyMethod("locationMapper.findContainerAndOffsetFromLocation"), Dt.proxyMethod("locationMapper.findNodeAndOffsetFromLocation"), Dt.proxyMethod("pointMapper.createDOMRangeFromPoint"), Dt.proxyMethod("pointMapper.getClientRectsForDOMRange"); -var ka = Object.freeze({ __proto__: null, Attachment: ae, AttachmentManager: Aa, AttachmentPiece: se, Block: ut, Composition: xt, Document: nt, Editor: La, HTMLParser: Re, HTMLSanitizer: mi, LineBreakInsertion: Ea, LocationMapper: Ca, ManagedAttachment: O, Piece: Vt, PointMapper: Ta, SelectionManager: Dt, SplittableList: li, StringPiece: Kn, Text: dt, UndoManager: In }), wl = Object.freeze({ __proto__: null, ObjectView: Ut, AttachmentView: zn, BlockView: pa, DocumentView: gi, PieceView: ma, PreviewableAttachmentView: ua, TextView: ga }); +var ka = Object.freeze({ __proto__: null, Attachment: ae, AttachmentManager: Aa, AttachmentPiece: se, Block: ut, Composition: Et, Document: nt, Editor: La, HTMLParser: Re, HTMLSanitizer: mi, LineBreakInsertion: xa, LocationMapper: Ca, ManagedAttachment: O, Piece: Vt, PointMapper: Ta, SelectionManager: Dt, SplittableList: li, StringPiece: Kn, Text: dt, UndoManager: In }), wl = Object.freeze({ __proto__: null, ObjectView: Ut, AttachmentView: zn, BlockView: pa, DocumentView: gi, PieceView: ma, PreviewableAttachmentView: ua, TextView: ga }); const { lang: tn, css: Rt, keyNames: Tl } = Be, en = function(s) { return function() { const t = s.apply(this, arguments); @@ -3806,10 +3806,10 @@ class Ia extends H { super(...arguments), G(this, "makeElementMutable", en(() => ({ do: () => { this.element.dataset.trixMutable = !0; }, undo: () => delete this.element.dataset.trixMutable }))), G(this, "addToolbar", en(() => { - const r = x({ tagName: "div", className: Rt.attachmentToolbar, data: { trixMutable: !0 }, childNodes: x({ tagName: "div", className: "trix-button-row", childNodes: x({ tagName: "span", className: "trix-button-group trix-button-group--actions", childNodes: x({ tagName: "button", className: "trix-button trix-button--remove", textContent: tn.remove, attributes: { title: tn.remove }, data: { trixAction: "remove" } }) }) }) }); - return this.attachment.isPreviewable() && r.appendChild(x({ tagName: "div", className: Rt.attachmentMetadataContainer, childNodes: x({ tagName: "span", className: Rt.attachmentMetadata, childNodes: [x({ tagName: "span", className: Rt.attachmentName, textContent: this.attachment.getFilename(), attributes: { title: this.attachment.getFilename() } }), x({ tagName: "span", className: Rt.attachmentSize, textContent: this.attachment.getFormattedFilesize() })] }) })), B("click", { onElement: r, withCallback: this.didClickToolbar }), B("click", { onElement: r, matchingSelector: "[data-trix-action]", withCallback: this.didClickActionButton }), Ae("trix-attachment-before-toolbar", { onElement: this.element, attributes: { toolbar: r, attachment: this.attachment } }), { do: () => this.element.appendChild(r), undo: () => Ct(r) }; + const r = E({ tagName: "div", className: Rt.attachmentToolbar, data: { trixMutable: !0 }, childNodes: E({ tagName: "div", className: "trix-button-row", childNodes: E({ tagName: "span", className: "trix-button-group trix-button-group--actions", childNodes: E({ tagName: "button", className: "trix-button trix-button--remove", textContent: tn.remove, attributes: { title: tn.remove }, data: { trixAction: "remove" } }) }) }) }); + return this.attachment.isPreviewable() && r.appendChild(E({ tagName: "div", className: Rt.attachmentMetadataContainer, childNodes: E({ tagName: "span", className: Rt.attachmentMetadata, childNodes: [E({ tagName: "span", className: Rt.attachmentName, textContent: this.attachment.getFilename(), attributes: { title: this.attachment.getFilename() } }), E({ tagName: "span", className: Rt.attachmentSize, textContent: this.attachment.getFormattedFilesize() })] }) })), B("click", { onElement: r, withCallback: this.didClickToolbar }), B("click", { onElement: r, matchingSelector: "[data-trix-action]", withCallback: this.didClickActionButton }), Ae("trix-attachment-before-toolbar", { onElement: this.element, attributes: { toolbar: r, attachment: this.attachment } }), { do: () => this.element.appendChild(r), undo: () => Ct(r) }; })), G(this, "installCaptionEditor", en(() => { - const r = x({ tagName: "textarea", className: Rt.attachmentCaptionEditor, attributes: { placeholder: tn.captionPlaceholder }, data: { trixMutable: !0 } }); + const r = E({ tagName: "textarea", className: Rt.attachmentCaptionEditor, attributes: { placeholder: tn.captionPlaceholder }, data: { trixMutable: !0 } }); r.value = this.attachmentPiece.getCaption(); const a = r.cloneNode(); a.classList.add("trix-autoresize-clone"), a.tabIndex = -1; @@ -4201,7 +4201,7 @@ class bt extends pi { } getCompositionInput() { if (this.isComposing()) return this.compositionInput; - this.compositionInput = new Et(this); + this.compositionInput = new xt(this); } isComposing() { return this.compositionInput && !this.compositionInput.isEnded(); @@ -4214,8 +4214,8 @@ class bt extends pi { var e; if (!function(n) { if (n == null || !n.setData) return !1; - for (const r in Es) { - const a = Es[r]; + for (const r in xs) { + const a = xs[r]; try { if (n.setData(r, a), !n.getData(r) === a) return !1; } catch { @@ -4234,7 +4234,7 @@ class bt extends pi { }), e.Files || e["application/x-trix-document"] || e["text/html"] || e["text/plain"]; } getPastedHTMLUsingHiddenElement(t) { - const e = this.getSelectedRange(), i = { position: "absolute", left: "".concat(window.pageXOffset, "px"), top: "".concat(window.pageYOffset, "px"), opacity: 0 }, n = x({ style: i, tagName: "div", editable: !0 }); + const e = this.getSelectedRange(), i = { position: "absolute", left: "".concat(window.pageXOffset, "px"), top: "".concat(window.pageYOffset, "px"), opacity: 0 }, n = E({ style: i, tagName: "div", editable: !0 }); return document.body.appendChild(n), n.focus(), requestAnimationFrame(() => { const r = n.innerHTML; return Ct(n), this.setSelectedRange(e), t(r); @@ -4312,8 +4312,8 @@ G(bt, "events", { keydown(s) { }, paste(s) { const t = s.clipboardData || s.testClipboardData, e = { clipboard: t }; if (!t || ql(s)) return void this.getPastedHTMLUsingHiddenElement((_) => { - var S, E, z; - return e.type = "text/html", e.html = _, (S = this.delegate) === null || S === void 0 || S.inputControllerWillPaste(e), (E = this.responder) === null || E === void 0 || E.insertHTML(e.html), this.requestRender(), (z = this.delegate) === null || z === void 0 ? void 0 : z.inputControllerDidPaste(e); + var S, x, z; + return e.type = "text/html", e.html = _, (S = this.delegate) === null || S === void 0 || S.inputControllerWillPaste(e), (x = this.responder) === null || x === void 0 || x.insertHTML(e.html), this.requestRender(), (z = this.delegate) === null || z === void 0 ? void 0 : z.inputControllerDidPaste(e); }); const i = t.getData("URL"), n = t.getData("text/html"), r = t.getData("public.url-name"); if (i) { @@ -4417,7 +4417,7 @@ const Nl = (s) => { } } }; -class Et extends H { +class xt extends H { constructor(t) { super(...arguments), this.inputController = t, this.responder = this.inputController.responder, this.delegate = this.inputController.delegate, this.inputSummary = this.inputController.inputSummary, this.data = {}; } @@ -4451,7 +4451,7 @@ class Et extends H { return ((t = this.data.start) === null || t === void 0 ? void 0 : t.length) === 0 && ((e = this.data.end) === null || e === void 0 ? void 0 : e.length) > 0 && this.range; } } -Et.proxyMethod("inputController.setInputSummary"), Et.proxyMethod("inputController.requestRender"), Et.proxyMethod("inputController.requestReparse"), Et.proxyMethod("responder?.selectionIsExpanded"), Et.proxyMethod("responder?.insertPlaceholder"), Et.proxyMethod("responder?.selectPlaceholder"), Et.proxyMethod("responder?.forgetPlaceholder"); +xt.proxyMethod("inputController.setInputSummary"), xt.proxyMethod("inputController.requestRender"), xt.proxyMethod("inputController.requestReparse"), xt.proxyMethod("responder?.selectionIsExpanded"), xt.proxyMethod("responder?.insertPlaceholder"), xt.proxyMethod("responder?.selectPlaceholder"), xt.proxyMethod("responder?.forgetPlaceholder"); class Ce extends pi { constructor() { super(...arguments), this.render = this.render.bind(this); @@ -4890,7 +4890,7 @@ class Fa extends H { class we extends Da { constructor(t) { let { editorElement: e, document: i, html: n } = t; - super(...arguments), this.editorElement = e, this.selectionManager = new Dt(this.editorElement), this.selectionManager.delegate = this, this.composition = new xt(), this.composition.delegate = this, this.attachmentManager = new Aa(this.composition.getAttachments()), this.attachmentManager.delegate = this, this.inputController = Hn.getLevel() === 2 ? new Ce(this.editorElement) : new bt(this.editorElement), this.inputController.delegate = this, this.inputController.responder = this.composition, this.compositionController = new Ra(this.editorElement, this.composition), this.compositionController.delegate = this, this.toolbarController = new Fa(this.editorElement.toolbarElement), this.toolbarController.delegate = this, this.editor = new La(this.composition, this.selectionManager, this.editorElement), i ? this.editor.loadDocument(i) : this.editor.loadHTML(n); + super(...arguments), this.editorElement = e, this.selectionManager = new Dt(this.editorElement), this.selectionManager.delegate = this, this.composition = new Et(), this.composition.delegate = this, this.attachmentManager = new Aa(this.composition.getAttachments()), this.attachmentManager.delegate = this, this.inputController = Hn.getLevel() === 2 ? new Ce(this.editorElement) : new bt(this.editorElement), this.inputController.delegate = this, this.inputController.responder = this.composition, this.compositionController = new Ra(this.editorElement, this.composition), this.compositionController.delegate = this, this.toolbarController = new Fa(this.editorElement.toolbarElement), this.toolbarController.delegate = this, this.editor = new La(this.composition, this.selectionManager, this.editorElement), i ? this.editor.loadDocument(i) : this.editor.loadHTML(n); } registerSelectionManager() { return Ht.registerSelectionManager(this.selectionManager); @@ -5343,7 +5343,7 @@ class ed { } function Ye() { let s = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : ""; - const { required: t, value: e } = this.element, i = t && !e, n = !!s, r = x("input", { required: t }), a = s || r.validationMessage; + const { required: t, value: e } = this.element, i = t && !e, n = !!s, r = E("input", { required: t }), a = s || r.validationMessage; w(this, ot).setValidity({ valueMissing: i, customError: n }, a); } var an = /* @__PURE__ */ new WeakMap(), on = /* @__PURE__ */ new WeakMap(), ln = /* @__PURE__ */ new WeakMap(); @@ -5465,7 +5465,7 @@ class di extends HTMLElement { if (this.hasAttribute("toolbar")) return (t = this.ownerDocument) === null || t === void 0 ? void 0 : t.getElementById(this.getAttribute("toolbar")); if (this.parentNode) { const e = "trix-toolbar-".concat(this.trixId); - return this.setAttribute("toolbar", e), this.internalToolbar = x("trix-toolbar", { id: e }), this.parentNode.insertBefore(this.internalToolbar, this), this.internalToolbar; + return this.setAttribute("toolbar", e), this.internalToolbar = E("trix-toolbar", { id: e }), this.parentNode.insertBefore(this.internalToolbar, this), this.internalToolbar; } } get form() { @@ -5514,7 +5514,7 @@ class di extends HTMLElement { if (Ae("trix-before-initialize", { onElement: this }), this.defaultValue = this.inputElement ? this.inputElement.value : this.innerHTML, !this.hasAttribute("input") && this.parentNode && this.willCreateInput) { const t = "trix-input-".concat(this.trixId); this.setAttribute("input", t); - const e = x("input", { type: "hidden", id: t }); + const e = E("input", { type: "hidden", id: t }); this.parentNode.insertBefore(e, this.nextElementSibling); } this.editorController = new we({ editorElement: this, html: this.defaultValue }), requestAnimationFrame(() => Ae("trix-initialize", { onElement: this })); @@ -5556,7 +5556,7 @@ class di extends HTMLElement { } } G(di, "formAssociated", "ElementInternals" in window), G(di, "observedAttributes", ["connected"]); -const Xs = { VERSION: io, config: Be, core: El, models: ka, views: wl, controllers: Kl, observers: Gl, operations: Jl, elements: Object.freeze({ __proto__: null, TrixEditorElement: di, TrixToolbarElement: qa }), filters: Object.freeze({ __proto__: null, Filter: xa, attachmentGalleryFilter: Sa }) }; +const Xs = { VERSION: io, config: Be, core: xl, models: ka, views: wl, controllers: Kl, observers: Gl, operations: Jl, elements: Object.freeze({ __proto__: null, TrixEditorElement: di, TrixToolbarElement: qa }), filters: Object.freeze({ __proto__: null, Filter: Ea, attachmentGalleryFilter: Sa }) }; Object.assign(Xs, ka), window.Trix = Xs, setTimeout(function() { customElements.get("trix-toolbar") || customElements.define("trix-toolbar", qa), customElements.get("trix-editor") || customElements.define("trix-editor", di); }, 0); @@ -6341,7 +6341,7 @@ class hd extends HTMLElement { } } ci = new WeakMap(); -const ud = "msr-component-wrapper", Zs = "msr-selected-items-container", tr = "msr-placeholder-no-selection-text", md = "msr-selected-item-pill", gd = "msr-selected-item-text", pd = "msr-item-name", fd = "msr-item-additional-data", bd = "msr-selected-item-role", er = "msr-selected-item-delete-btn", _d = "msr-controls-area", ir = "msr-pre-add-button", nr = "msr-input-area-wrapper", Qe = "msr-input-area-default-border", dn = "msr-input-area-staged", sr = "msr-staging-area-container", vd = "msr-staged-item-pill", yd = "msr-staged-item-text", cn = "msr-staged-role-select", rr = "msr-staged-cancel-btn", ar = "msr-text-input", or = "msr-add-button", lr = "msr-options-list", dr = "msr-option-item", Ad = "msr-option-item-name", Ed = "msr-option-item-detail", cr = "msr-option-item-highlighted", hn = "msr-hidden-select", xd = "msr-state-no-selection", Sd = "msr-state-has-selection", Ld = "msr-state-list-open", Cd = "msr-state-item-staged"; +const ud = "msr-component-wrapper", Zs = "msr-selected-items-container", tr = "msr-placeholder-no-selection-text", md = "msr-selected-item-pill", gd = "msr-selected-item-text", pd = "msr-item-name", fd = "msr-item-additional-data", bd = "msr-selected-item-role", er = "msr-selected-item-delete-btn", _d = "msr-controls-area", ir = "msr-pre-add-button", nr = "msr-input-area-wrapper", Qe = "msr-input-area-default-border", dn = "msr-input-area-staged", sr = "msr-staging-area-container", vd = "msr-staged-item-pill", yd = "msr-staged-item-text", cn = "msr-staged-role-select", rr = "msr-staged-cancel-btn", ar = "msr-text-input", or = "msr-add-button", lr = "msr-options-list", dr = "msr-option-item", Ad = "msr-option-item-name", xd = "msr-option-item-detail", cr = "msr-option-item-highlighted", hn = "msr-hidden-select", Ed = "msr-state-no-selection", Sd = "msr-state-has-selection", Ld = "msr-state-list-open", Cd = "msr-state-item-staged"; class Ha extends HTMLElement { constructor() { super(); @@ -6423,7 +6423,7 @@ class Ha extends HTMLElement { this.optionTemplate = document.createElement("template"), this.optionTemplate.innerHTML = `