Edit via SFTP
<?php namespace ferret\layout;
  PURPOSE: very generalized output-page-building class; should be able to handle any kind of content/markup
    * This is specifically a *web* page because of the stashed-redirect. Stashing implies cookies, which
      are web, as does redirecting.
    * In theory this could be further split into a non-web type that just dispatches Events, but let's
      wait for a use-case.
   * All of a Page's contents are subnodes; it has none aside from that.
   * It's not necessary (or even necessarily good) to define abstract methods here
    for the event-objects to call. It would probably be more useful just to have
    some templates with usage in the documentation. (2022-06-23 will get to that.)
    The event-methods only need to be defined in the classes where they actually surface.
    2021-11-30 renamed ferret\cPage -> ferret\page\caPage
    2021-12-01 moved some XML-specific stuff from ferret\page\caPage to ferret\page\html\caPage
    2022-06-22 normalized DoOutput() to work with evint objects like the other Do*() fx.
      RenderNodes() is now called in the OnRender() handler in tRenderableTree.
    2022-06-27 removed tRenderableTree
    2022-06-30 moved to ferret\layout namespace; renamed caPage -> caWebPage
abstract class caWebPage extends cElement {
    // ++ EXECUTION ++ //
      PURPOSE: lets the Page class handle the order in which events are triggered.
        2022-06-28 created
        2022-10-29 renamed DoAllEvents() to Run()
          Note that actually this isn't *quite* the same thing as App->Go(), because
          other things happen after it is called. (Not actually sure that's right...)
          See app/app.php : App->Main().
    public function Run() {
        #echo 'AFTER BUILDING: '.$this->DumpTree();
    protected function DoBuilding()  { $this->OnEvent(new cEventNodeBuild); }
    protected function DoFiguring()  { $this->OnEvent(new cEventNodeFigure); }
    protected function DoOutput()    { 
        $this->OnEvent($oe = new cEventNodeRender);
        if ($oe->HasOutput()) {
            echo $oe->Output();
        } else {
            echo '<b>Internal Error</b>: No output rendered.<br>PAGE CLASS: '.cClassWrapper::DumpClass($this);
    #public function DoOutput() : void { echo $this->Render(); }
    // -- EXECUTION -- //
    // ++ I/O ++ //
    abstract public function AddContentString(string $s);
    abstract public function DoStashedRedirect(string $url);
    // -- I/O -- //