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.
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
}
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 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;
})
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 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();
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.
Showing off some plain text in these paragraphs eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Here you can find different accents and emphasis sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
This is a link and how it could look like bestlinkinthebeautifulworld. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Here's just some classic bold text adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam notBoldSecondbestlinkinthebeautifulworld illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at adipisicing elit libero vel voluptas? Expedita, adipisicing facere dolores voluptatem ad ab rem assumenda soluta!
Other cuple of colors in case we want to emphasize several ways adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at voluptatem libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae quas consequuntur illo numquam assumenda autem exercitationem distinctio perspiciatis in natus. Eius dicta similique ipsam ipsa minima, nemo quae enim tempore.
GPAL
.CallIfNotFound(GenericCallIfNotFound)
.WithPublishToConsole();
//System.Drawing.Rectangle windowSize = new System.Drawing.Rectangle(10, 10, 1500, 1024);
// NOTE: we have to set browser = before we execute any steps
// this is due to the 'GenericCallIfNotFound' which might throw an exception, and BankScraper will not have the browser set when it calls scraper.Close()
// until the complete fluent line gets executed (meaning every step, meaning browser is not set until everything else succeeds)
browser = GPAL.Browser
.WithBrowserType(Enums.BrowserType.Chrome)
.WithProfileDataDirectory(ChromeProfileLocation)
.WithUseAutomationEngine(AutomationEngine.Selenium)
.WithWindowSize(new System.Drawing.Rectangle(0,0,1920,1080))
.ToGPALObject();