Files
seanime-docker/seanime-2.9.10/internal/plugin/ui/DOCS.md
2025-09-20 14:08:38 +01:00

2.2 KiB

Code

Dev notes for the plugin UI

Avoid

func (d *DOMManager) getElementChildren(elementID string) []*goja.Object {

	// Listen for changes from the client
	eventListener := d.ctx.RegisterEventListener(ClientDOMElementUpdatedEvent)
	defer d.ctx.UnregisterEventListener(eventListener.ID)
	payload := ClientDOMElementUpdatedEventPayload{}

	doneCh := make(chan []*goja.Object)

	go func(eventListener *EventListener) {
		for event := range eventListener.Channel {
			if event.ParsePayloadAs(ClientDOMElementUpdatedEvent, &payload) {
				if payload.Action == "getChildren" && payload.ElementId == elementID {
					if v, ok := payload.Result.([]interface{}); ok {
						arr := make([]*goja.Object, 0, len(v))
						for _, elem := range v {
							if elemData, ok := elem.(map[string]interface{}); ok {
								arr = append(arr, d.createDOMElementObject(elemData))
							}
						}
						doneCh <- arr
						return
					}
				}
			}
		}
	}(eventListener)

	d.ctx.SendEventToClient(ServerDOMManipulateEvent, &ServerDOMManipulateEventPayload{
		ElementId: elementID,
		Action:    "getChildren",
		Params:    map[string]interface{}{},
	})
	timeout := time.After(4 * time.Second)

	select {
	case <-timeout:
		return []*goja.Object{}
	case res := <-doneCh:
		return res
	}
}

In the above code

arr = append(arr, d.createDOMElementObject(elemData))

Uses the VM so it should be scheduled.

d.ctx.ScheduleAsync(func() error {
	arr := make([]*goja.Object, 0, len(v))
	for _, elem := range v {
		if elemData, ok := elem.(map[string]interface{}); ok {
			arr = append(arr, d.createDOMElementObject(elemData))
		}
	}
	return nil
})

However, getElementChildren() might be launched in a scheduled task.

ctx.registerEventHandler("test", () => {
    const el = ctx.dom.queryOne("#test")
    el.getChildren()
})

And since getElementChildren() is coded "synchronously" (without promises), it will block the task until the timeout and won't run its own task. You'll end up with something like this:

> event received
> timeout
> processing scheduled task
> sending task

Conclusion: Prefer promises when possible. For synchronous functions, avoid scheduling tasks inside them.