1656 new page collection

This adds the new page collection described in ticket 1656:
* A page has a parent and a name. Pages can be top-level (no parent) or nested.
* If a page has no parent and its name matches the name of a collection, it will be used as the default page of that collection. This is done by embedding the default page in the collection's 'page' frame, and making the frontend code render the default page if present and merge its contextual actions into those of the collection. The default page's `@id` is `/pages/name-of-page/`, but it is rendered with a `<link rel="canonical" />` pointing to the collection URI, to help point search bots to the right place.
* Similarly, a page with no parent and name == 'homepage' will be used as the default page of the root.

Some ancillary changes:
* Moved `make_subrequest` and the embed-related functions from `contentbase` to `renderers` to break an import cycle.
* Changed most uses of `self.__parent__` to `self.collection` in the `Item` class, so that a page can have a resource path that's not within the page collection.
* Changed link properties to erase all links if None/null is PUT as the value (so that pages with a parent can be turned into top-level pages)
* Added a (simple dict global) registry of custom validator functions, which can be referenced in the schema by name, e.g. `"validators": ["name_of_validator"]`. Used to make sure a default page can't be used as a parent page.
* Improved the object picker component so that its value can be cleared.
* Improved the form component so that schema validation errors are shown next to their respective fields.
No, then we wouldn't get the URLs we want...all pages would have an @id starting with /pages/, and the `canonical_redirect` middleware would redirect to it. This only uses the page collection as the parent for pages that would otherwise have the same @id as a collection or the site root (i.e. default pages). Top-level pages use the root as a parent (@id = /page-name/) and subpages use their configured parent as the traversal parent (@id = /parent-name/page-name/)