Core Concepts

Callback Return Values: CallIfStatus

MatchFunction, CallIfFound, CallIfNotFound, and CallAfterFillIn all return a CallIfStatus value that tells GPAL what to do next. The same four values appear in every callback, but their precise effect depends on which callback you are in.

The Four Values

Handled stops the custom handler chain at the current level -- no further custom handlers fire for this event. NotHandled passes control to the next registered handler. Terminate exits the entire operation immediately. TryNextSelector discards the current element candidate set and retries from the next location strategy defined on the selector. The exact effect of each value depends on which callback you are in -- the following slides cover each one.

public enum CallIfStatus

{

Handled, // I handled it -- stop the custom handler chain

NotHandled, // pass to the next handler in the chain

Terminate, // exit the entire operation now

TryNextSelector // discard this set, retry with the next location strategy

}

TIP

MatchFunction, CallIfFound, CallIfNotFound, and CallAfterFillIn all share this return type. The values carry the same general intent everywhere, but their precise behavior varies per callback.

MatchFunction: All Four Values Are Live

MatchFunction runs before simple match criteria. It receives the full found element list, populates the matched list and an all-matched flag, and returns a CallIfStatus. All four values are precise here: Handled stops the custom handler chain and passes matched elements into simple criteria; NotHandled passes the found list to the next registered MatchFunction; Terminate exits the entire operation; TryNextSelector signals that the found set has nothing worth matching and instructs GPAL to discard it and retry with the next location strategy.

.MatchFunction((found, out matched, out all, sel, exact) => {

matched = found.Where(e => e.GetAttribute("data-ready") == "true").ToList();

if (!matched.Any()) return CallIfStatus.TryNextSelector;

all = matched.Count == found.Count;

return CallIfStatus.Handled;

})

TIP

Multiple MatchFunction calls on the same selector chain in order. Each receives the found list and can pass it unchanged to the next by returning NotHandled. Only the final Handled handler's matched list feeds into simple match criteria, letting you compose matching logic from smaller reusable pieces.

CallIfFound, CallIfNotFound, and CallAfterFillIn

CallIfFound and CallIfNotFound cascade through three levels -- selector, then UOW, then global -- advancing only if the previous level returns NotHandled. Use Handled to stop the cascade at your level; Terminate exits the entire operation. Note: TryNextSelector in these callbacks stops the handler chain but does not actually retry the next location strategy -- that behavior is specific to MatchFunction. CallAfterFillIn fires after each FillInFrom row; only Terminate has a defined effect, stopping row processing early. All other return values continue to the next row.

browser

.CallIfFound((b, found, matched, sel, all) => {

Log($"Matched {matched.Count} on {sel.Name}");

return CallIfStatus.Handled;

})

.CallIfNotFound((b, found, matched, sel, all) => {

sel.Remove(); // remove this selector from the UOW

return CallIfStatus.Handled;

})

.CallAfterFillIn((b, tokens, idx) => {

return done ? CallIfStatus.Terminate : CallIfStatus.Handled;

})

.Execute();

TIP

selector.Remove() is most useful with persistent selectors. When several candidate selectors are registered persistently and one is found, removing it stops GPAL from checking for it in every subsequent UOW. If that selector had its own registered handler, the handler goes with it. For a shared handler registered across multiple selectors or scopes, call browser.RemoveCallIfHandlerEverywhere to clean it up everywhere at once.