skeleton

The SKELETON-cell convention: a row that exists before its items have landed.

Both cell components render skeletons — JRRowItem for Home's rows and GridItem for the item grid's genre rows — and several views build and guard against them. The whole convention lives here: the placeholder a producer appends, the predicate a consumer guards with, and the spinner the cells draw. A hand-typed "Loading" literal at any site is drift waiting to happen — a misspelled construction site would send a bare ContentNode into the media render path, where reading absent fields crashes the render thread.

Members

(static, constant) PLACEHOLDER_TYPE

The type field value that marks a placeholder. Compare via isPlaceholder(), construct via createPlaceholder() — never hand-type this string elsewhere.

Default Value
  • Loading

(static, constant) SPINNER_SIZE

Diameter of the spinner graphic, in px. Small enough to read as "this cell is waiting" rather than as content in its own right.

Default Value
  • 48

Methods

(static) createPlaceholder() → {object}

Builds the placeholder child a skeleton row carries so the RowList renders the row (a childless row is not laid out at all) at its correct slot size.

Returns:
Type: 
object

(static) hideSpinner(spinner) → {void}

Hides and stops spinner if the caller ever created one.

Call this on every non-skeleton render, not just when leaving a skeleton: cells are RECYCLED, so the cell now rendering a real item may be the same node that showed a spinner a moment ago. A spinner left running would keep animating over real content.

Parameters:
NameTypeDescription
spinnerdynamic
Returns:
Type: 
void

(static) isPlaceholder(node) → {boolean}

True when node is a skeleton placeholder. Safe on invalid and on nodes with no type field (a bare ContentNode reads invalid there).

Parameters:
NameTypeDescription
nodedynamic
Returns:
Type: 
boolean

(static) showSpinner(owner, spinner, slotWidth, posterHeight, posterTopopt) → {object}

Lazy-creates, centers and starts the spinner over owner's poster area.

The node is passed in and handed back rather than kept in an m here: these run inside a component's scope, where m is that component instance. The caller owns the reference (one spinner per recycled cell); this only knows how to size, place and start it.

Creation work (sizing the graphic, parenting to owner) happens ONCE, in the create branch — cells are recycled and re-bound often, an appendChild of an already-parented child is a detach+reattach scene-graph mutation, and control = "start" on a running spinner visibly resets the animation. The steady-state path only re-places (slot sizes differ across rows) and re-shows.

within the full cell, whose height includes the title area below the poster) sits at the cell origin, as in JRRowItem; GridItem offsets it)

Parameters:
NameTypeAttributesDefaultDescription
ownerobject

the cell node the spinner is parented to (constant per caller)

spinnerdynamic

the caller's existing spinner, or invalid on first use

slotWidthfloat

the cell's width

posterHeightfloat

the poster area's height (the spinner centers within it, NOT

posterTopfloat<optional>
0

the poster area's y offset within the cell (0 when the poster

Returns:

the spinner node, for the caller to hold onto across recycles

Type: 
object