diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6f1cfbaf1d..10b2dfe5b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - php-versions: ['7.4', '8.0', '8.1', '8.2'] + php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3'] fail-fast: false steps: - name: Checkout @@ -36,7 +36,7 @@ jobs: tools: composer:v1 env: COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + - name: Set up Node uses: actions/setup-node@v3 with: @@ -53,23 +53,23 @@ jobs: path: ${{ env.CI_COMPOSER_CACHE_DIR }} key: composer-${{ hashFiles('**/composer.lock') }} restore-keys: composer- - + - name: Cache build caches uses: actions/cache@v3 with: path: ./build/cache key: build-cache-${{ github.sha }} restore-keys: build-cache- - + - name: Start MySQL run: sudo systemctl start mysql.service - + - name: Install Node dependencies run: npm install - + - name: Gulp init run: npx gulp init - + - name: Set up database run: | mysql -e "create database IF NOT EXISTS omeka_test;" -uroot -proot @@ -77,7 +77,7 @@ jobs: sed -i 's/^user.*/user = "root"/' application/test/config/database.ini sed -i 's/^dbname.*/dbname = "omeka_test"/' application/test/config/database.ini sed -i 's/^password.*/password = "root"/' application/test/config/database.ini - + - name: Run tests run: npx gulp test --continue env: diff --git a/.htaccess.dist b/.htaccess.dist index e3ddcd16f5..c9e80a7f6d 100644 --- a/.htaccess.dist +++ b/.htaccess.dist @@ -5,7 +5,7 @@ RewriteEngine On # The following rule tells Apache that if the requested filename # exists, simply serve it. RewriteCond %{REQUEST_FILENAME} -f -RewriteRule !\.(php[0-9]?|phtml|phps)$ - [NC,C] +RewriteRule !\.(php[0-9]?|phtml|phps|phar|hphp)$ - [NC,C] RewriteRule !(?:^|/)\.(?!well-known(?:/.*)?$) - [C] RewriteRule .* - [L] diff --git a/README.md b/README.md index d4d9b30732..7b0ca9cd59 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ See the [user manual](https://omeka.org/s/docs/user-manual) for more information ### Requirements * Linux * [Apache](https://www.apache.org/) (with [AllowOverride](https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride) set to "All" and [mod_rewrite](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) enabled) -* [MySQL](https://www.mysql.com/) 5.6.4+ (or [MariaDB](https://mariadb.org/) 10.0.5+) +* [MySQL](https://www.mysql.com/) 5.7.9+ (or [MariaDB](https://mariadb.org/) 10.2.6+) * [PHP](https://www.php.net/) 7.4+ (latest stable version preferred, with [PDO](http://php.net/manual/en/intro.pdo.php), [pdo_mysql](http://php.net/manual/en/ref.pdo-mysql.php), and [xml](http://php.net/manual/en/intro.xml.php) extensions installed) ### Generating thumbnails diff --git a/application/Module.php b/application/Module.php index af71d4d574..7ff309bcae 100644 --- a/application/Module.php +++ b/application/Module.php @@ -1,13 +1,17 @@ attach( 'Omeka\Entity\Media', - 'entity.persist.post', - [$this, 'saveFulltextOnMediaSave'] - ); - - $sharedEventManager->attach( - 'Omeka\Entity\Media', - 'entity.update.post', - [$this, 'saveFulltextOnMediaSave'] + 'entity.remove.pre', + [$this, 'deleteFulltextMedia'] ); $sharedEventManager->attach( 'Omeka\Api\Adapter\SitePageAdapter', 'api.delete.pre', - [$this, 'deleteFulltextPre'] + [$this, 'deleteFulltextPreSitePage'] ); $sharedEventManager->attach( @@ -178,6 +176,44 @@ public function attachListeners(SharedEventManagerInterface $sharedEventManager) [$this, 'noindexItemSet'] ); + // Add favicon to layouts. + $sharedEventManager->attach( + '*', + 'view.layout', + function (ZendEvent $event) { + $view = $event->getTarget(); + // Get the favicon asset ID. + if ($view->status()->isSiteRequest()) { + $faviconAssetId = $view->siteSetting('favicon'); + if (!is_numeric($faviconAssetId)) { + $faviconAssetId = $view->setting('favicon'); + } + } else { + $faviconAssetId = $view->setting('favicon'); + } + // Get the favicon href. + if (is_numeric($faviconAssetId)) { + $faviconAsset = $view->api()->searchOne('assets', ['id' => $faviconAssetId])->getContent(); + $href = $faviconAsset ? $faviconAsset->assetUrl() : null; + } else { + $href = null; // Passing null clears the favicon. + } + $view->headLink(['rel' => 'icon', 'href' => $href], 'PREPEND'); + } + ); + + $sharedEventManager->attach( + '*', + 'api.output.serialize', + [$this, 'serializeApiOutputJsonLd'] + ); + + $sharedEventManager->attach( + '*', + 'api.output.serialize', + [$this, 'serializeApiOutputRdf'] + ); + $sharedEventManager->attach( '*', 'sql_filter.resource_visibility', @@ -564,34 +600,42 @@ public function saveFulltext(ZendEvent $event) { $adapter = $event->getTarget(); $entity = $event->getParam('response')->getContent(); + $fulltextSearch = $this->getServiceLocator()->get('Omeka\FulltextSearch'); + $fulltextSearch->save($entity, $adapter); + + // Item create needs special handling. We must save media fulltext here + // because media is created via cascade persist (during item create/update), + // which is invisible to normal API events. + if ($entity instanceof Item) { + $mediaAdapter = $adapter->getAdapter('media'); + foreach ($entity->getMedia() as $mediaEntity) { + $fulltextSearch->save($mediaEntity, $mediaAdapter); + } + } + // Item media needs special handling. We must update the item's fulltext + // to append updated media data. if ($entity instanceof Media) { - // Media get special handling during entity.persist.post and - // entity.update.post in self::saveFulltextOnMediaSave(). There's no - // need to process them here. - return; + $itemEntity = $entity->getItem(); + $itemAdapter = $adapter->getAdapter('items'); + $fulltextSearch->save($itemEntity, $itemAdapter); } - $fulltext = $this->getServiceLocator()->get('Omeka\FulltextSearch'); - $fulltext->save($entity, $adapter); } /** - * Save fulltext on media save. + * Delete the fulltext of a media. * - * This method does two things. First, it updates the parent item's fulltext - * to contain any new text introduced by this media. Second it ensures that - * the fulltext of newly created media is saved. Otherwise, media created - * in the item context (via cascade persist) will not have fulltext. + * We must delete media fulltext here because media may be deleted via cascade + * remove (during item update), which is invisible to normal API events. * * @param ZendEvent $event */ - public function saveFulltextOnMediaSave(ZendEvent $event) + public function deleteFulltextMedia(ZendEvent $event) { $fulltextSearch = $this->getServiceLocator()->get('Omeka\FulltextSearch'); $adapterManager = $this->getServiceLocator()->get('Omeka\ApiAdapterManager'); $mediaEntity = $event->getTarget(); - $itemEntity = $mediaEntity->getItem(); - $fulltextSearch->save($mediaEntity, $adapterManager->get('media')); - $fulltextSearch->save($itemEntity, $adapterManager->get('items')); + $mediaAdapter = $adapterManager->get('media'); + $fulltextSearch->delete($mediaEntity->getId(), $mediaAdapter); } /** @@ -603,7 +647,7 @@ public function saveFulltextOnMediaSave(ZendEvent $event) * * @param ZendEvent $event */ - public function deleteFulltextPre(ZendEvent $event) + public function deleteFulltextPreSitePage(ZendEvent $event) { $request = $event->getParam('request'); $em = $this->getServiceLocator()->get('Omeka\EntityManager'); @@ -624,10 +668,24 @@ public function deleteFulltextPre(ZendEvent $event) */ public function deleteFulltext(ZendEvent $event) { - $fulltext = $this->getServiceLocator()->get('Omeka\FulltextSearch'); + $adapter = $event->getTarget(); + $entity = $event->getParam('response')->getContent(); $request = $event->getParam('request'); - $fulltext->delete( - // Note that the resource may not have an ID after being deleted. + $fulltextSearch = $this->getServiceLocator()->get('Omeka\FulltextSearch'); + + // Media delete needs special handling. We must update the item's fulltext + // to remove the appended media data. We return here because deleting media + // fulltext is handled by self::deleteFulltextMedia(). + if ($entity instanceof Media) { + $itemEntity = $entity->getItem(); + $itemAdapter = $adapter->getAdapter('items'); + $fulltextSearch->save($itemEntity, $itemAdapter); + return; + } + + // Note that the resource may not have an ID after being deleted. This + // is why we must use $request->getId() rather than $entity->getId(). + $fulltextSearch->delete( $request->getOption('deleted_entity_id') ?? $request->getId(), $event->getTarget() ); @@ -743,6 +801,99 @@ public function noindexItemSet(ZendEvent $event) $this->noindexResourceShow($view, $view->itemSet); } + /** + * Serialize the API output to JSON-LD. + */ + public function serializeApiOutputJsonLd(ZendEvent $event) + { + $renderer = $event->getTarget(); + $model = $event->getParam('model'); + $format = $event->getParam('format'); + $payload = $event->getParam('payload'); + $output = $event->getParam('output'); + + if ('jsonld' !== $format) { + return; + } + + $eventManager = $this->getServiceLocator()->get('EventManager'); + + if ($payload instanceof RepresentationInterface) { + $args = $eventManager->prepareArgs(['jsonLd' => $output]); + $eventManager->trigger('rep.resource.json_output', $payload, $args); + $output = $args['jsonLd']; + } + + if (null !== $model->getOption('pretty_print')) { + // Pretty print the JSON. + $output = Json::prettyPrint($output); + } + + $jsonpCallback = (string) $model->getOption('callback'); + if (!empty($jsonpCallback)) { + // Wrap the JSON in a JSONP callback. Normally this would be done + // via `$this->setJsonpCallback()` but we don't want to pass the + // wrapped string to `rep.resource.json_output` handlers. + $output = sprintf('%s(%s);', $jsonpCallback, $output); + $renderer->setHasJsonpCallback(true); + } + + $event->setParam('output', $output); + } + + /** + * Serialize the API output to RDF formats (rdfxml, n3, turtle, ntriples). + */ + public function serializeApiOutputRdf(ZendEvent $event) + { + $renderer = $event->getTarget(); + $model = $event->getParam('model'); + $format = $event->getParam('format'); + $payload = $event->getParam('payload'); + $output = $event->getParam('output'); + + if (!in_array($format, ['rdfxml', 'n3', 'turtle', 'ntriples'])) { + return; + } + + $eventManager = $this->getServiceLocator()->get('EventManager'); + + $serializeRdf = function ($jsonLd) use ($format) { + $graph = new Graph; + $graph->parse(Json::encode($jsonLd), 'jsonld'); + return $graph->serialise($format); + }; + + $getJsonLdWithContext = function (RepresentationInterface $representation) use ($eventManager) { + // Add the @context by encoding the output as JSON, then decoding to an array. + static $context; + if (!$context) { + // Get the JSON-LD @context + $args = $eventManager->prepareArgs(['context' => []]); + $eventManager->trigger('api.context', null, $args); + $context = $args['context']; + } + $jsonLd = Json::decode(Json::encode($representation), true); + $jsonLd['@context'] = $context; + return $jsonLd; + }; + + // Render a single representation (get). + if ($payload instanceof RepresentationInterface) { + $jsonLd = $getJsonLdWithContext($payload); + $output = $serializeRdf($jsonLd); + // Render multiple representations (getList); + } elseif (is_array($payload) && array_filter($payload, fn ($object) => ($object instanceof RepresentationInterface))) { + $jsonLd = []; + foreach ($payload as $representation) { + $jsonLd[] = $getJsonLdWithContext($representation); + } + $output = $serializeRdf($jsonLd); + } + + $event->setParam('output', $output); + } + /** * Add a robots "noindex" metatag to the current view if the resource * being viewed does not belong to the current site. diff --git a/application/asset/css/jstree.css b/application/asset/css/jstree.css index 290516bde6..8099fc44db 100755 --- a/application/asset/css/jstree.css +++ b/application/asset/css/jstree.css @@ -1 +1 @@ -.jstree-container-ul{margin:0}.jstree-container-ul,.jstree-container-ul ul{list-style-type:none}.jstree-children{padding-left:36px}.jstree-container-ul,.jstree-container-ul>li{padding-left:0}.jstree-node{position:relative}.jstree-anchor{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px;display:block;margin:6px 0 0}.jstree-editlink-container{display:none;padding:11px;border:1px solid rgba(0,0,0,.04);overflow:hidden;line-height:36px;font-weight:bold}.jstree-editlink-container>label>input,.jstree-editlink-container>label>textarea,.jstree-editlink-container>label>select,.jstree-editlink-container .query-form-element{float:right;width:70%;font-weight:normal}.jstree-editlink-container .query-form-element input{width:100%}.jstree-editlink-container label{display:block}.jstree-editlink-container label:not(:last-child){margin-bottom:6px}.jstree-hovered,.jstree-clicked{background-color:rgba(0,0,0,.12)}i.jstree-icon{font-style:normal;position:absolute;right:12px;top:0}.jstree-icon:before{font-family:"Font Awesome 5 Free";font-weight:900}.jstree-open,.jstree-closed{position:relative}.jstree-open>.jstree-ocl,.jstree-closed>.jstree-ocl,.jstree-removenode-remove,.jstree-removenode-undo,.jstree-editlink-edit,.jstree-displaylink,.jstree-private{width:24px;height:36px;line-height:36px;background-color:rgba(0,0,0,.2);text-align:right;cursor:pointer;z-index:1}.jstree-open>.jstree-ocl,.jstree-closed>.jstree-ocl{width:36px;right:0;text-align:center}i.jstree-icon.jstree-ok,i.jstree-icon.jstree-er{left:100%;width:36px;height:36px;line-height:36px;background-color:rgba(0,0,0,.12);text-align:center}.jstree-removenode-remove,.jstree-removenode-undo,.jstree-editlink-edit,.jstree-displaylink,.jstree-private{background-color:transparent;opacity:.5}.jstree-removenode-remove:hover,.jstree-removenode-undo:hover,.jstree-editlink-edit:hover,.jstree-displaylink:hover,.jstree-private:hover{opacity:1}.jstree-private{color:#676767}.jstree-private:hover{opacity:.5}.jstree-open>.jstree-anchor .jstree-removenode-remove,.jstree-closed>.jstree-anchor .jstree-removenode-remove,.jstree-open>.jstree-anchor .jstree-removenode-undo,.jstree-closed>.jstree-anchor .jstree-removenode-undo{right:48px}.jstree-open>.jstree-anchor .jstree-editlink-edit,.jstree-closed>.jstree-anchor .jstree-editlink-edit{right:72px}i.jstree-editlink-edit{right:36px}i.jstree-private{background-color:transparent;position:static;display:inline-block;margin-right:6px;height:16px;line-height:1}.jstree-open>.jstree-anchor .jstree-displaylink,.jstree-closed>.jstree-anchor .jstree-displaylink{right:96px}i.jstree-displaylink{right:60px}.block-pagelist-tree .jstree-open>.jstree-anchor .jstree-displaylink,.block-pagelist-tree .jstree-closed>.jstree-anchor .jstree-displaylink{right:72px}.block-pagelist-tree i.jstree-displaylink{right:36px}.jstree-anchor:hover>.jstree-removenode-remove{display:block}.jstree-open>.jstree-ocl:before{content:""}.jstree-closed>.jstree-ocl:before{content:""}.jstree-ok:before{content:""}.jstree-er:before{content:""}.jstree-removenode-remove:before{content:""}.jstree-removenode-undo:before{content:""}.jstree-editlink-edit:before{content:""}.jstree-displaylink:before{content:""}.jstree-private:before{content:""}.jstree-removenode-removed .jstree-anchor{background-color:#fcc}.jstree-removenode-removed .jstree-children .jstree-removenode-remove,.jstree-removenode-removed .jstree-children .jstree-removenode-undo{display:none}.jstree-removenode-removed.jstree-open>.jstree-ocl,.jstree-removenode-removed.jstree-closed>.jstree-ocl{background-color:rgba(255,0,0,.24)}.jstree-editlink-editmode>.jstree-anchor .jstree-editlink-edit{opacity:.35}#jstree-marker{position:absolute;top:0;left:0;margin:-5px 0 0 0;padding:0;border-right:0;border-top:5px solid rgba(0,0,0,0);border-bottom:5px solid rgba(0,0,0,0);border-left:5px solid;width:0;height:0;font-size:0;line-height:0}#jstree-dnd{z-index:1;padding:6px 12px;background-color:rgba(0,0,0,.04);line-height:24px} \ No newline at end of file +.jstree-container-ul{margin:0}.jstree-container-ul,.jstree-container-ul ul{list-style-type:none}.jstree-children{padding-left:36px}.jstree-container-ul,.jstree-container-ul>li{padding-left:0}.jstree-node{position:relative}.jstree-anchor{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px;display:block;margin:6px 0 0}.jstree-editlink-container{display:none;padding:11px;border:1px solid rgba(0,0,0,.04);overflow:hidden;line-height:36px;font-weight:bold}.jstree-editlink-container>label>input,.jstree-editlink-container>label>textarea,.jstree-editlink-container>label>select,.jstree-editlink-container .query-form-element{float:right;width:70%;font-weight:normal}.jstree-editlink-container .query-form-element input{width:100%}.jstree-editlink-container label{display:block}.jstree-editlink-container label:not(:last-child){margin-bottom:6px}.value .jstree-editlink-container label{line-height:36px}.jstree-hovered,.jstree-clicked{background-color:rgba(0,0,0,.12)}i.jstree-icon{font-style:normal;position:absolute;right:12px;top:0}.jstree-icon:before{font-family:"Font Awesome 5 Free";font-weight:900}.jstree-open,.jstree-closed{position:relative}.jstree-open>.jstree-ocl,.jstree-closed>.jstree-ocl,.jstree-removenode-remove,.jstree-removenode-undo,.jstree-editlink-edit,.jstree-displaylink,.jstree-private{width:24px;height:36px;line-height:36px;background-color:rgba(0,0,0,.2);text-align:right;cursor:pointer;z-index:1}.jstree-open>.jstree-ocl,.jstree-closed>.jstree-ocl{width:36px;right:0;text-align:center}i.jstree-icon.jstree-ok,i.jstree-icon.jstree-er{left:100%;width:36px;height:36px;line-height:36px;background-color:rgba(0,0,0,.12);text-align:center}.jstree-removenode-remove,.jstree-removenode-undo,.jstree-editlink-edit,.jstree-displaylink,.jstree-private{background-color:transparent;opacity:.5}.jstree-removenode-remove:hover,.jstree-removenode-undo:hover,.jstree-editlink-edit:hover,.jstree-displaylink:hover,.jstree-private:hover{opacity:1}.jstree-private{color:#676767}.jstree-private:hover{opacity:.5}.jstree-open>.jstree-anchor .jstree-removenode-remove,.jstree-closed>.jstree-anchor .jstree-removenode-remove,.jstree-open>.jstree-anchor .jstree-removenode-undo,.jstree-closed>.jstree-anchor .jstree-removenode-undo{right:48px}.jstree-open>.jstree-anchor .jstree-editlink-edit,.jstree-closed>.jstree-anchor .jstree-editlink-edit{right:72px}i.jstree-editlink-edit{right:36px}i.jstree-private{background-color:transparent;position:static;display:inline-block;margin-right:6px;height:16px;line-height:1}.jstree-open>.jstree-anchor .jstree-displaylink,.jstree-closed>.jstree-anchor .jstree-displaylink{right:96px}i.jstree-displaylink{right:60px}.block-pagelist-tree .jstree-open>.jstree-anchor .jstree-displaylink,.block-pagelist-tree .jstree-closed>.jstree-anchor .jstree-displaylink{right:72px}.block-pagelist-tree i.jstree-displaylink{right:36px}.jstree-anchor:hover>.jstree-removenode-remove{display:block}.jstree-open>.jstree-ocl:before{content:""}.jstree-closed>.jstree-ocl:before{content:""}.jstree-ok:before{content:""}.jstree-er:before{content:""}.jstree-removenode-remove:before{content:""}.jstree-removenode-undo:before{content:""}.jstree-editlink-edit:before{content:""}.jstree-displaylink:before{content:""}.jstree-private:before{content:""}.jstree-removenode-removed .jstree-anchor{background-color:#fcc}.jstree-removenode-removed .jstree-children .jstree-removenode-remove,.jstree-removenode-removed .jstree-children .jstree-removenode-undo{display:none}.jstree-removenode-removed.jstree-open>.jstree-ocl,.jstree-removenode-removed.jstree-closed>.jstree-ocl{background-color:rgba(255,0,0,.24)}.jstree-editlink-editmode>.jstree-anchor .jstree-editlink-edit{opacity:.35}#jstree-marker{position:absolute;top:0;left:0;margin:-5px 0 0 0;padding:0;border-right:0;border-top:5px solid rgba(0,0,0,0);border-bottom:5px solid rgba(0,0,0,0);border-left:5px solid;width:0;height:0;font-size:0;line-height:0}#jstree-dnd{z-index:1;padding:6px 12px;background-color:rgba(0,0,0,.04);line-height:24px} \ No newline at end of file diff --git a/application/asset/css/page-blocks.css b/application/asset/css/page-blocks.css index 327bb7be72..db300d6456 100644 --- a/application/asset/css/page-blocks.css +++ b/application/asset/css/page-blocks.css @@ -1 +1 @@ -.item-showcase{margin:1rem 0;border-top:1px solid #dfdfdf;border-bottom:1px solid #dfdfdf;padding:calc(1rem - 1px) 0 0;overflow:hidden;text-align:center;clear:both;display:flex;flex-wrap:wrap;justify-content:center}.item.resource .caption{font-size:.875rem;line-height:1.5rem}.item.resource .caption *{margin:0 0 1rem 0}.item.resource .caption>*:last-child{margin-bottom:0}.item-showcase .resource.item{vertical-align:top;margin-bottom:1rem}.item-showcase .resource.item img{margin-right:.5rem;max-width:100%}.item-showcase .resource.item:only-child img{margin:0 auto}.item-showcase .resource.item:not(:only-child){width:25%;clear:none;padding:0 .5rem}.item-showcase .resource.item:not(:only-child) h3{clear:left;font-size:1rem;line-height:1.5rem;margin:.5rem 0 0}.item-showcase .resource.item:not(:only-child) img{max-height:7rem;width:auto;float:none;margin-right:0;vertical-align:top}.right,.left{overflow:hidden;max-width:33.33%}.left .item.resource,.right .item.resource{margin:0 0 1rem 0}.left .item.resource:first-of-type,.right .item.resource:first-of-type{padding-top:calc(1rem - 1px);margin-top:0}.left .item.resource:last-of-type,.right .item.resource:last-of-type{padding-bottom:-1px}.left .item.resource .media-render a,.right .item.resource .media-render a{display:block}.left .item.resource audio,.left .item.resource canvas,.left .item.resource video,.left .item.resource progress,.left .item.resource img,.right .item.resource audio,.right .item.resource canvas,.right .item.resource video,.right .item.resource progress,.right .item.resource img{max-width:100%;vertical-align:bottom;margin-bottom:.5rem}.file{border-top:1px solid #dfdfdf;border-bottom:1px solid #dfdfdf;margin-top:1rem;margin-bottom:1rem}.left.file,.left.assets{float:left;clear:left;margin:0 1rem 1rem 0}.right.file,.right.assets{float:right;clear:right;margin:0 0 1rem 1rem}.center.file,.center.assets{display:flex;justify-content:center;flex-wrap:wrap;text-align:center}.center.file .item,.center.assets .item{width:100%}.left .item.resource>a:first-child,.right .item.resource>a:first-child{vertical-align:top}.medium .item.resource>h3,.square .item.resource>h3{font-size:16px;line-height:1.5rem}.left .item.resource>h3,.right .item.resource>h3{margin:0}.left .item.resource+p,.right .item.resource+p{margin-top:0}.break{width:100%;clear:both;border-bottom:1px solid #dfdfdf;padding-bottom:-1px;margin:1rem 0}.break.transparent{border-color:transparent}.break.opaque{border-color:#dfdfdf}.preview-block{margin:1rem 0;overflow:hidden;width:100%;clear:both}.toc-block>ul{margin:1rem 0;list-style-type:none;border-left:5px solid #dfdfdf}.toc-block>ul>li{margin-bottom:.5rem}.toc-block>ul>li>a{font-weight:bold}.toc-block ul ul{list-style-type:none;padding-left:0}.toc-block ul ul ul{padding-left:1.25em}.toc-block ul ul li:before{content:"—";color:#dfdfdf}.item-with-metadata{width:100%;overflow:hidden;margin:1rem 0}.item-with-metadata .show.resource{margin:2rem 0}.list-of-sites .site-list .site{margin-bottom:.5rem;overflow:auto}.list-of-sites .site-list .site-link{display:inline-block;font-size:1.25rem;margin-bottom:.25rem}.list-of-sites .site-list .site-summary{margin:0 0 .25rem 0;line-height:20px}.list-of-sites .site-list .site-thumbnail-image{max-width:25%;float:left;margin-right:1rem}.assets .asset,.assets .asset img{max-width:100%;height:auto}.assets .asset{margin-bottom:1rem}.assets .link-title{display:block;font-size:1.25rem;font-weight:bold}.page-date-time{margin:1rem 0}.page-date-time .property{font-weight:bold}.page-date-time .property:after{content:": "}.page-date-time>div,.page-date-time .property,.page-date-time .value{display:inline-block;margin:0} \ No newline at end of file +.block-layout-background-position-y-top{background-position-y:top}.block-layout-background-position-y-center{background-position-y:center}.block-layout-background-position-y-bottom{background-position-y:bottom}.block-layout-background-position-x-left{background-position-x:left}.block-layout-background-position-x-center{background-position-x:center}.block-layout-background-position-x-right{background-position-x:right}.page-layout-normal .block-layout-alignment-right,.page-layout-normal .block-layout-alignment-left{overflow:hidden;max-width:33.33%}.block-layout-alignment-left .item.resource,.block-layout-alignment-right .item.resource{margin:0 0 1rem 0}.block-layout-alignment-left .item.resource:first-of-type,.block-layout-alignment-right .item.resource:first-of-type{padding-top:calc(1rem - 1px);margin-top:0}.block-layout-alignment-left .item.resource:last-of-type,.block-layout-alignment-right .item.resource:last-of-type{padding-bottom:-1px}.block-layout-alignment-left .item.resource .media-render a,.block-layout-alignment-right .item.resource .media-render a{display:block}.block-layout-alignment-left .item.resource audio,.block-layout-alignment-left .item.resource canvas,.block-layout-alignment-left .item.resource video,.block-layout-alignment-left .item.resource progress,.block-layout-alignment-left .item.resource img,.block-layout-alignment-right .item.resource audio,.block-layout-alignment-right .item.resource canvas,.block-layout-alignment-right .item.resource video,.block-layout-alignment-right .item.resource progress,.block-layout-alignment-right .item.resource img{max-width:100%;vertical-align:bottom;margin-bottom:.5rem}.block-layout-alignment-left{float:left;clear:left;margin:0 1rem 1rem 0}.block-layout-alignment-right{float:right;clear:right;margin:0 0 1rem 1rem}.block-layout-alignment-center{display:flex;justify-content:center;flex-wrap:wrap;text-align:center}.block-layout-alignment-center .item{width:100%}.block-layout-alignment-left .item.resource>a:first-child,.block-layout-alignment-right .item.resource>a:first-child{vertical-align:top}.block-layout-alignment-left .item.resource>h3,.block-layout-alignment-right .item.resource>h3{margin:0}.block-layout-alignment-left .item.resource+p,.block-layout-alignment-right .item.resource+p{margin-top:0}.block-layout-background-size-cover,.block-layout-background-size-contain{background-repeat:no-repeat}.block-layout-background-size-cover{background-size:cover}.block-layout-background-size-contain{background-size:contain}.item-showcase{margin:1rem 0;border-top:1px solid #dfdfdf;border-bottom:1px solid #dfdfdf;padding:calc(1rem - 1px) 0 0;overflow:hidden;text-align:center;clear:both;display:flex;flex-wrap:wrap;justify-content:center}.item.resource .caption{font-size:.875rem;line-height:1.5rem}.item.resource .caption *{margin:0 0 1rem 0}.item.resource .caption>*:last-child{margin-bottom:0}.item-showcase .resource.item{vertical-align:top;margin-bottom:1rem}.item-showcase .resource.item img{margin-right:.5rem;max-width:100%}.item-showcase .resource.item:only-child img{margin:0 auto}.item-showcase .resource.item:not(:only-child){width:25%;clear:none;padding:0 .5rem}.item-showcase .resource.item:not(:only-child) h3{clear:left;font-size:1rem;line-height:1.5rem;margin:.5rem 0 0}.item-showcase .resource.item:not(:only-child) img{max-height:7rem;width:auto;float:none;margin-right:0;vertical-align:top}.file{border-top:1px solid #dfdfdf;border-bottom:1px solid #dfdfdf;margin-top:1rem;margin-bottom:1rem}.medium .item.resource>h3,.square .item.resource>h3{font-size:16px;line-height:1.5rem}.break{width:100%;clear:both;border-bottom:1px solid #dfdfdf;padding-bottom:-1px;margin:1rem 0}.break.transparent{border-color:transparent}.break.opaque{border-color:#dfdfdf}.preview-block{margin:1rem 0;overflow:hidden;width:100%;clear:both}.toc-block>ul{margin:1rem 0;list-style-type:none;border-left:5px solid #dfdfdf}.toc-block>ul>li{margin-bottom:.5rem}.toc-block>ul>li>a{font-weight:bold}.toc-block ul ul{list-style-type:none;padding-left:0}.toc-block ul ul ul{padding-left:1.25em}.toc-block ul ul li:before{content:"—";color:#dfdfdf}.item-with-metadata{width:100%;overflow:hidden;margin:1rem 0}.item-with-metadata .show.resource{margin:2rem 0}.list-of-sites .site-list .site{margin-bottom:.5rem;overflow:auto}.list-of-sites .site-list .site-link{display:inline-block;font-size:1.25rem;margin-bottom:.25rem}.list-of-sites .site-list .site-summary{margin:0 0 .25rem 0;line-height:20px}.list-of-sites .site-list .site-thumbnail-image{max-width:25%;float:left;margin-right:1rem}.assets .asset,.assets .asset img{max-width:100%;height:auto}.assets .asset{margin-bottom:1rem}.assets .link-title{display:block;font-size:1.25rem;font-weight:bold}.page-date-time{margin:1rem 0}.page-date-time .property{font-weight:bold}.page-date-time .property:after{content:": "}.page-date-time>div,.page-date-time .property,.page-date-time .value{display:inline-block;margin:0} \ No newline at end of file diff --git a/application/asset/css/page-grid.css b/application/asset/css/page-grid.css new file mode 100644 index 0000000000..6e8d8a1729 --- /dev/null +++ b/application/asset/css/page-grid.css @@ -0,0 +1 @@ +.page-layout-grid{display:grid}.page-layout-grid>div{min-height:50px}@media screen and (max-width: 896px){.page-layout-grid{display:block}} \ No newline at end of file diff --git a/application/asset/css/style.css b/application/asset/css/style.css index 15ef100b51..7b1b84dd89 100644 --- a/application/asset/css/style.css +++ b/application/asset/css/style.css @@ -1 +1 @@ -/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}template,[hidden]{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}@media screen{*{box-sizing:border-box}em,i{font-style:italic}strong,b{font-weight:bold}a{text-decoration:none}a:link,a:visited{color:#a91919}a:active,a:hover{color:#e34545}h1,h2,h3,h4,h5,h6{margin:0}h3,h4,h5,h6{font-weight:bold}h1{font-size:32px;line-height:48px;margin-bottom:24px}h2{font-size:30px;line-height:36px;margin-bottom:24px}h3{font-size:24px;margin-bottom:24px}h5{font-size:14px}p{margin:24px 0}ul{padding-left:24px;list-style:disc}pre{max-width:100%;overflow-x:auto}html,body{height:100%}body{font-family:"Lato",sans-serif;font-size:16px;line-height:24px;color:#676767;overflow-x:hidden}table{width:100%;border-spacing:0;table-layout:fixed}th,table.tablesaw th{font-weight:bold;text-align:left;padding:6px .5em}table,table.tablesaw{margin-bottom:12px;border:1px solid #dfdfdf;border-radius:3px;border-collapse:separate}.tablesaw tr:not(:last-child) td{border-bottom:1px solid #dfdfdf}tr.delete{background-color:#fcc}td,table.tablesaw td{padding:6px .5em 5px;position:relative;vertical-align:middle}table.tablesaw td:first-child a{word-wrap:break-word}table.tablesaw thead tr:first-child th{padding-top:6px;padding-bottom:5px;border-bottom:1px solid #dfdfdf}legend{font-size:20px;padding:12px 0;font-weight:bold}[contenteditable=true],textarea{clear:both;padding:6px;border:1px solid rgba(0,0,0,.15);display:block;background-color:#fff;min-height:72px;overflow-y:auto}[contenteditable=true] p{margin:12px 0}.cke_dialog_body textarea{max-height:none}input,[contenteditable=true],textarea,button,select{font-family:"Lato",sans-serif;font-size:16px;line-height:24px;margin:0;color:#676767}input[type=text],input[type=password],input[type=email],input[type=url],input[type=number],input[type=date],input[type=datetime-local]{-webkit-appearance:none;appearance:none;border-radius:0;height:36px;border:1px solid rgba(0,0,0,.15);padding:6px;margin:0}:disabled{background-color:rgba(0,0,0,.04);box-shadow:0 0 0 1px rgba(0,0,0,.15) inset;color:#a7a7a7;-webkit-text-fill-color:#a7a7a7;cursor:default}:disabled:hover{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset !important}::placeholder{font-style:italic}[contenteditable=true]>*:first-child{margin-top:0}[contenteditable=true]>*:last-child{margin-bottom:0}input[type=submit],button,a.button,.button{min-height:36px;background-color:rgba(0,0,0,.08);color:#676767;border-radius:3px;border:0;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset;padding:6px 10px;display:inline-block;text-align:center;cursor:pointer;margin:0 0 12px 0}input[type=submit]:hover:not(.inactive),button:hover:not(.inactive),a.button:hover:not(.inactive),.button:hover:not(.inactive){box-shadow:0 0 0 1px rgba(0,0,0,.3) inset}input[type=submit].inactive,button.inactive,a.button.inactive,.button.inactive{box-shadow:none;background-color:#d2d2d2;cursor:default;border:0}.red.button{background-color:#fdefef;box-shadow:0 0 0 1px #e0c3c3 inset;color:#a91919}.red.button:hover{box-shadow:0 0 0 1px #da8b8b inset}.green.button{background-color:#cdffcd;color:green;box-shadow:0 0 0 1px #addead inset}.green.button:hover{box-shadow:0 0 0 1px #63c363 inset}.required .field-meta{position:relative;padding-right:36px}.required .field-meta:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";font-size:12px;position:absolute;right:12px;color:#a91919;top:6px}label input[type=checkbox]{display:inline-block;width:auto}label.required:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";font-size:12px;color:#a91919;float:right;padding-right:12px}.touched:invalid{box-shadow:0 0 2px 2px #a91919}.field{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px;display:flex;flex-wrap:wrap}.field:first-child{border-color:transparent}.media-field-wrapper{width:100%;padding:12px 6px;margin-bottom:6px;background-color:rgba(0,0,0,.04);position:relative}.media-field-wrapper .field{width:100%;margin:0 0 6px;padding:0;background-color:transparent}.media-field-wrapper .field:last-of-type{margin-bottom:0}.media-field-wrapper .field:last-of-type .field-meta,.media-field-wrapper .field:last-of-type .inputs{margin-bottom:-6px}.media-field-wrapper .actions{font-size:16px;padding:6px 0}select{background:#fff url("../img/select-arrow.svg") no-repeat;background-position:right 6px center;background-size:8px;border:1px solid #dfdfdf;height:36px;line-height:36px;font-size:16px;margin:0;padding:0 24px 0 6px;border-radius:3px;vertical-align:top;-webkit-appearance:none;appearance:none}select::-ms-expand{display:none}label input{margin-right:.5em}fieldset{margin:0 0 24px;border:0;padding:0;min-width:100%}.selector input[type=text],.selector>ul{width:100%}.selector>ul{margin:0}.chosen-container{max-width:100%}.chosen-container-single .chosen-single,.chosen-container-multi .chosen-choices{background-image:none;background-color:#fff;box-shadow:none;font-size:16px;line-height:24px;padding:6px;height:auto;border-radius:3px;border-collapse:#dfdfdf;color:#676767;border-color:#dfdfdf}.chosen-container-multi.chosen-container-active .chosen-choices{border-color:#aaa;border-radius:3px 3px 0 0}.chosen-container-multi.chosen-container.chosen-drop-up .chosen-choices{border-radius:0 0 3px 3px}.chosen-container-multi.chosen-container .chosen-drop{top:calc(100% - 1px);border-top:1px solid #aaa}.chosen-container-multi.chosen-container.chosen-drop-up .chosen-drop{bottom:calc(100% - 1px)}.chosen-container-multi .chosen-choices{padding:3px}.chosen-container-multi .chosen-choices li.search-field input[type=text]{font-family:"Lato",sans-serif;margin:0}.chosen-container-multi .chosen-choices li.search-choice{background:#f0f0f0;font-size:14px;line-height:24px;border:0;padding:0 27px 0 0}.chosen-container-multi .chosen-choices li.search-choice span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;display:block}.chosen-container .search-choice .group-name{color:#676767;position:relative;background-color:rgba(0,0,0,.04);margin-right:6px;padding:0 6px;display:inline-block;vertical-align:top}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{top:50%;right:6px;transform:translateY(-50%)}.chosen-container .search-choice .group-name:after{content:""}.chosen-container-multi .chosen-choices li.search-field input[type=text]{min-height:0;margin:3px;height:auto;line-height:24px}.chosen-container-active.chosen-with-drop .chosen-single{background-image:none}.chosen-container-single .chosen-single abbr{top:12px}.chosen-container-single .chosen-single div b{background:none !important}.chosen-container-single .chosen-single div b:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";line-height:24px;padding:6px 0;display:inline-block}.chosen-container-active.chosen-with-drop .chosen-single div b:after{content:""}.chosen-container-single .chosen-search input[type=text]{background:none !important}.chosen-search{position:relative}.chosen-search:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";line-height:24px;padding:6px 0;display:block;position:absolute;top:3px;right:12px}.chosen-container .chosen-results li.highlighted{background-color:#676767;background-image:none}.chosen-container.chosen-drop-up .chosen-drop{top:auto;bottom:100%;border-radius:3px 3px 0 0;box-shadow:0 -1px 2px rgba(0,0,0,.15);border-top:1px solid #aaa}.chosen-container-active.chosen-drop-up.chosen-with-drop .chosen-single{border-radius:0 0 3px 3px}.flex{display:flex}.mobile-only{display:none}.sr-only{left:-9999px}div[role=main]>.messages{margin-bottom:12px}div[role=main]>.messages li{margin:0 0 6px}div[role=main]>.messages .error{background-color:#f4b4b4}div[role=main]>.messages .success{background-color:#cdffcd}div[role=main]>.messages .warning{background-color:#fff6e6}div[role=main]>.messages a{text-decoration:underline}.messages{padding:0;margin:0;clear:both}.messages li{background-color:rgba(255,255,255,.5);border-radius:3px;padding:6px 10px;margin-top:6px;display:block;width:100%}.field .messages{width:70%;color:#a91919;margin-left:auto}.field .messages li{box-shadow:0 0 0 1px inset}.error,.error a{color:#a91919}.success,.success a{color:green}.warning,.warning a{color:orange}.version-notification{background-color:#cdffcd;color:green;border-radius:3px;padding:6px 10px;margin-top:6px;display:block;width:100%}.version-notification a{color:green;text-decoration:underline}table .icon-sortable{opacity:.4;font-size:12px;line-height:100%}.row{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px}.row.delete{background-color:#fcc;overflow:hidden}.jstree-themeicon,.sortable-handle{cursor:move;margin-right:12px;width:18px}.jstree-themeicon:before,.sortable-handle:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;opacity:.35;font-size:20px;line-height:24px}.jstree i.jstree-themeicon{color:#676767;position:static;top:auto;right:auto}.o-description{margin-bottom:0}a.expand,a.collapse{color:#676767}.expand:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;margin-left:3px}.collapse:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;margin-left:3px}.selector-table{display:table}.selector-table.empty,.selector-table+.no-resources{display:none}.selector-table.empty+.no-resources{display:block}.selector .resources-available.empty,.selector .resources-available+.resources-unavailable{display:none}.selector .resources-available.empty+.resources-unavailable{display:block}.selector .selector-child.filter-hidden,.selector .selector-child.added{display:none}header{background-color:#404e61;width:18.75%;min-height:100vh;text-align:left;padding:0 1.0416666667% 24px;color:#bdcde3}.skip{position:absolute;left:-9999px}.skip:focus{position:absolute;top:0;left:45%;width:10%;z-index:1002;text-align:center;background-color:#fff;border-radius:0 0 3px 3px;border:1px solid #dfdfdf;padding:5px}.logo a,#user a{color:#bdcde3}#user{color:#fff;padding-top:12px;margin-bottom:-6px;display:flex;flex-wrap:wrap}#user p{margin:0 0 6px;display:inline-flex;vertical-align:top}#user .user-id{text-transform:uppercase;font-size:12px;margin-right:auto}#user .user-id a.button{display:inline-block;font-size:12px;text-transform:none;margin-bottom:0;background-color:#222933;padding:0 6px;min-height:0;border:0}#user .user-show{border-radius:3px 0 0 3px;margin-right:1px;display:inline-flex;max-width:85%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}#user .user-show:before{margin-right:6px}#user .user-settings{border-radius:0 3px 3px 0;border-left:0}#user .user-settings:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}#user .logout{font-size:12px;padding:0 6px;background-color:#222933;border-radius:3px;display:inline-block;min-width:25%;text-align:center}.logo{padding:6px 6.25%;margin:0 -6.25%;background-color:#222933}#search{width:100%;display:inline-block;vertical-align:top;margin:24px 0}#search input[type=text]{width:calc(100% - 72px);float:left}#search button{width:36px;text-indent:-9999px;background-color:#222933;color:#bdcde3;border:0;float:left;margin:0;border-radius:0;position:relative;height:36px;box-shadow:none}#search button:last-of-type{border-left:1px solid rgba(255,255,255,.2);border-radius:0 3px 3px 0}#search button:last-of-type:after{content:""}#search button:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;text-indent:0;position:absolute;top:0;left:0;width:36px;line-height:36px;text-align:center}#advanced-options{display:none}div[role=main]>h1:first-of-type{background-color:#fff;font-size:24px;position:fixed;padding:3px 30% 3px 1.0416666667%;z-index:3;top:0;right:0;width:81.25%;height:48px;border-bottom:1px solid #dfdfdf;overflow:hidden;line-height:36px}div[role=main]>h1:first-of-type .title{text-overflow:ellipsis;white-space:nowrap;max-width:65%;display:inline-block;overflow:hidden;vertical-align:middle}.subhead{text-transform:uppercase;font-size:14px;padding:0 6px;background-color:#eee;line-height:36px;vertical-align:middle;margin:0 12px 0 0;font-weight:normal;display:inline-block}.subhead:before{font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-right:6px;font-size:16px;vertical-align:top}.action{display:inline-block;vertical-align:middle}.action:before{content:"·";margin:0 12px}.sidebar-open footer{margin-right:25%}footer{font-size:12px;position:relative;margin-top:-27px;margin-left:18.75%;padding-right:1.0416666667%;text-align:right}footer .site-version{margin:0;display:inline-block}footer .version-number{display:inline-block;margin:0 12px;line-height:1}body.transitions-enabled footer{transition:margin-right .5s}footer>a:not(:last-child){margin-right:12px}nav ul{padding:0;list-style:none;margin:0}nav.pagination{margin-bottom:12px;overflow:hidden}nav.pagination form,nav.pagination .button,nav.pagination .row-count{float:left}nav.pagination form{margin-right:12px}nav.pagination form *{display:inline-block;padding:0;text-align:center}nav.pagination .button{border-radius:0;margin:0;padding:0 10px}nav.pagination .button,nav.pagination input[type=text],.sorting button,.sorting select{font-size:13.08px;min-height:0;height:24px;line-height:24px;vertical-align:top;background-size:6.5408px}nav.pagination .button{box-shadow:0 0 0 1px #c8c8c8 inset;position:relative}nav.pagination .button:hover{z-index:1}nav.pagination .button:before{vertical-align:top;line-height:24px}nav.pagination .previous.button{border-radius:3px 0 0 3px}nav.pagination .next.button{border-radius:0 3px 3px 0;margin-left:-1px}nav.pagination form input[type=text]{margin-right:.25em;width:48px;border:1px solid #dfdfdf;padding:5px}nav.pagination+*:not(.sorting){clear:left}#mobile-nav{display:none}.mobile-container{position:relative}button .o-icon-private{margin:0 6px;color:#dfdfdf}header nav h4{padding-bottom:5px;border-bottom:1px solid #364252;margin-bottom:6px}header nav h4:not(:first-of-type){margin-top:24px}header nav ul.navigation>li:not(:first-of-type){margin-top:6px}header nav ul.navigation>li:not(:last-of-type){border-color:#dfdfdf}header nav ul.navigation li li{display:none}header nav ul.navigation li.active li{display:block;margin-left:24px}header nav ul.navigation li.active>a{color:#fff}header nav a:link,header nav a:visited{color:#bdcde3}header nav li>a:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;width:24px}header nav .items:before,.items .subhead:before{content:""}header nav .media:before,.media .subhead:before{content:""}header nav .item-sets:before,.item-sets .subhead:before{content:""}header nav .vocabularies:before,.vocabularies .subhead:before{content:""}header nav .resource-templates:before,.resource-templates .subhead:before{content:""}header nav .users:before,.users .subhead:before{content:""}header nav .modules:before,.modules .subhead:before{content:""}header nav .jobs:before,.jobs .subhead:before{content:""}header nav .sites:before,.sites .subhead:before{content:""}header nav .settings:before,.settings .subhead:before{content:""}header nav .assets:before,.assets .subhead:before{content:""}header nav li li a:before{content:""}header ul.navigation{margin-bottom:6px}#menu{position:relative}#menu h5{text-transform:uppercase;border-top:1px solid #364252;padding-top:5px;margin-bottom:0}#menu .expand,#menu .collapse{width:100%;z-index:1;padding-bottom:6px;margin-bottom:6px}#site-nav{background-color:#364252;padding:6px;margin-bottom:12px;border-radius:3px}#site-nav h5{border-top:0;border-bottom:1px solid #2c3542;padding:0 24px 5px 0;margin-bottom:6px}header nav#site-nav h5 a:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;width:24px;display:inline-block;font-size:16px}#menu .pages:before,.site-pages .subhead:before{content:""}#menu a.navigation:before{content:""}#menu a.public{float:right;text-align:right;font-size:16px;line-height:30px;margin-top:-39px}#menu a.resources:before{content:""}#menu a.site-info:before{content:""}#menu a.theme:before,.theme-settings .subhead:before{content:""}div[role=main]{width:81.25%;padding:60px 1.0416666667% 36px;background-color:#fff;min-height:100%;overflow:hidden}body.transitions-enabled div[role=main]{transition:width .5s}#dashboard>p{width:100%;margin-top:12px}#manage-resources .add.button:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}.panel{width:48.9583333333%;float:left;padding-left:1.0416666667%;padding-right:1.0416666667%;border:1px solid #dfdfdf;padding:5px;margin:0 1.0416666667% 0 0;float:left;overflow:hidden}.panel .row{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px}.panel>.row:last-child{margin-bottom:0}.panel .button{float:right;margin:0}.panel .row a.button{box-shadow:none;padding:0;color:#a91919;background-color:transparent}.panel h2{font-size:18px;line-height:24px;margin-bottom:6px}.browse .add.button,.browse .batch-edit.button{float:left;margin-right:.25em}.browse td:first-child,.browse th:first-child{width:50%}.browse td,.browse th{padding:12px 6px;overflow:hidden}.browse .browse-controls{display:flex;justify-content:space-between;flex-wrap:wrap;font-size:13.08px}.sites.pages.browse .browse-controls{justify-content:flex-end}.browse .browse-controls .advanced-search:before{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;font-style:normal;font-variant:normal;font-weight:normal;line-height:1;font-family:"Font Awesome 5 Free";font-weight:900;content:"";padding:.25em}.browse-controls select,.browse-controls input,.browse-controls button,.browse-controls .button{font-size:13.08px;min-height:0;height:24px;line-height:24px;vertical-align:top;background-size:6.5408px}.browse-controls .sorting:not(:last-child){margin-left:auto}.browse-controls button,.browse-controls .button{padding:0 10px}.browse-controls .filtering{margin-left:24px}.browse .select-all{width:12px;margin-right:12px}.browse .tablesaw-cell-content,#properties .tablesaw-cell-content{display:flex;align-items:center;justify-content:flex-start;word-wrap:break-word}.browse .tablesaw-cell-content>.actions,#properties .tablesaw-cell-content>.actions{white-space:nowrap}.browse .batch-edit .tablesaw-cell-content>input[type=checkbox]{margin-right:12px;flex-shrink:0}.browse .tablesaw-cell-content>span.indent{display:inline-block;vertical-align:top;flex:0;min-width:1em}.actions{margin:0 0 0 auto;display:flex;padding:0}.actions li{list-style-type:none}.actions a,.actions a:before,.actions button,.actions button:before{width:24px;height:24px;line-height:24px;vertical-align:top;border:0;box-shadow:none;display:inline-block}.actions .button:hover,.actions button:hover{box-shadow:none !important}.actions a,.actions button{opacity:.5}.actions a:before,.actions button:before{text-align:right}.actions a:hover,.actions a:active,.actions button:hover{opacity:1}.actions .inactive{display:none}.actions button{background-color:transparent;color:#a91919;margin:0;text-indent:-9999px;position:relative;padding:0;min-height:0}.actions button:before{text-indent:0;position:absolute;top:0;left:0}.row-count{margin:0 6px}.no-resources{text-align:center;position:relative;margin-top:96px}.no-resources:before{font-family:"Font Awesome 5 Free";font-weight:900;font-size:96px;position:absolute;top:0;left:0;width:100%;opacity:.08;content:""}.no-resources p{font-size:24px;line-height:48px;margin-top:48px}td .o-icon-private,td .o-icon-user-inactive{display:inline-block;vertical-align:bottom;margin-left:.5em;opacity:.5}.items .no-resources:before{content:""}.item-sets .no-resources:before{content:""}.media .no-resources:before,#media-list .no-resources:before{content:""}.modules .no-resources:before{content:""}.vocabs .no-resources:before{content:""}.resource-templates .no-resources:before,.resources-templates{content:""}.users .no-resources:before{content:""}.jobs .no-resources:before{content:""}.sites .no-resources:before{content:""}.sidebar .no-resources{display:block}.browse.assets td:first-child,.browse.assets th:first-child{width:75%}.asset-inline{max-width:100%}#batch-form{border:1px solid #dfdfdf;border-bottom:0;border-radius:3px;margin-bottom:12px}#batch-form table.tablesaw{border-width:1px 0;border-radius:0 0 3px 3px;margin-bottom:0}#batch-form .batch-actions{display:inline-block}#batch-form .batch-inputs{display:flex;align-items:center;padding:6px;background-color:rgba(0,0,0,.04)}#batch-form .batch-actions>a.button,#batch-form .batch-actions>button,#batch-form .batch-actions>input[type=submit]{display:none;margin:0 12px 0 0;font-size:14px;line-height:24px;min-height:0;padding:0 6px}#batch-form .batch-actions>a.button.active,#batch-form .batch-actions>button.active,#batch-form .batch-actions>input[type=submit].active{display:inline-block}#batch-form select{font-size:14px;min-height:0;height:auto;line-height:24px;padding:0 24px 0 6px;margin-right:6px;border:0;box-shadow:0 0 0 1px #dfdfdf inset}.batch-selected{padding-left:0;list-style:none}.batch-selected li{padding:12px 0 11px;border-bottom:1px solid #dfdfdf}.batch-selected li:first-child{padding-top:0}.batch-selected li:last-child{border-color:transparent}#advanced-options{background-color:#fff;padding:6px 12px calc(6px - 1px);clear:both;border:1px solid rgba(0,0,0,.15);border-top:0;color:#676767}#advanced-options legend{float:left;width:calc(100% + 24px);font-weight:bold;padding:6px 12px;margin:-6px -12px 12px;background-color:rgba(0,0,0,.04);max-width:none}#advanced-options input{float:left;clear:left;margin-right:.5em;height:24px;margin-bottom:6px}#advanced-options label{float:left;margin-bottom:6px}.search-filters{margin-bottom:6px;display:inline-block}.filter{display:inline-block;font-size:13.08px;margin:0 6px 6px 0;border-radius:3px;background-color:#f0f0f0;padding:0;vertical-align:top}.filter-label{display:inline-block;background-color:rgba(0,0,0,.04);border-radius:3px 0 0 3px}.filter-label,.filter-value{padding:0 6px}.filter-value:not(:last-child):after{content:","}.multi-value .value{display:flex}.multi-value .add-value,.multi-value.field .remove-value{background-color:transparent;color:#a91919;display:inline-block;text-indent:-9999px;position:relative;min-width:36px;width:36px;text-align:center;box-shadow:none}.multi-value .add-value:before,.multi-value.field .remove-value:before{position:absolute;top:0;left:0;width:36px;line-height:36px;text-indent:0}.multi-value .add-value:hover,.multi-value.field .remove-value:hover{box-shadow:none;color:#a91919}.multi-value .add-value{position:absolute;top:0;right:0}.multi-value .field-meta{padding-right:36px}.item-set-select-type{max-width:25%}fieldset.section>legend{position:absolute;left:-9999px}.section-nav{border-top:1px solid #fff;height:42px;position:relative;margin-bottom:12px;clear:both}.section-nav:before{content:"";height:3px;position:absolute;bottom:1px;left:0;right:0;z-index:0;background:#fff;border:1px solid #dfdfdf;border-width:1px 0}.section-nav a{display:block;float:left;height:36px;line-height:30px;padding:3px 1em;position:relative;z-index:1;background-color:#fff;border-color:#dfdfdf;border:1px solid #dfdfdf;margin-left:.25em;color:#676767}.section-nav .active a{font-weight:bold;border-bottom-color:#fff}.section:not(a){display:none}.section.active{display:block;clear:both}#page-actions{position:fixed;padding:6px 1.0416666667%;z-index:4;top:0;height:36px;right:0;text-align:right;margin-bottom:0}#page-actions input[type=submit],#page-actions button,#page-actions .button{display:inline-block;height:36px;padding:6px 1em;min-height:0;vertical-align:top}#page-actions .delete.button{background-color:#fdefef;box-shadow:0 0 0 1px #e0c3c3 inset;color:#a91919}#page-actions .delete.button:hover{box-shadow:0 0 0 1px #da8b8b inset}.page-action-menu{display:inline-block;position:relative}.page-action-menu ul{display:none;list-style:none;border:1px solid #dfdfdf;background-color:#fff;border-radius:3px;text-align:left;padding:0;position:relative;box-shadow:0 0 5px #dfdfdf;position:absolute;right:0;width:auto;white-space:nowrap;margin:12px 0}.page-action-menu ul:before{content:"";position:absolute;bottom:calc(100% - 1px);right:12px;width:0;height:0;border-bottom:12px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent}.page-action-menu ul:after{content:"";position:absolute;bottom:calc(100% - 1px);right:11px;width:0;height:0;border-bottom:14px solid #dfdfdf;border-left:7px solid transparent;border-right:7px solid transparent;z-index:-1}.page-action-menu ul a,.page-action-menu ul .inactive{padding:6px 12px 5px;display:block;position:relative}.page-action-menu ul .inactive{color:#dfdfdf}.page-action-menu ul li{position:relative}.page-action-menu ul li:hover:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:#dfdfdf}.page-action-menu ul li:not(:last-child) a,.page-action-menu ul li:not(:last-child) span,.page-action-menu ul li:not(:last-child) [type=submit]{border-bottom:1px solid #dfdfdf}.page-action-menu [type=submit]{background:none;box-shadow:none;width:100%;margin-bottom:0;text-align:left}.page-action-menu li label{display:inline-block;height:36px;padding:6px 1em;min-height:0;vertical-align:top;width:100%}.page-action-menu li label input{margin-left:.25em}.page-action-menu li:not(:last-child) label{border-bottom:1px solid #dfdfdf}.page-action-menu .expand:after{content:""}.page-action-menu .expand:after,.page-action-menu .collapse:after{margin-left:6px}.page-action-menu .collapse+.collapsible{overflow:visible;display:block}.add-property.button{margin-top:24px}.field-term{display:inline-block;font-family:"Source Code Pro",monospace;font-size:12px}.value .input-body a.value-language{margin-right:0;vertical-align:top;position:absolute;top:0;right:0;height:36px;width:36px;line-height:36px;border:1px solid #dfdfdf;border-width:0 0 1px 1px;overflow:hidden;text-align:center;color:#f19d9d;z-index:1}.value .input-body a.value-language~textarea{padding-right:42px}.value .input-body .language-wrapper.active a.value-language{border-color:transparent;color:#a91919}.value .language-wrapper:not(.active)~textarea{padding-right:48px}.value .actions a.o-icon-more{display:block;height:36px}.more-actions.active a.o-icon-more{border-bottom:1px solid #dfdfdf}.language-wrapper input[type=text].value-language{line-height:24px;background-color:transparent;border:0;min-height:0;padding:6px 42px 6px 6px;display:block;background-color:#fff}.language-wrapper.active input[type=text].value-language~textarea{padding-left:6px;border-top:0}.input-body .language-wrapper:not(.active) .language-label{display:none}.sidebar .language-label{font-weight:inherit}.language-wrapper .language-label,.value[data-data-type=uri] .input-body label{display:flex;align-items:flex-start;background-color:#fff;margin:0;padding:0 42px 0 6px;box-shadow:0 0 0 1px #dfdfdf}.value-label-text{background-color:rgba(0,0,0,.04);border-radius:2px;font-size:14px;margin:6px;padding:0 6px}.sidebar .value-annotation .value{padding-bottom:0}.sidebar .value-annotation label:after{content:none}.sidebar .value-annotation p.selected-resource{border-bottom:1px solid #dfdfdf}.sidebar .value-annotation-resource-select{margin:6px !important}.sidebar [data-data-type^=resource] .o-title:not(:empty){padding:0;border-bottom:0}.sidebar [data-data-type^=resource] .o-title:not(:empty) a:empty{display:none}.sidebar [data-data-type^=resource] .o-title:not(:empty) img{margin:6px}.sidebar [data-data-type^=resource] .o-title:not(:empty) a{padding:6px;width:100%}.non-properties{margin-bottom:12px}.resource-form .values .sortable-handle{width:12px;background-color:rgba(0,0,0,.04);border:1px solid #dfdfdf;border-radius:2px 0 0 2px;align-self:stretch;border-right:0;margin:0;display:flex;align-items:center;justify-content:center}.resource-form .values .sortable-handle:before{font-size:10px}.visibility{display:inline-block;padding:6px;margin-right:12px}.add .visibility:before,.edit .visibility:before{margin-right:.25em}.add .visibility [type=checkbox],.edit .visibility [type=checkbox]{margin-left:.5em}#add-item .remove.field{background-color:#ea7171;opacity:.6}.resource.input-option span{display:block;background-color:rgba(255,255,255,.5);padding:6px 10px 0;width:100%;float:left}.field-meta{width:30%;padding-right:6px;position:relative}.field-meta legend,.field-meta label,.field-meta .label{max-width:80%;padding:6px 0;display:inline-block}.field-meta legend{position:static;float:left}.field-meta .error{float:left}.field-meta ul{margin:0}.field-label-text{display:block}.template{display:none}.selector ul{list-style:none;padding-left:0}.selector>ul{margin-top:6px}.selector li{position:relative}.selector li.total-count-heading{background-color:#404e61;color:#fff;border-radius:3px;text-transform:uppercase;font-size:12px;padding:6px 10px}.selector li.total-count-heading>ul{margin:6px -10px -6px;border-radius:0 0 3px 3px}.selector li.selector-parent.empty{display:none}.selector li.show>ul{position:relative;top:0;left:0;overflow:visible}.selector .selectable-list{background-color:#fff;color:#676767;overflow:visible;border-radius:3px;font-weight:bold;position:relative;border:1px solid #dfdfdf;margin:6px 0 0;text-transform:uppercase;font-size:12px}.selector .selectable-list li{padding:6px 12px}.selector .selectable-list .selector-parent{cursor:pointer;padding-right:24px;margin-bottom:0}.selector .selectable-list .selector-parent:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;position:absolute;right:0;top:6px;width:18px}.selector .selectable-list .selector-parent.show:after{content:""}.selector .selectable-list .selector-parent:hover:before{content:"";position:absolute;top:0;bottom:0;left:0;width:5px;background-color:#dfdfdf}.selector .selectable-list .selector-parent:not(:last-of-type){border-bottom:1px solid #dfdfdf;padding-bottom:5px;border-color:#dfdfdf}.selector-parent ul{position:absolute;top:-9999px;left:-9999px}.selector-child{border-radius:0;font-weight:normal;padding:6px 10px;margin:0 -12px;font-size:16px;text-transform:none;width:calc(100% + 36px)}.selector-child:hover{background-color:rgba(0,0,0,.04)}.selector-child:last-of-type{margin-bottom:-6px}.selector .description{display:inline-block;vertical-align:top}.selector .description.no-comment{opacity:0}.selector .description .o-icon-info{display:inline-block;margin:0 6px 0 0;opacity:.75;width:1em}.selector .description .o-icon-info:hover+.field-comment{left:5px;right:0;top:36px;padding:3px 10px 3px 36px;line-height:18px;background-color:#fff;z-index:1;margin:0;border-bottom:1px solid #dfdfdf;font-size:12px}.selector .description .o-icon-info:hover+.field-comment:before{content:"";position:absolute;left:7px;top:-6px;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff}.selector .description .o-icon-info:hover+.field-comment.above{bottom:100%;top:auto}.selector .description .o-icon-info:hover+.field-comment.above:before{top:calc(100% - 6px);transform:rotate(180deg)}.selector .description .o-icon-info+.field-comment{position:absolute;top:-9999px;left:-9999px;width:calc(100% - 5px)}.selector .selectable{display:inline-block;width:calc(100% - 36px);word-wrap:break-word}.field-actions{width:60%;display:inline-block;margin:24px 0 0 30%}.field .field-label{display:inline-block}.field .field-description,.field .docs-link{font-size:14px;line-height:18px;position:static;text-align:left;height:auto}.field .field-description:not(:only-child){margin-bottom:6px}.field-description{display:block;margin-right:10px;line-height:36px;height:36px;position:absolute;top:0;right:0;text-align:right;left:0}.field-description .o-icon-info{margin:0;cursor:pointer}.field-description .field-comment.open{left:inherit;right:0px;top:36px;background-color:#333;color:#fff;border-radius:3px;z-index:1;max-width:100%;font-size:14px;padding:6px 5px;margin:12px 0}.field-description .field-comment.open.above{top:auto;bottom:30px}.field-description .field-comment.open:before{content:"";display:block;height:0;width:0;position:absolute;top:-6px;bottom:0;right:3px;font-size:16px;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:12px solid #333}.field-description .field-comment.open.above:before{top:auto;bottom:-12px;transform:rotate(180deg)}.field .docs-link:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-right:6px;font-size:14px;line-height:18px}.field-meta .expand,.field-meta .collapse{display:inline-block !important;margin-left:.5em !important;padding:0 !important;border:0 !important;width:auto !important}.field-meta .expand:after,.field-meta .collapse:after{float:none !important;margin-right:0 !important}.collapsible{display:none}.collapse+.collapsible{display:block;clear:both;overflow:hidden}.field-description .field-comment{position:absolute;top:-9999px;left:-9999px}.resource-property .field-term{display:block}.inputs{line-height:36px;width:70%}.inputs:only-child{width:100%}.inputs p:only-child{margin:0}.inputs label,.inputs select,.inputs textarea,.inputs input[type=text],.inputs input[type=password],.inputs input[type=email],.inputs input[type=url],.inputs input[type=date],.inputs input[type=datetime-local]{width:100%;min-height:36px;margin:6px 0}.inputs label:only-child,.inputs select:only-child,.inputs textarea:only-child,.inputs input[type=text]:only-child,.inputs input[type=password]:only-child,.inputs input[type=email]:only-child,.inputs input[type=url]:only-child,.inputs input[type=date]:only-child,.inputs input[type=datetime-local]:only-child{margin:0}.inputs textarea{resize:vertical;line-height:1.5;background-color:#fff;min-width:0}.inputs label{padding:6px 0;margin:0 24px 0 0}.inputs .button,.inputs button,.inputs input[type=submit]{margin:6px 0;line-height:24px}.inputs input:focus,.inputs textarea:focus{position:relative;z-index:100}#resource-values div.value{display:flex;align-items:stretch}#resource-values div.value:only-of-type .sortable-handle{display:none}.value{margin-bottom:6px}.value:last-of-type{margin-bottom:0}.value:last-of-type .remove-value{margin-bottom:0;box-shadow:none}.value.template{display:none}.inputs p.no-values{padding:12px;border-radius:3px;background-color:rgba(0,0,0,.04);line-height:24px}.inputs p.no-values:not(:only-child){display:none}.add-values{margin:6px 0 -3px}.add-values *{display:inline-block;min-width:36px;height:36px;border-radius:2px;text-align:center;margin:0}.inputs .add-values a.button{margin:0 0 3px}.inputs .add-values a.button:before{margin-right:.25em}.add-values label{background-color:rgba(0,0,0,.04);line-height:36px;margin-right:0;overflow:hidden;width:12px;vertical-align:top}.input-footer{display:flex;width:30px}.input-footer .actions{margin-left:6px;flex-direction:column}.input-footer .actions a:before{line-height:36px;height:36px;text-align:center}.more-actions ul{padding:0;display:none}.more-actions.active{box-shadow:0 0 0 1px #dfdfdf;background-color:#fff;border-radius:2px}.more-actions.active ul{display:block}.value.delete{background-color:#fcc;overflow:hidden}.value .restore-value,.value.delete a.tab,.value.delete [class*=o-icon-]:not(.restore-value){display:none}.value.delete .input-footer{background-color:transparent;width:100%}.value.delete .restore-value{display:inline-block}.value [class*=o-icon-].label{position:absolute;top:0;left:0;height:36px;width:36px;background-color:rgba(0,0,0,.04);text-align:center;line-height:36px;overflow:hidden}.value label,.add-values label{margin:0;min-height:0;line-height:24px}.block.value .inputs label{margin-right:24px}.add-values button,.add-values .button{line-height:24px}.inputs .value textarea,.inputs .value input[type=text]{width:100%;margin:0}.inputs .value textarea{min-height:72px;border:0;box-shadow:0 0 0 1px #dfdfdf}.inputs .value .input-body>textarea{padding:6px 12px}[data-data-type^=resource] .default,[data-data-type^=resource] .o-title:not(:empty){padding:6px;border-bottom:1px solid #dfdfdf;word-wrap:break-word;line-height:24px;display:flex}[data-data-type^=resource].delete .o-icon-undo:before{padding-right:0}.input-body{clear:both;background-color:#fff;flex:1;position:relative;box-shadow:0 0 0 1px inset #dfdfdf;max-width:calc(100% - 30px)}.value:not(:only-of-type) .input-body{max-width:calc(100% - 48px)}.inputs .input-body input[type=text]{margin:0;background-color:transparent}.inputs .input-body input[type=text]:focus,.inputs .input-body textarea:focus{z-index:10}.inputs .input-body .chosen-container{max-width:calc(100% - 12px);margin:6px}[data-data-type^=resource] .button{font-size:14px;padding:0 6px;line-height:24px;min-height:0;margin-right:3px}[data-data-type^=resource] .button:before{margin-right:6px}.value.delete span.restore-value{display:inline-block;padding:0 6px;width:calc(100% - 36px)}.value.delete>*:not(.input-footer){display:none}.sortable-handle~.input-body{background-color:transparent}.resource-inputs{background-color:#fff;box-shadow:0 0 0 1px #dfdfdf}p.selected-resource{position:relative;width:100%;margin:0}.selected-resource a{width:calc(100% - 72px)}.selected-resource+a.button{margin-left:6px}.selected-resource img{height:24px;margin-right:6px}.selected-resource .o-title a:after{font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin:0 6px}.selected-resource .items a:after{content:""}.selected-resource .item_sets a:after{content:""}.selected-resource .media a:after{content:""}[data-data-type=literal] .sortable-handle~.input-body{background-color:#fff}.inputs [data-data-type=literal] textarea.input-value{background-color:transparent;padding-right:42px}[data-data-type=uri] .input{position:relative;clear:both;background-color:#fff;box-shadow:0 0 0 1px #dfdfdf}[data-data-type=uri] .input:first-child{border-bottom:1px solid #dfdfdf}.value[data-data-type=uri] .input-body label{padding-right:0}.sidebar [data-data-type=uri] label{font-weight:inherit}[data-data-type=uri] .input-body input.uri-value,[data-data-type=uri] textarea.value-label{height:36px;border:0;box-shadow:none;padding:6px 42px 6px 6px;font-weight:normal;background:transparent;min-height:36px}[data-data-type=uri] textarea.value-label{border-top-width:0}.annotation-form{padding-bottom:12px}.annotation-form>div,.annotation-form>select{margin-bottom:6px}.value-annotation:not(:last-child){border-bottom:1px solid #dfdfdf;padding-bottom:12px;margin-bottom:12px}.value-annotation .restore-value{line-height:36px}#resource-files button{margin:24px 0 0}#add-media-field{margin-bottom:0}.media.row{padding:6px;margin-bottom:6px;display:flex;align-items:center;word-wrap:break-word}.media.row img{width:36px;height:auto;margin-right:12px}.media.row .resource-name{margin-right:12px;min-width:0}.media.row .primary-media{text-transform:uppercase;font-size:12px;font-weight:bold;margin:0 0 0 auto}.media.row .primary-media input{margin-left:6px}.media.row .actions{margin-left:24px}.media.value.delete span.restore-value{padding:0}.media.value.delete>*:not(.restore-value),.media.value.delete .actions a:not(.o-icon-undo){display:none}.media.value.delete>.actions{display:block;top:18px}.media-header{font-size:16px;margin:6px -6px;margin-top:-12px;background-color:rgba(0,0,0,.04);padding:0 6px;display:flex;align-items:center}.value.delete>.actions{display:inline-block}.media-render{margin-bottom:24px}.media-render>*{max-width:100%}.media-render img{max-width:100%;height:auto}#item-media .sidebar button{width:100%;text-align:left}#item-item-sets+.no-resources:before,#site-item-sets+.no-resources:before{content:""}#item-item-sets tr.delete{background-color:#fcc}#page-actions [class*=o-icon-].button{background-color:transparent;width:auto;padding:6px 6px;box-shadow:none}.o-icon-private.button,.o-icon-public.button{margin-right:6px;box-shadow:none}#item-sites.empty+.no-resources:before{content:""}.media.edit #media .cke_contents{min-height:500px}.search-nav{width:100%}.search-nav .resource-search{width:100%;position:relative;margin-bottom:6px;display:flex;flex-wrap:wrap}.search-nav .chosen-container{margin-bottom:6px}.search-nav button.o-icon-search{height:36px;width:36px;line-height:24px;padding:0 10px;border-radius:0 3px 3px 0;min-height:0;position:relative;text-indent:-9999px;margin:0}.search-nav button.o-icon-search:before{text-indent:0px;position:absolute;left:0;top:6px;line-height:24px;width:100%}.search-nav .resource-search>input[type=text]{width:calc(100% - 36px);border-right:0;margin-bottom:6px}.resource-search-filters{padding-bottom:5px;border-bottom:1px solid #dfdfdf;margin-bottom:6px;width:100%}.resource-search-filters a.expand:after,.resource-search-filters a.collapse:after{float:right}.resource-search-filters .collapsible{margin-top:6px;overflow:visible}.sidebar .pagination{font-size:13.08px;border-bottom:1px solid rgba(0,0,0,.08);padding-bottom:11px;margin-bottom:0;overflow:hidden;width:100%}.sidebar .pagination li{float:left}.sidebar .pagination li:first-of-type{padding-right:10px}.sidebar .pagination input{width:3em;text-align:center;color:#333;margin:0 3px}.sidebar .pagination .next.button{margin-right:5px}.sidebar .pagination input[type=text]{float:left;line-height:19.62px;height:24px;border:1px solid #dfdfdf;margin-left:0}.sidebar .pagination .page-count{float:left;margin-right:12px}.sidebar .pagination .inactive{background-color:#e6e6e6;color:#b9b9b9}.sidebar textarea{resize:vertical}#item-results+.confirm-panel,#item-results .select-resource-checkbox-wrapper{display:none}#item-results.active{padding-bottom:72px}#item-results.active+.confirm-panel{display:block}#item-results.active .select-resource-checkbox-wrapper{display:inline-flex;align-items:center}.sidebar button.select-all,.sidebar button.quick-select-toggle{background-color:transparent;color:#676767;box-shadow:none;margin:12px;padding:0;line-height:1;min-height:0}.success-statuses{position:absolute}.success-statuses .status,.sidebar button .sr-only{display:none}.sidebar button:not(.active) .sr-only.off,.sidebar button.active .sr-only.on,.success-statuses:not(.active) .sr-only.off,.success-statuses.active .sr-only.on{display:block}.sidebar button.select-all:before,.sidebar button.quick-select-toggle:before{font-family:"Font Awesome 5 Free";font-weight:900;content:"";display:inline-block;margin-right:6px}.sidebar button.quick-select-toggle.active:before{content:""}.sidebar button.select-all:before{content:"";font-weight:400}.sidebar button.select-all.active:before{content:""}.sidebar button.quick-select-toggle+.resource-list{border-top:1px solid #dfdfdf}.resource-link{display:inline-flex;align-items:center;max-width:100%;min-width:0}.resource-link img{height:36px;margin-right:6px}.resource-link .resource-name{flex:1;min-width:0}.resource-list{width:100%}.resource-list .resource{padding:6px 12px 5px;border-bottom:1px solid rgba(0,0,0,.08);position:relative;width:100%;overflow:hidden;display:flex;align-items:center;word-wrap:break-word}.resource-list .resource:hover{background-color:rgba(255,255,255,.8)}.resource-list .resource:hover .select{right:0px}.resource-list .resource .select-resource-checkbox-wrapper{height:24px;margin-right:12px}#resource-details{background-color:#fff;overflow:hidden;padding:0}#resource-details .o-description,#resource-details .property{margin-bottom:0}.confirm-main{position:absolute;top:0;bottom:60px;overflow-y:auto;left:0;right:0;padding:12px 12px 0}.confirm-panel{position:absolute;bottom:0;right:0;left:0;padding:12px;background-color:#f7f7f7;border-top:1px solid #dfdfdf}.confirm-panel button,.confirm-panel .button{width:100%;margin:0}.sidebar .field-meta{width:100%;position:relative;padding-right:36px;margin-bottom:12px;border-bottom:3px solid #dfdfdf}.sidebar .field-meta .label,.sidebar .field-meta label{margin:0;width:auto;display:inline-block;padding:0 0 6px}.sidebar .field-meta .label:after,.sidebar .field-meta label:after{content:none}.sidebar .field-meta .collapsible{margin-bottom:12px}.sidebar .field-meta button.add-value{padding:0;background:transparent;color:#676767;min-height:0;position:absolute;top:0;right:0}.sidebar .field-meta button.add-value:before{height:auto;line-height:1.5}.sidebar .inputs{width:100%}.sidebar #advanced-search .value{flex-wrap:wrap}.sidebar #advanced-search .value:not(:first-child){margin-top:6px}.sidebar .multi-value .value:not(:only-child){width:calc(100% - 36px);position:relative;padding-bottom:0;margin-bottom:5px;border-bottom:0}.sidebar .multi-value .value:only-child .remove-value{display:none}.sidebar .multi-value .remove-value{position:absolute;right:-36px;bottom:0}.sidebar #advanced-search .value select,.sidebar #advanced-search .value input{margin-left:0}.sidebar #advanced-search .confirm-panel{display:flex;justify-content:space-between}.sidebar #advanced-search .confirm-panel button{width:calc(33.33% - 6px)}.block .block-content input[type=hidden]+button{padding-top:6px}.query-form-element .active{display:block}.query-form-element .inactive{display:none}.query-display .search-filters{margin-bottom:0}.query-display .filter{background-color:#fff;box-shadow:0 0 0 1px #dfdfdf inset}.query-display .filter-label{background-color:#dfdfdf}.query-form-element button.active{display:inline-block}.query-display{min-height:42px}input[type=text].query-form-query{margin-top:0}.query-display .filter-value:not(:last-child):after{content:none}#save-search{display:none}#save-search.active{display:flex;margin-top:-6px;padding:0 6px 12px calc(30% + 3px);background-color:rgba(0,0,0,.04)}#save-search.active input{margin-left:6px}.vocabs .field [type=file]{margin:6px 0 0}.vocabulary ul{padding-left:0;list-style:none;overflow:hidden}.vocabulary h2{margin-bottom:0}.vocabs.update td{vertical-align:top}.vocabs.update td:first-of-type,.vocabs.update td:nth-of-type(2){width:15%;word-wrap:break-word}.vocabs.update td:nth-of-type(3),.vocabs.update td:nth-of-type(4){width:35%}.vocabs.update td:nth-of-type(3):last-child{width:auto}.vocabs.update td:nth-of-type(3):not(:last-child){background-color:#ffe6e6}.vocabs.update td:nth-of-type(4){background-color:#cdffcd}.show .property,.meta-group{overflow:hidden;display:flex;justify-content:flex-end;flex-wrap:wrap}.show .property dt,.meta-group dt{width:22.2222222222%;vertical-align:top;padding:6px 0;font-weight:bold}.show .property dd,.show .property .values,.meta-group dd,.meta-group .values{padding:6px;margin:0;word-wrap:break-word;width:77.7777777778%}.show .property dd:not(:first-of-type),.show .property .values:not(:first-of-type),.meta-group dd:not(:first-of-type),.meta-group .values:not(:first-of-type){padding-top:0}.show .property .language,.meta-group .language{font-size:12px;padding:0 6px;margin-right:6px;background-color:rgba(0,0,0,.04)}#linked-filter label{display:flex;align-items:center;margin-bottom:24px}#linked-filter label select{margin-left:12px}#linked-resources table{margin-bottom:24px}#linked-resources caption{background-color:rgba(0,0,0,.04);font-family:bold;padding:6px;font-family:"Lato",sans-serif;font-weight:bold;text-align:left;font-size:20px}#linked-resources th{border-bottom:3px solid #dfdfdf}.linked-resource{margin-bottom:12px;padding-bottom:11px;border-bottom:1px solid #dfdfdf}.has-annotation:before{display:inline-block}.o-icon-annotation:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}.show .value.resource,.show .value.resource .value-content{display:flex;flex-wrap:wrap;align-items:center}.show .value .o-icon-private,.show .value .value-content{margin-right:12px}.collapsible.annotation{border-left:3px solid #dfdfdf;padding:0;border-radius:3px;margin:6px 0 12px 24px;width:100%}.collapsible.annotation h4,.collapsible.annotation .values{width:100%;padding:0}.collapsible.annotation .property{padding:0 12px}.collapsible.annotation .property:not(:first-child){margin-top:12px;border-top:1px solid #dfdfdf;padding-top:12px}.property .value .resource-name:after,.property .value.uri .uri-value-link:after{font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-left:.5em}.property .value.uri .uri-value-link:after{content:""}.property .value.items .resource-name:after{content:""}.property .value.media .resource-name:after{content:""}.property .value.item_sets .resource-name:after{content:""}.class-row{border-bottom:1px solid #dfdfdf;padding-bottom:11px}.class-label{font-weight:bold}.class-label:after{content:": "}.sidebar{position:fixed;top:48px;left:100%;visibility:hidden;bottom:0;background-color:#f7f7f7;z-index:3;border-left:1px solid #dfdfdf;overflow-y:auto;overflow-x:hidden;width:25%;padding:12px}body.transitions-enabled .sidebar{transition:left .5s,visibility .5s}.sidebar.active,.sidebar.always-open{left:75%;visibility:visible}.sidebar.loading{overflow:hidden}.sidebar.loading *{visibility:hidden}.sidebar.loading:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";line-height:1;position:absolute;top:.75em;left:calc(50% - .5em);font-size:4em;animation:fa-spin 1s infinite linear;height:1em;width:1em;text-align:center}.sidebar a.o-icon-close{position:absolute;right:12px;top:12px;z-index:3;color:#666}.sidebar .vocabulary,.sidebar .meta-group{margin-bottom:0}.sidebar .value{margin-bottom:6px;border-bottom:1px solid #dfdfdf;padding-bottom:5px;vertical-align:middle}.sidebar .value *:last-child{margin-bottom:0}.sidebar .value:last-child{border-color:transparent;margin-bottom:0}.sidebar input,.sidebar textarea,.sidebar select{width:100%}.sidebar input[type=checkbox],.sidebar input[type=radio]{width:auto}.sidebar h2{font-size:24px;margin-bottom:12px}.sidebar h3,.sidebar label,.sidebar .label{display:block;font-size:16px;font-weight:bold;margin:0 0 12px 0;padding:0 24px 12px 0;position:relative;width:100%;word-wrap:break-word;max-width:none}.sidebar h3:after,.sidebar label:after,.sidebar .label:after{content:"";position:absolute;left:-12px;right:-12px;bottom:0;top:-12px;background-color:#dfdfdf;z-index:-1}.sidebar .field{background-color:transparent;padding:0;margin-bottom:24px;flex-wrap:wrap;justify-content:flex-start}.sidebar .field .option{width:100%}.sidebar .field div.option+div.option{padding-top:11px;border-top:1px solid #dfdfdf;margin-top:12px}.sidebar .button,.sidebar button{background-color:#676767;border-color:#676767;color:#fff}.sidebar .button:disabled,.sidebar .button.disabled,.sidebar button:disabled,.sidebar button.disabled{background-color:rgba(0,0,0,.04);border-color:rgba(0,0,0,.04);color:#676767;box-shadow:none !important}.sidebar button.option{width:100%;text-align:left;border-color:#dfdfdf;background-color:#fff;color:#676767;display:inline-flex;justify-content:space-between}.sidebar button.option:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;color:#dfdfdf}#sidebar-confirm{display:block;padding-bottom:12px;margin-bottom:12px}#sidebar-confirm input[type=submit]{background-color:#a91919;color:#fff;box-shadow:none}body.sidebar-open #content{width:56.25%}.sidebar .meta-group{margin-bottom:12px}.sidebar .meta-group .value{width:100%;padding:6px 0;margin:0;word-wrap:break-word;display:block}.sidebar .meta-group .value:not(:last-child){border-bottom:1px solid #dfdfdf;padding-bottom:5px}.sidebar .meta-group h4{display:block;background-color:transparent;border-color:#dfdfdf;padding:6px 0;border-bottom:2px solid #dfdfdf;padding-bottom:4px;margin-bottom:0;width:100%}.sidebar .media a:first-child img,.sidebar>img:first-child{height:168px;width:auto;display:block;margin-bottom:12px}.sidebar .meta-group img{height:48px;box-shadow:0 0 0 1px #dfdfdf}.source-type{font-weight:bold}.resource-templates #properties{list-style:none;padding-left:0;margin-left:0}.resource-templates table{width:100%}.resource-templates th,.resource-templates td{padding:6px;vertical-align:top}.resource-templates .property.row{display:flex}.resource-templates .property.row.delete{background-color:#fcc}.resource-templates .property.row.delete .actions li:not(:last-child){display:none}.resource-templates .property.row:not(.delete) .sortable-handle{display:inline-flex}.resource-templates #properties{margin:24px 0 0;clear:both;padding:0}.resource-templates #edit-sidebar{padding-bottom:48px}.resource-templates #edit-sidebar .field h4,.resource-templates #edit-sidebar .field h4+span{width:100%}.resource-templates #edit-sidebar .field h4+span{margin-bottom:12px}.resource-templates #edit-sidebar .field label:not(:first-child),.resource-templates #edit-sidebar .field .option label{margin:0;padding-bottom:6px;padding-right:0;display:flex;justify-content:space-between}.resource-templates #edit-sidebar .field label:not(:first-child):only-child,.resource-templates #edit-sidebar .field .option label:only-child{padding-bottom:0}.resource-templates #edit-sidebar .field label:not(:first-child):after,.resource-templates #edit-sidebar .field .option label:after{padding:0;margin:0;background:transparent}.alternate-label-cell:not(:empty){background-color:#dfdfdf;display:inline-block;padding:0 6px;margin:0 6px;position:relative}.alternate-label-cell:not(:empty):after{content:"";border-top:12px solid transparent;border-bottom:12px solid transparent;border-left:6px solid #dfdfdf;width:0;height:0;position:absolute;left:100%;top:0}.title-property-cell,.description-property-cell{text-transform:uppercase;font-size:12px;font-weight:bold;margin-left:auto;margin-right:12px}.title-property-cell:after,.description-property-cell:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-left:6px}.title-property-cell~.actions,.description-property-cell~.actions{margin-left:0}.title-property-cell~.description-property-cell,.description-property-cell~.title-property-cell{margin-left:12px}#modules.installed tbody tr:not(.installed),#modules.uninstalled tbody tr:not(.uninstalled),#modules.needs-upgrade tbody tr:not(.needs-upgrade),#modules.active tbody tr:not(.active),#modules.deactivated tbody tr:not(.deactivated){display:none}.state-filter select{margin-bottom:12px}.module-name{font-weight:bold}.module-author{display:block}#modules .module{border-bottom:1px solid #dfdfdf;padding-bottom:11px;margin-bottom:12px;overflow:hidden}#modules .module-meta{float:left;max-width:50%}#modules .module-actions{float:right;max-width:50%;text-align:right}#modules .module form{display:inline-block}#modules button,#modules .button{display:inline-block;margin-left:6px;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset}#modules button:hover,#modules .button:hover{box-shadow:0 0 0 1px rgba(0,0,0,.3) inset}#modules button:before,#modules .button:before{margin-right:6px}#modules .o-icon-install{box-shadow:0 0 0 1px #addead inset}#modules .o-icon-install:hover{box-shadow:0 0 0 1px #63c363 inset}#modules .o-icon-uninstall{margin-left:24px;box-shadow:0 0 0 1px #e0c3c3 inset}#modules .o-icon-uninstall:hover{box-shadow:0 0 0 1px #da8b8b inset}#edit-keys td{word-wrap:break-word}.api-delete{width:10%}.api-label{width:25%}#system-info-table .label-col{width:25%}#system-info-table th,#system-info-table td{font-size:.875em;padding:0;line-height:1.75;border:none;vertical-align:top}#system-info-table th[scope=rowgroup]{font-size:1em;border-bottom:1px solid #dfdfdf;padding-left:6px}#system-info-table tbody:not(:last-child) tr:last-child td{padding-bottom:24px}#system-info-table th[scope=row]{padding-left:1.5em}.breadcrumbs{border-bottom:1px solid #dfdfdf;padding-bottom:11px;margin-bottom:24px}.breadcrumbs+.field{margin-top:24px}.breadcrumbs a:before{margin-right:6px}.breadcrumbs>*:not(:last-child):after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin:0 calc(12px - 3px) 0 12px;color:#000;cursor:default}#site-item-sets th:first-child,#site-item-sets th:last-child{width:36px}.manual-assignment .inputs label{display:block;padding:0;margin:6px 0 0;min-height:0;line-height:24px}.manual-assignment .inputs label:last-child{margin-bottom:6px}.manual-assignment #advanced-search{margin-top:-6px;padding:12px 0 6px;background-color:rgba(0,0,0,.04);border-top:1px solid #dfdfdf}.manual-assignment #advanced-search.inactive{display:none}.manual-assignment .advanced-search-header{padding:0 6px}.manual-assignment .advanced-search-header a.button{margin-bottom:6px}.manual-assignment .advanced-search-content .field{background-color:transparent}.keep-search,.keep-search input{margin:0 0 0 6px}tr.value.delete>td:not(.input-footer){display:table-cell}tr.value.delete .user-name,tr.value.delete select,tr.value.delete .o-icon-delete{display:none}td.user-meta{width:50%}#site-user-permissions.empty+.no-resources:before{content:""}#site-user-permissions .actions{justify-content:flex-end;padding:6px 0}.indent:before{content:"—";margin-right:-1px}.expand-collapse-all{margin-top:12px;text-align:right}.block{margin-bottom:6px}.block .block-header{position:relative;display:flex;align-items:center;background-color:rgba(0,0,0,.12);padding:6px;font-weight:bold}.block .block-header .actions a:before{text-align:center}.block .block-content input[type=hidden]+*{padding-top:0;margin-top:0}.block.html>div{border:1px solid #dfdfdf}.block .field{padding:0;border-color:transparent;background-color:transparent;margin-top:6px}.block .field:last-child{margin-bottom:0}.block.delete>.block-header{font-weight:normal;display:flex;background:transparent}.block.delete>*:not(.block-header){display:none}.block.delete span.restore-value{padding:0 3px;text-transform:lowercase;width:auto}.block.delete a.restore-value:before{padding:0}.block.delete .sortable-handle{display:none}.delete .block-type,.block .delete div.item-title{margin-left:30px}.delete .block-type{font-weight:bold}.block div.item-title{margin:6px 0;display:flex;align-items:center}.block .item-title img{height:36px;width:auto;display:inline-block;margin-right:6px;vertical-align:top}.block .delete.attachment{background-color:#fcc}.block .delete.attachment .actions .undo{display:inline-block}.block .delete.attachment .sortable-handle,.block .delete.attachment .actions li:not(.undo){display:none}.block .attachments-form{margin-bottom:12px}.block .attachments-form a h4{display:inline-block}.block .attachment .actions{margin-left:auto}.block .attachment .actions .button{background-color:transparent;color:#a91919;padding:0;min-height:0}.block .attachment .actions .button:hover{color:#a91919}.block .attachment .actions .undo{display:none}.block .block-content{clear:both;background-color:rgba(0,0,0,.04);padding:6px}.block.sortable-ghost .block-content{display:none}.block-content fieldset:last-of-type{margin-bottom:0}.block .attachment{display:flex;align-items:center;position:relative;padding:0 6px}.block .attachment:not(:last-child){border-bottom:1px solid #dfdfdf;padding-bottom:-1px}.block .attachment .button{margin-bottom:0}.block .attachment-add{margin:6px 0 0}.block-header.collapse:after{content:none}.block-content .expand,.block-content .collapse{width:100%;display:flex;padding:0 6px 0 0;justify-content:space-between}.block .field-meta .collapse+.collapsible{width:auto;border:0}.block .expand h4,.block .collapse h4{display:inline-block;padding:0}.block-content .collapse+.collapsible{border-top:1px solid #dfdfdf;padding:-1px 0 0 24px;margin-top:6px}.block[data-block-layout=html] [contenteditable=true]{resize:vertical;min-height:72px;max-height:288px}#attachment-options .option{position:relative;margin-bottom:12px}#attachment-options .expand,#attachment-options .collapse{position:absolute;right:0;top:0}#attachment-options h3{overflow:visible;white-space:normal}#attachment-item-select{display:block;margin:12px 0 0}#attachment-options .selected-attachment{margin-bottom:12px;margin-top:-12px;box-sizing:content-box;margin-right:-12px;margin-left:-12px;padding-right:12px;padding-left:12px;padding-top:12px;padding-bottom:12px;overflow:hidden}#attachment-options .selected-attachment img{height:96px;width:auto;float:right;margin:0 0 0 12px}#attachment-options .selected-attachment p:first-child{margin:0}#attachment-options h3.item-title{text-align:left}#attachment-options .item-thumbnail~h3.item-title{width:100%}#attachment-options .media-title{font-size:12px;display:block;width:calc(100% - 108px);float:left;word-wrap:break-word;text-align:left;clear:left}#attachment-options .item-thumbnail~#attachment-item-select{font-size:12px;display:inline-block;width:calc(100% - 108px);word-wrap:break-word}#attachment-options h3{word-wrap:break-word}#attachment-options .media-list{list-style:none;padding:0;margin:0 0 12px}#attachment-options .media-list li.media{position:relative;height:48px;width:48px;cursor:pointer;display:inline-block;padding:3px;border:1px solid #dfdfdf}#attachment-options .media-list li.media.attached,#attachment-options .media-list li.media:hover{background-color:rgba(0,0,0,.04)}#attachment-options .media-list img{width:100%;height:auto}#asset-options .selected-asset{overflow:hidden}#asset-options .selected-asset-image{float:left;margin:0 12px 0 0;max-width:50%}#asset-list.active{z-index:6}#asset-options .selected-asset .selected-asset-name{display:none}.asset-attachments-form{margin-bottom:12px}.add-asset-attachment{margin-top:6px}#asset-options .sidebar-content>div{margin-bottom:2rem}.asset-attachment-select{margin-top:.5rem}.asset-title{display:flex;align-items:center}.asset-title img{height:100%;width:auto}.asset-title .thumbnail:not(:empty){height:2rem;position:relative;width:2rem;margin:.25rem .25rem .25rem 0;overflow:hidden;display:inline-flex;justify-content:center}#asset-options .none-selected.inactive{display:none}#asset-options .none-selected:not(.inactive)~*{display:none}#asset-options .page-status{margin-bottom:12px}#asset-options .selected-page+.o-icon-external{margin-left:6px}.browse-defualts-form-element{display:flex;justify-content:space-between}.browse-defualts-form-element select{width:49.5%}input[type=text].page-selector-filter{width:100%;margin-bottom:12px}#nav-page-links,#nav-custom-links{width:100%}.page-selector-filter.empty,#nav-page-links .nav-page-link,#nav-page-links .added.active.nav-page-link,#no-pages{display:none}#nav-page-links .active.nav-page-link{display:flex}.empty~#no-pages{display:block}.site-page-add{margin:0}.jstree>.jstree-node:first-child .jstree-anchor{margin-top:0}.block-pagelist-tree li:last-child{margin-bottom:6px}.selectable-themes,.current-theme{display:flex;flex-wrap:wrap}.selectable-themes img,.current-theme img{max-width:100%;height:auto;vertical-align:bottom;position:relative;z-index:1}.selectable-themes .error,.current-theme .error{background-color:#f4b4b4;border-radius:3px;padding:6px 10px;margin:6px 0;display:block;width:100%;order:2}.theme-thumbnail{align-self:flex-start}.current-theme .error+ul{font-family:monospace;padding:11px;border:1px solid #dfdfdf;list-style-type:none}.invalid .theme-thumbnail img{opacity:.5}.selectable-themes .theme{width:calc(33.33% - 24px);margin:0 24px 24px 0;padding:11px;border:1px solid #dfdfdf;background-color:#fff;display:flex;flex-wrap:wrap}.selectable-themes .theme:hover{border:3px solid #9f9f9f;padding:9px}.selectable-themes .invalid.theme:hover{border:1px solid #dfdfdf;padding:11px}.selectable-themes .theme-thumbnail{width:100%;margin-bottom:12px;border:1px solid #dfdfdf}.selectable-themes .active.theme{background-color:#e7e7e7;position:relative;overflow:hidden;border-width:3px;padding:9px}.selectable-themes .active.theme:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;position:absolute;bottom:0;right:0;opacity:.15;font-size:96px;line-height:96px}.current-theme{padding-bottom:23px;border-bottom:1px solid #dfdfdf;margin-bottom:24px;flex-wrap:nowrap}.current-theme .theme-thumbnail{width:50%;margin:0 24px 0 0;border:1px solid #dfdfdf}.current-theme .current-theme-info{width:calc(50% - 24px)}.current-theme-label{font-size:16px;text-transform:uppercase;display:block;margin-bottom:6px}.theme-meta{display:flex;flex-direction:column;width:100%}.theme-resource-pages .blocks{list-style:none;padding-left:0;border:1px solid #dfdfdf;padding:12px;min-height:30px}.theme-resource-pages .block{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px;display:flex;height:36px}.theme-resource-pages .block.delete{background-color:#fcc;padding-left:36px}.theme-resource-pages .block.delete>*:not(.block-header){display:block}.theme-resource-pages .block.delete .sortable-handle{display:none}.theme-resource-pages button:disabled{display:none}.jobs.browse th:first-child,.jobs.browse td:first-child{width:10%}body.minimal{padding:0;margin:48px 0;width:93.75%;max-width:100%;margin-left:auto;margin-right:auto;height:auto;background-color:#404e61}body.minimal:after{content:" ";display:block;clear:both}body.minimal div[role=main]>h1:first-of-type{position:static;padding:0;width:100%;height:auto;display:inline-block;margin:0 0 24px 0}body.minimal h2{font-size:20px;margin-bottom:12px}body.minimal h3{font-size:18px;margin-bottom:12px}body.minimal fieldset legend{font-weight:bold;font-size:20px;margin-bottom:12px}body.minimal .logo{position:static;width:auto;float:none;padding:0;text-align:center;font-size:32px;line-height:48px}body.minimal div[role=main]{width:100%;min-height:0;margin:0;padding:48px 6.25%;overflow:hidden}body.minimal .inputs{width:70%}body.minimal .inputs input{width:calc(66.66% - 6px);vertical-align:top}body.minimal .inputs *:only-child{width:100%}body.minimal [type=submit]{width:100%;display:block;margin:auto;clear:both}body.minimal .field:last-child{margin-bottom:0}body.minimal .site-list{margin-bottom:24px;display:flex;flex-wrap:wrap}body.minimal .site-list .site{margin-bottom:12px;overflow:auto;max-width:60rem;width:50%;padding-right:1rem}body.minimal .site-list .site-link{display:inline-block;font-size:18px}body.minimal .site-list .site-summary{margin:0;line-height:20px}body.minimal .site-list .site-thumbnail{float:left;display:block;margin-right:1rem}body.minimal .site-list .site-thumbnail-image{max-width:15rem;vertical-align:bottom}body.minimal .results{margin-bottom:24px}body.minimal .results>ul{padding-left:0}body.minimal .results>ul>li{list-style-type:none}body.minimal .advanced-search{margin:-12px 0 24px;display:block}body.minimal .advanced-search-actions{margin:12px 0}body.minimal .advanced-search-actions input[type=submit]{width:auto;display:inline-block}.forgot-password{margin:6px 0}.sitewide-search-form{display:flex;margin-bottom:24px}.sitewide-search-form input[type=text]{min-width:60%;margin-right:6px}.sitewide-search-form input[type=submit]{width:auto;margin:0}body.minimal .site.results thead{background-color:rgba(0,0,0,.04)}.results>ul{display:flex;flex-wrap:wrap;align-items:flex-start;margin-bottom:0}.results>ul>li{border:1px solid #dfdfdf;border-radius:3px;padding:6px 6px 0;margin-bottom:12px;width:calc(50% - 12px)}.results>ul>li:nth-child(2n){margin-left:12px}.results ul ul{list-style:none;padding:0;margin-top:6px}.results li li{padding:6px;border-top:1px solid #dfdfdf;margin:0px -6px}.results .result-title{background-color:rgba(0,0,0,.04);display:block;padding:6px;margin:-6px;font-weight:bold}.results+.pagination{margin-top:-24px}.site.results .result-title{border-bottom:1px solid #dfdfdf;margin-bottom:6px}.site.results .result-site{margin-bottom:6px;display:block}.asset-form-element{line-height:36px}.asset-form-element.empty .asset-form-clear{display:none}.asset-form-element:not(.empty) .no-selected-asset{display:none}.selected-asset,.no-selected-asset{display:block}.selected-asset-name:not(:empty)~.none-selected,.selected-page:empty+a,.selected-page:not(:empty)~.none-selected{display:none}.selected-asset-image{max-width:100%}.asset-form-select{margin-top:12px}.new.attachment{display:none}.asset-upload{overflow:hidden;margin-bottom:24px}.asset-upload button{margin:6px 0 0;display:none}.asset-upload button.active{display:inline-block}.asset-upload ul.errors{color:#a91919;margin-top:0;word-wrap:break-word}.asset-upload ul.errors:empty{display:none}.asset-upload ul.errors a{border-bottom:1px solid #a91919}.asset-upload label{margin:6px 0;padding:0}.asset-upload label:after{content:none}.asset-upload input[type=file]{width:100%}.asset-filters{margin-bottom:6px}.asset-list .asset{padding-bottom:5px;border-bottom:1px solid #dfdfdf;margin-bottom:6px}.asset-list .asset:last-child{border-bottom-color:transparent}.asset-entry{display:flex;align-items:center;word-wrap:break-word}.asset-entry img{margin-right:6px;max-height:48px;max-width:50%}.asset-entry .asset-name{flex-grow:1}.color-picker{display:flex}.color-picker input[type=text]{margin:0}.color-picker .color-picker-sample{border:1px solid #dfdfdf;width:30%;margin-left:6px}}@media screen and (max-width: 640px){script{display:none !important}body{padding:0}.mobile-only{display:block}button.mobile-only{width:100%}header{width:100%;float:none;text-align:center;position:fixed;top:0;left:0;padding:0;right:0;z-index:1000;min-height:0}header .button{border-radius:0px;position:absolute;top:0;z-index:1001;color:#fff;background-color:#222933;box-shadow:none}header .o-icon-menu.button{left:0;border-right:1px solid rgba(0,0,0,.08);width:36px}header .o-icon-search.button{left:36px}header .o-icon-user.button{right:0}header nav ul.navigation>li:not(:first-of-type){margin-top:0}.logo{line-height:36px;padding:0 16.6666666667%;width:100%;text-align:center;display:block;background-color:#404e61}#user,#search,header nav{position:fixed;top:-9999px;left:-9999px;z-index:1000}header nav#site-nav{position:static;background-color:#fff;padding:0;margin-bottom:0}header nav#site-nav h5{border-top:1px solid #dfdfdf;padding-top:6px -1px;margin-bottom:0}header nav#site-nav h5 a{padding:0;border-bottom:0}#menu.active,#user.active,#search.active{top:36px;left:0;bottom:0;right:0;background-color:#fff;margin:0}footer{margin:0;padding:0;position:static;width:100%;text-align:center}footer:after{position:static;background:transparent}.browse td:first-child,.browse th:first-child{width:100%}td .o-icon-private,td .o-icon-user-inactive{vertical-align:top;margin:0}div[role=main]{margin:36px 0 0 0;width:100%;min-height:calc(100% - 72px);position:relative;padding-top:48px}div[role=main]>h1:first-of-type{width:auto;position:static;padding:12px 1.0416666667%;height:auto;margin:0 -1.0416666667% 12px;white-space:normal;line-height:36px}#menu{text-align:left;background-color:#fff;position:fixed;overflow:scroll}#menu ul{margin-bottom:0;border-bottom:0;padding-bottom:0}#menu a{display:block;padding:6px 12px 5px;color:#676767;border-bottom:1px solid #dfdfdf}#menu li:last-child a{border-bottom:0;padding-bottom:6px}#menu h5 a{padding:0;border-bottom:0}#menu h5{height:36px;color:#676767;background-color:rgba(0,0,0,.04);padding:6px 12px 5px;border:1px solid #dfdfdf;border-width:1px 0}#menu h4{background-color:rgba(0,0,0,.12);margin-bottom:0}#menu h4:not(:first-of-type){margin-top:0}#menu a.public,#menu a.expand,#menu a.collapse{height:36px;margin:-36px 0 0;padding:0 12px 0 0}#menu a.public:before,#menu a.public:after,#menu a.expand:before,#menu a.expand:after,#menu a.collapse:before,#menu a.collapse:after{height:36px;line-height:36px}#mobile-nav{display:block}#mobile-nav a.active{background-color:#500c0c}#user{text-align:center}#user .user-id{color:#676767;width:100%;margin:0 6px 24px}#user .user-id a{color:#a91919}#user .logout{display:block;margin:12px 6px;font-size:16px;color:#676767;border-radius:3px;width:calc(100% - 12px);min-height:36px;background-color:rgba(0,0,0,.08);border-radius:3px;border:0;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset;padding:6px 10px;display:inline-block;text-align:center;cursor:pointer;margin:0 6px}#user .logout:last-of-type:before{content:""}#user .logout a{color:#676767}#page-actions{top:36px;background-color:#fff;width:100%;border-bottom:1px solid rgba(0,0,0,.08);height:48px;padding-bottom:5px}#sidebar{position:fixed;top:36px;z-index:100;width:100%}#sidebar #content.sidebar-open{left:0}body.sidebar-open #content{width:100%}.sidebar{width:100%;top:36px;z-index:1000}.sidebar.always-open{left:100%}.sidebar.active,.confirm-panel{left:0;width:100%}fieldset.section>.always.active{content:"";bottom:0;left:0;right:0;height:48px;background-color:#fff;position:fixed;border-top:1px solid rgba(0,0,0,.04)}fieldset.section>.always.active button{width:100%;margin:6px}#modules .module-meta,#modules .module-actions{width:100%;max-width:100%}#modules .module-meta{margin-bottom:12px}#modules .module-actions{text-align:left}#modules button,#modules .button{margin:0 6px 0 0}.vocabs.update td{width:100% !important}#search-form{margin:48px 4.1666666667%}.batch-edit.button{margin:0;border-radius:0px;position:relative;z-index:1}.browse table{position:relative}.browse .sorting{float:left}.browse .pagination{margin-right:48px}.jobs.browse th:first-child,.jobs.browse td:first-child{width:100%}fieldset.section,fieldset.section{margin-bottom:0;position:relative}fieldset.section>legend:first-child{position:relative;left:auto;display:block;width:100%;font-size:20px;padding:6px 9px 6px 0;color:#a91919;cursor:pointer;border-bottom:3px solid rgba(0,0,0,.08);padding-bottom:-3px;margin-bottom:12px}fieldset.section>legend:after{content:"";font-family:"Font Awesome 5 Free";position:absolute;right:9px;top:12px}fieldset.section.mobile-active>legend:after{content:""}.add .active.section>.button,.edit .active.section>.button{display:inline-block}.field-meta,.inputs{width:100%}.field-actions{position:absolute;top:9px;right:1.6666666667%;z-index:1;width:50%}.field-actions a{float:right;display:block}.field-actions a.button{margin-left:.5em !important}.field-meta label,.field-description p{line-height:24px;margin-bottom:6px}.field-meta label{font-weight:bold}.unset .field-meta{width:100%}.show .sidebar.active{position:static;border:1px solid #dfdfdf;padding:11px;margin-top:24px}.show .section .property,.show .section .meta-group{margin-bottom:6px;box-shadow:0 0 0 1px #dfdfdf;border-radius:2px}.show .section .meta-group h4,.show .section .property h4{padding-bottom:6px;border-bottom:1px solid #dfdfdf;background-color:rgba(0,0,0,.04)}.show .section .meta-group h4,.show .section .meta-group .value,.show .section .property h4,.show .section .property .values{width:100% !important;padding:6px !important}.show .section .meta-group .value:not(:first-of-type),.show .section .property .value:not(:first-of-type){border-top:1px solid #dfdfdf;padding-top:6px -1px;margin-top:6px}.show .sidebar .meta-group .value:not(:first-of-type),.show .sidebar .property .value:not(:first-of-type){padding-top:6px}body.minimal{width:100%;margin:0}body.minimal .logo{background-color:transparent}body.minimal div[role=main]{padding:24px 6.25%}body.minimal div[role=main]>.messages{margin-top:24px}body.minimal .inputs{width:100%;margin-left:0}body.minimal footer{color:#fff}.tablesaw tr{overflow:hidden;margin-bottom:0}.tablesaw tr:first-of-type{border-top:1px solid #dfdfdf}.browse td:not(:first-of-type) .tablesaw-cell-content,#properties td:not(:first-of-type) .tablesaw-cell-content{display:inline-block}.tablesaw td:first-of-type{background-color:rgba(0,0,0,.04)}.tablesaw td:first-of-type .tablesaw-cell-label{width:0;height:0;overflow:hidden;padding:0;display:block}.tablesaw td:first-of-type .tablesaw-cell-content{width:100%;max-width:100%}.batch-edit.tablesaw td:first-of-type{width:100%;background:rgba(0,0,0,.04)}.batch-edit.tablesaw td:first-of-type img{margin-bottom:0}.batch-edit.tablesaw td:first-of-type .tablesaw-cell-label{width:0;overflow:hidden;padding:0}.batch-edit .tablesaw-cell-content{display:inline-flex}.tablesaw-cell-content{width:70%;max-width:70%}.tablesaw-cell-content img{margin:0 6px 0 0}.tablesaw tr:last-of-type td,.tablesaw tr:last-of-type th,.tablesaw th,.tablesaw td{padding-top:6px;padding-bottom:6px;vertical-align:top}.tablesaw th:not(:last-of-type),.tablesaw td:not(:last-of-type){border-bottom:1px solid #dfdfdf}.tablesaw tr.delete{border:0}.tablesaw tr.delete td{border:0}.tablesaw tr.delete td:not(:first-of-type){display:none}.resource-template th:first-of-type,.resource-template td:first-of-type{width:100%}#site-user-permissions tr.user.value{position:relative}#site-user-permissions td:nth-child(3){position:absolute;top:0;right:0;padding:0 6px 0 0}#site-user-permissions td:nth-child(3) .tablesaw-cell-label{display:none}#site-user-permissions td:nth-child(3) .tablesaw-cell-content{width:100%;max-width:100%}#site-user-permissions.tablesaw-stack tbody tr{border-bottom:0}} \ No newline at end of file +/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}template,[hidden]{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}@media screen{*{box-sizing:border-box}em,i{font-style:italic}strong,b{font-weight:bold}a{text-decoration:none}a:link,a:visited{color:#a91919}a:active,a:hover{color:#e34545}h1,h2,h3,h4,h5,h6{margin:0}h3,h4,h5,h6{font-weight:bold}h1{font-size:32px;line-height:48px;margin-bottom:24px}h2{font-size:30px;line-height:36px;margin-bottom:24px}h3{font-size:24px;margin-bottom:24px}h5{font-size:14px}p{margin:24px 0}ul{padding-left:24px;list-style:disc}pre{max-width:100%;overflow-x:auto}html,body{height:100%}body{font-family:"Lato",sans-serif;font-size:16px;line-height:24px;color:#676767;overflow-x:hidden}table{width:100%;border-spacing:0;table-layout:fixed}th,table.tablesaw th{font-weight:bold;text-align:left;padding:6px .5em}table,table.tablesaw{margin-bottom:12px;border:1px solid #dfdfdf;border-radius:3px;border-collapse:separate}.tablesaw tr:not(:last-child) td{border-bottom:1px solid #dfdfdf}tr.delete{background-color:#fcc}td,table.tablesaw td{padding:6px .5em 5px;position:relative;vertical-align:middle}table.tablesaw td:first-child a{word-wrap:break-word}table.tablesaw thead tr:first-child th{padding-top:6px;padding-bottom:5px;border-bottom:1px solid #dfdfdf}legend{font-size:20px;padding:12px 0;font-weight:bold}[contenteditable=true],textarea{clear:both;padding:6px;border:1px solid rgba(0,0,0,.15);display:block;background-color:#fff;min-height:72px;overflow-y:auto}[contenteditable=true] p{margin:12px 0}.cke_dialog_body textarea{max-height:none}input,[contenteditable=true],textarea,button,select{font-family:"Lato",sans-serif;font-size:16px;line-height:24px;margin:0;color:#676767}input[type=text],input[type=password],input[type=email],input[type=url],input[type=number],input[type=date],input[type=datetime-local]{-webkit-appearance:none;appearance:none;border-radius:0;height:36px;border:1px solid rgba(0,0,0,.15);padding:6px;margin:0}:disabled{background-color:rgba(0,0,0,.04);box-shadow:0 0 0 1px rgba(0,0,0,.15) inset;color:#a7a7a7;-webkit-text-fill-color:#a7a7a7;cursor:default}:disabled:hover{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset !important}::placeholder{font-style:italic}[contenteditable=true]>*:first-child{margin-top:0}[contenteditable=true]>*:last-child{margin-bottom:0}input[type=submit],button,a.button,.button{min-height:36px;background-color:rgba(0,0,0,.08);color:#676767;border-radius:3px;border:0;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset;padding:6px 10px;display:inline-block;text-align:center;cursor:pointer;margin:0 0 12px 0}input[type=submit]:hover:not(.inactive),button:hover:not(.inactive),a.button:hover:not(.inactive),.button:hover:not(.inactive){box-shadow:0 0 0 1px rgba(0,0,0,.3) inset}input[type=submit].inactive,button.inactive,a.button.inactive,.button.inactive{box-shadow:none;background-color:#d2d2d2;cursor:default;border:0}.red.button{background-color:#fdefef;box-shadow:0 0 0 1px #e0c3c3 inset;color:#a91919}.red.button:hover{box-shadow:0 0 0 1px #da8b8b inset}.green.button{background-color:#cdffcd;color:green;box-shadow:0 0 0 1px #addead inset}.green.button:hover{box-shadow:0 0 0 1px #63c363 inset}.required .field-meta{position:relative;padding-right:36px}.required .field-meta:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";font-size:12px;position:absolute;right:12px;color:#a91919;top:6px}label input[type=checkbox]{display:inline-block;width:auto}label.required:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";font-size:12px;color:#a91919;float:right;padding-right:12px}.touched:invalid{box-shadow:0 0 2px 2px #a91919}.field{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px;display:flex;flex-wrap:wrap}.field:first-child{border-color:transparent}.media-field-wrapper{width:100%;padding:12px 6px;margin-bottom:6px;background-color:rgba(0,0,0,.04);position:relative}.media-field-wrapper .field{width:100%;margin:0 0 6px;padding:0;background-color:transparent}.media-field-wrapper .field:last-of-type{margin-bottom:0}.media-field-wrapper .field:last-of-type .field-meta,.media-field-wrapper .field:last-of-type .inputs{margin-bottom:-6px}.media-field-wrapper .actions{font-size:16px;padding:6px 0}select{background:#fff url("../img/select-arrow.svg") no-repeat;background-position:right 6px center;background-size:8px;border:1px solid #dfdfdf;height:36px;line-height:36px;font-size:16px;margin:0;padding:0 24px 0 6px;border-radius:3px;vertical-align:top;-webkit-appearance:none;appearance:none}select::-ms-expand{display:none}label input{margin-right:.5em}fieldset{margin:0 0 24px;border:0;padding:0;min-width:100%}.selector input[type=text],.selector>ul{width:100%}.selector>ul{margin:0}.chosen-container{max-width:100%}.chosen-container-single .chosen-single,.chosen-container-multi .chosen-choices{background-image:none;background-color:#fff;box-shadow:none;font-size:16px;line-height:24px;padding:6px;height:auto;border-radius:3px;border-collapse:#dfdfdf;color:#676767;border-color:#dfdfdf}.chosen-container-multi.chosen-container-active .chosen-choices{border-color:#aaa;border-radius:3px 3px 0 0}.chosen-container-multi.chosen-container.chosen-drop-up .chosen-choices{border-radius:0 0 3px 3px}.chosen-container-multi.chosen-container .chosen-drop{top:calc(100% - 1px);border-top:1px solid #aaa}.chosen-container-multi.chosen-container.chosen-drop-up .chosen-drop{bottom:calc(100% - 1px)}.chosen-container-multi .chosen-choices{padding:3px}.chosen-container-multi .chosen-choices li.search-field input[type=text]{font-family:"Lato",sans-serif;margin:0}.chosen-container-multi .chosen-choices li.search-choice{background:#f0f0f0;font-size:14px;line-height:24px;border:0;padding:0 27px 0 0}.chosen-container-multi .chosen-choices li.search-choice span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;display:block}.chosen-container .search-choice .group-name{color:#676767;position:relative;background-color:rgba(0,0,0,.04);margin-right:6px;padding:0 6px;display:inline-block;vertical-align:top}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{top:50%;right:6px;transform:translateY(-50%)}.chosen-container .search-choice .group-name:after{content:""}.chosen-container-multi .chosen-choices li.search-field input[type=text]{min-height:0;margin:3px;height:auto;line-height:24px}.chosen-container-active.chosen-with-drop .chosen-single{background-image:none}.chosen-container-single .chosen-single abbr{top:12px}.chosen-container-single .chosen-single div b{background:none !important}.chosen-container-single .chosen-single div b:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";line-height:24px;padding:6px 0;display:inline-block}.chosen-container-active.chosen-with-drop .chosen-single div b:after{content:""}.chosen-container-single .chosen-search input[type=text]{background:none !important}.chosen-search{position:relative}.chosen-search:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";line-height:24px;padding:6px 0;display:block;position:absolute;top:3px;right:12px}.chosen-container .chosen-results li.highlighted{background-color:#676767;background-image:none}.chosen-container.chosen-drop-up .chosen-drop{top:auto;bottom:100%;border-radius:3px 3px 0 0;box-shadow:0 -1px 2px rgba(0,0,0,.15);border-top:1px solid #aaa}.chosen-container-active.chosen-drop-up.chosen-with-drop .chosen-single{border-radius:0 0 3px 3px}.flex{display:flex}.mobile-only{display:none}.sr-only{left:-9999px}div[role=main]>.messages{margin-bottom:12px}div[role=main]>.messages li{margin:0 0 6px}div[role=main]>.messages .error{background-color:#f4b4b4}div[role=main]>.messages .success{background-color:#cdffcd}div[role=main]>.messages .warning{background-color:#fff6e6}div[role=main]>.messages a{text-decoration:underline}.messages{padding:0;margin:0;clear:both}.messages li{background-color:rgba(255,255,255,.5);border-radius:3px;padding:6px 10px;margin-top:6px;display:block;width:100%}.field .messages{width:70%;color:#a91919;margin-left:auto}.field .messages li{box-shadow:0 0 0 1px inset}.error,.error a{color:#a91919}.success,.success a{color:green}.warning,.warning a{color:orange}.version-notification{background-color:#cdffcd;color:green;border-radius:3px;padding:6px 10px;margin-top:6px;display:block;width:100%}.version-notification a{color:green;text-decoration:underline}table .icon-sortable{opacity:.4;font-size:12px;line-height:100%}.row{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px}.row.delete{background-color:#fcc;overflow:hidden}.jstree-themeicon,.sortable-handle{cursor:move;margin-right:12px;width:18px}.jstree-themeicon:before,.sortable-handle:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;opacity:.35;font-size:20px;line-height:24px}.jstree i.jstree-themeicon{color:#676767;position:static;top:auto;right:auto}.o-description{margin-bottom:0}a.expand,a.collapse{color:#676767}.expand:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;margin-left:3px}.collapse:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;margin-left:3px}.selector-table{display:table}.selector-table.empty,.selector-table+.no-resources{display:none}.selector-table.empty+.no-resources{display:block}.selector .resources-available.empty,.selector .resources-available+.resources-unavailable{display:none}.selector .resources-available.empty+.resources-unavailable{display:block}.selector .selector-child.filter-hidden,.selector .selector-child.added{display:none}header{background-color:#404e61;width:18.75%;min-height:100vh;text-align:left;padding:0 1.0416666667% 24px;color:#bdcde3}.skip{position:absolute;left:-9999px}.skip:focus{position:absolute;top:0;left:45%;width:10%;z-index:1002;text-align:center;background-color:#fff;border-radius:0 0 3px 3px;border:1px solid #dfdfdf;padding:5px}.logo a,#user a{color:#bdcde3}#user{color:#fff;padding-top:12px;margin-bottom:-6px;display:flex;flex-wrap:wrap}#user p{margin:0 0 6px;display:inline-flex;vertical-align:top}#user .user-id{text-transform:uppercase;font-size:12px;margin-right:auto}#user .user-id a.button{display:inline-block;font-size:12px;text-transform:none;margin-bottom:0;background-color:#222933;padding:0 6px;min-height:0;border:0}#user .user-show{border-radius:3px 0 0 3px;margin-right:1px;display:inline-flex;max-width:85%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}#user .user-show:before{margin-right:6px}#user .user-settings{border-radius:0 3px 3px 0;border-left:0}#user .user-settings:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}#user .logout{font-size:12px;padding:0 6px;background-color:#222933;border-radius:3px;display:inline-block;min-width:25%;text-align:center}.logo{padding:6px 6.25%;margin:0 -6.25%;background-color:#222933}#search{width:100%;display:inline-block;vertical-align:top;margin:24px 0}#search input[type=text]{width:calc(100% - 72px);float:left}#search button{width:36px;text-indent:-9999px;background-color:#222933;color:#bdcde3;border:0;float:left;margin:0;border-radius:0;position:relative;height:36px;box-shadow:none}#search button:last-of-type{border-left:1px solid rgba(255,255,255,.2);border-radius:0 3px 3px 0}#search button:last-of-type:after{content:""}#search button:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;text-indent:0;position:absolute;top:0;left:0;width:36px;line-height:36px;text-align:center}#advanced-options{display:none}div[role=main]>h1:first-of-type{background-color:#fff;font-size:24px;position:fixed;padding:3px 30% 3px 1.0416666667%;z-index:3;top:0;right:0;width:81.25%;height:48px;border-bottom:1px solid #dfdfdf;overflow:hidden;line-height:36px}div[role=main]>h1:first-of-type .title{text-overflow:ellipsis;white-space:nowrap;max-width:65%;display:inline-block;overflow:hidden;vertical-align:middle}.subhead{text-transform:uppercase;font-size:14px;padding:0 6px;background-color:#eee;line-height:36px;vertical-align:middle;margin:0 12px 0 0;font-weight:normal;display:inline-block}.subhead:before{font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-right:6px;font-size:16px;vertical-align:top}.action{display:inline-block;vertical-align:middle}.action:before{content:"·";margin:0 12px}.sidebar-open footer{margin-right:25%}footer{font-size:12px;position:relative;margin-top:-27px;margin-left:18.75%;padding-right:1.0416666667%;text-align:right}footer .site-version{margin:0;display:inline-block}footer .version-number{display:inline-block;margin:0 12px;line-height:1}body.transitions-enabled footer{transition:margin-right .5s}footer>a:not(:last-child){margin-right:12px}nav ul{padding:0;list-style:none;margin:0}nav.pagination{margin-bottom:12px;overflow:hidden}nav.pagination form,nav.pagination .button,nav.pagination .row-count{float:left}nav.pagination form{margin-right:12px}nav.pagination form *{display:inline-block;padding:0;text-align:center}nav.pagination .button{border-radius:0;margin:0;padding:0 10px}nav.pagination .button,nav.pagination input[type=text],.sorting button,.sorting select{font-size:13.08px;min-height:0;height:24px;line-height:24px;vertical-align:top;background-size:6.5408px}nav.pagination .button{box-shadow:0 0 0 1px #c8c8c8 inset;position:relative}nav.pagination .button:hover{z-index:1}nav.pagination .button:before{vertical-align:top;line-height:24px}nav.pagination .previous.button{border-radius:3px 0 0 3px}nav.pagination .next.button{border-radius:0 3px 3px 0;margin-left:-1px}nav.pagination form input[type=text]{margin-right:.25em;width:48px;border:1px solid #dfdfdf;padding:5px}nav.pagination+*:not(.sorting){clear:left}#mobile-nav{display:none}.mobile-container{position:relative}button .o-icon-private{margin:0 6px;color:#dfdfdf}header nav h4{padding-bottom:5px;border-bottom:1px solid #364252;margin-bottom:6px}header nav h4:not(:first-of-type){margin-top:24px}header nav ul.navigation>li:not(:first-of-type){margin-top:6px}header nav ul.navigation>li:not(:last-of-type){border-color:#dfdfdf}header nav ul.navigation li li{display:none}header nav ul.navigation li.active li{display:block;margin-left:24px}header nav ul.navigation li.active>a{color:#fff}header nav a:link,header nav a:visited{color:#bdcde3}header nav li>a:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;width:24px}header nav .items:before,.items .subhead:before{content:""}header nav .media:before,.media .subhead:before{content:""}header nav .item-sets:before,.item-sets .subhead:before{content:""}header nav .vocabularies:before,.vocabularies .subhead:before{content:""}header nav .resource-templates:before,.resource-templates .subhead:before{content:""}header nav .users:before,.users .subhead:before{content:""}header nav .modules:before,.modules .subhead:before{content:""}header nav .jobs:before,.jobs .subhead:before{content:""}header nav .sites:before,.sites .subhead:before{content:""}header nav .settings:before,.settings .subhead:before{content:""}header nav .assets:before,.assets .subhead:before{content:""}header nav li li a:before{content:""}header ul.navigation{margin-bottom:6px}#menu{position:relative}#menu h5{text-transform:uppercase;border-top:1px solid #364252;padding-top:5px;margin-bottom:0}#menu .expand,#menu .collapse{width:100%;z-index:1;padding-bottom:6px;margin-bottom:6px}#site-nav{background-color:#364252;padding:6px;margin-bottom:12px;border-radius:3px}#site-nav h5{border-top:0;border-bottom:1px solid #2c3542;padding:0 24px 5px 0;margin-bottom:6px}header nav#site-nav h5 a:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;width:24px;display:inline-block;font-size:16px}#menu .pages:before,.site-pages .subhead:before{content:""}#menu a.navigation:before{content:""}#menu a.public{float:right;text-align:right;font-size:16px;line-height:30px;margin-top:-39px}#menu a.resources:before{content:""}#menu a.site-info:before{content:""}#menu a.theme:before,.theme-settings .subhead:before{content:""}div[role=main]{width:81.25%;padding:60px 1.0416666667% 36px;background-color:#fff;min-height:100%;overflow:hidden}body.transitions-enabled div[role=main]{transition:width .5s}#dashboard>p{width:100%;margin-top:12px}#manage-resources .add.button:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}.panel{width:48.9583333333%;float:left;padding-left:1.0416666667%;padding-right:1.0416666667%;border:1px solid #dfdfdf;padding:5px;margin:0 1.0416666667% 0 0;float:left;overflow:hidden}.panel .row{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px}.panel>.row:last-child{margin-bottom:0}.panel .button{float:right;margin:0}.panel .row a.button{box-shadow:none;padding:0;color:#a91919;background-color:transparent}.panel h2{font-size:18px;line-height:24px;margin-bottom:6px}.browse .add.button,.browse .batch-edit.button{float:left;margin-right:.25em}.browse td:first-child,.browse th:first-child{width:50%}.browse td,.browse th{padding:12px 6px;overflow:hidden}.browse .browse-controls{display:flex;justify-content:space-between;flex-wrap:wrap;font-size:13.08px}.sites.pages.browse .browse-controls{justify-content:flex-end}.browse .browse-controls .advanced-search:before{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;font-style:normal;font-variant:normal;font-weight:normal;line-height:1;font-family:"Font Awesome 5 Free";font-weight:900;content:"";padding:.25em}.browse-controls select,.browse-controls input,.browse-controls button,.browse-controls .button{font-size:13.08px;min-height:0;height:24px;line-height:24px;vertical-align:top;background-size:6.5408px}.browse-controls .sorting:not(:last-child){margin-left:auto}.browse-controls button,.browse-controls .button{padding:0 10px}.browse-controls .filtering{margin-left:24px}.browse .select-all{width:12px;margin-right:12px}.browse .tablesaw-cell-content,#properties .tablesaw-cell-content{display:flex;align-items:center;justify-content:flex-start;word-wrap:break-word}.browse .tablesaw-cell-content>.actions,#properties .tablesaw-cell-content>.actions{white-space:nowrap}.browse .batch-edit .tablesaw-cell-content>input[type=checkbox]{margin-right:12px;flex-shrink:0}.browse .tablesaw-cell-content>span.indent{display:inline-block;vertical-align:top;flex:0;min-width:1em}.actions{margin:0 0 0 auto;display:flex;padding:0}.actions li{list-style-type:none}.actions a,.actions a:before,.actions button,.actions button:before{width:24px;height:24px;line-height:24px;vertical-align:top;border:0;box-shadow:none;display:inline-block}.actions .button:hover,.actions button:hover{box-shadow:none !important}.actions a,.actions button{opacity:.5}.actions a:before,.actions button:before{text-align:right}.actions a:hover,.actions a:active,.actions button:hover{opacity:1}.actions .inactive{display:none}.actions button{background-color:transparent;color:#a91919;margin:0;text-indent:-9999px;position:relative;padding:0;min-height:0}.actions button:before{text-indent:0;position:absolute;top:0;left:0}.row-count{margin:0 6px}.no-resources{text-align:center;position:relative;margin-top:96px}.no-resources:before{font-family:"Font Awesome 5 Free";font-weight:900;font-size:96px;position:absolute;top:0;left:0;width:100%;opacity:.08;content:""}.no-resources p{font-size:24px;line-height:48px;margin-top:48px}td .o-icon-private,td .o-icon-user-inactive{display:inline-block;vertical-align:bottom;margin-left:.5em;opacity:.5}.items .no-resources:before{content:""}.item-sets .no-resources:before{content:""}.media .no-resources:before,#media-list .no-resources:before{content:""}.modules .no-resources:before{content:""}.vocabs .no-resources:before{content:""}.resource-templates .no-resources:before,.resources-templates{content:""}.users .no-resources:before{content:""}.jobs .no-resources:before{content:""}.sites .no-resources:before{content:""}.sidebar .no-resources{display:block}.browse.assets td:first-child,.browse.assets th:first-child{width:75%}.asset-inline{max-width:100%}#batch-form{border:1px solid #dfdfdf;border-bottom:0;border-radius:3px;margin-bottom:12px}#batch-form table.tablesaw{border-width:1px 0;border-radius:0 0 3px 3px;margin-bottom:0}#batch-form .batch-actions{display:inline-block}#batch-form .batch-inputs{display:flex;align-items:center;padding:6px;background-color:rgba(0,0,0,.04)}#batch-form .batch-actions>a.button,#batch-form .batch-actions>button,#batch-form .batch-actions>input[type=submit]{display:none;margin:0 12px 0 0;font-size:14px;line-height:24px;min-height:0;padding:0 6px}#batch-form .batch-actions>a.button.active,#batch-form .batch-actions>button.active,#batch-form .batch-actions>input[type=submit].active{display:inline-block}#batch-form select{font-size:14px;min-height:0;height:auto;line-height:24px;padding:0 24px 0 6px;margin-right:6px;border:0;box-shadow:0 0 0 1px #dfdfdf inset}.batch-selected{padding-left:0;list-style:none}.batch-selected li{padding:12px 0 11px;border-bottom:1px solid #dfdfdf}.batch-selected li:first-child{padding-top:0}.batch-selected li:last-child{border-color:transparent}#advanced-options{background-color:#fff;padding:6px 12px calc(6px - 1px);clear:both;border:1px solid rgba(0,0,0,.15);border-top:0;color:#676767}#advanced-options legend{float:left;width:calc(100% + 24px);font-weight:bold;padding:6px 12px;margin:-6px -12px 12px;background-color:rgba(0,0,0,.04);max-width:none}#advanced-options input{float:left;clear:left;margin-right:.5em;height:24px;margin-bottom:6px}#advanced-options label{float:left;margin-bottom:6px}.search-filters{margin-bottom:6px;display:inline-block}.filter{display:inline-block;font-size:13.08px;margin:0 6px 6px 0;border-radius:3px;background-color:#f0f0f0;padding:0;vertical-align:top}.filter-label{display:inline-block;background-color:rgba(0,0,0,.04);border-radius:3px 0 0 3px}.filter-label,.filter-value{padding:0 6px}.filter-value:not(:last-child):after{content:","}.multi-value .value{display:flex}.multi-value .add-value,.multi-value.field .remove-value{background-color:transparent;color:#a91919;display:inline-block;text-indent:-9999px;position:relative;min-width:36px;width:36px;text-align:center;box-shadow:none}.multi-value .add-value:before,.multi-value.field .remove-value:before{position:absolute;top:0;left:0;width:36px;line-height:36px;text-indent:0}.multi-value .add-value:hover,.multi-value.field .remove-value:hover{box-shadow:none;color:#a91919}.multi-value .add-value{position:absolute;top:0;right:0}.multi-value .field-meta{padding-right:36px}.item-set-select-type{max-width:25%}fieldset.section>legend{position:absolute;left:-9999px}.section-nav{border-top:1px solid #fff;height:42px;position:relative;margin-bottom:12px;clear:both}.section-nav:before{content:"";height:3px;position:absolute;bottom:1px;left:0;right:0;z-index:0;background:#fff;border:1px solid #dfdfdf;border-width:1px 0}.section-nav a{display:block;float:left;height:36px;line-height:30px;padding:3px 1em;position:relative;z-index:1;background-color:#fff;border-color:#dfdfdf;border:1px solid #dfdfdf;margin-left:.25em;color:#676767}.section-nav .active a{font-weight:bold;border-bottom-color:#fff}.section:not(a){display:none}.section.active{display:block;clear:both}#page-actions{position:fixed;padding:6px 1.0416666667%;z-index:4;top:0;height:36px;right:0;text-align:right;margin-bottom:0}#page-actions input[type=submit],#page-actions button,#page-actions .button{display:inline-block;height:36px;padding:6px 1em;min-height:0;vertical-align:top}#page-actions .delete.button{background-color:#fdefef;box-shadow:0 0 0 1px #e0c3c3 inset;color:#a91919}#page-actions .delete.button:hover{box-shadow:0 0 0 1px #da8b8b inset}.page-action-menu{display:inline-block;position:relative}.page-action-menu ul{display:none;list-style:none;border:1px solid #dfdfdf;background-color:#fff;border-radius:3px;text-align:left;padding:0;position:relative;box-shadow:0 0 5px #dfdfdf;position:absolute;right:0;width:auto;white-space:nowrap;margin:12px 0}.page-action-menu ul:before{content:"";position:absolute;bottom:calc(100% - 1px);right:12px;width:0;height:0;border-bottom:12px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent}.page-action-menu ul:after{content:"";position:absolute;bottom:calc(100% - 1px);right:11px;width:0;height:0;border-bottom:14px solid #dfdfdf;border-left:7px solid transparent;border-right:7px solid transparent;z-index:-1}.page-action-menu ul a,.page-action-menu ul .inactive{padding:6px 12px 5px;display:block;position:relative}.page-action-menu ul .inactive{color:#dfdfdf}.page-action-menu ul li{position:relative}.page-action-menu ul li:hover:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:#dfdfdf}.page-action-menu ul li:not(:last-child) a,.page-action-menu ul li:not(:last-child) span,.page-action-menu ul li:not(:last-child) [type=submit]{border-bottom:1px solid #dfdfdf}.page-action-menu [type=submit]{background:none;box-shadow:none;width:100%;margin-bottom:0;text-align:left}.page-action-menu li label{display:inline-block;height:36px;padding:6px 1em;min-height:0;vertical-align:top;width:100%}.page-action-menu li label input{margin-left:.25em}.page-action-menu li:not(:last-child) label{border-bottom:1px solid #dfdfdf}.page-action-menu .expand:after{content:""}.page-action-menu .expand:after,.page-action-menu .collapse:after{margin-left:6px}.page-action-menu .collapse+.collapsible{overflow:visible;display:block}.add-property.button{margin-top:24px}.field-term{display:inline-block;font-family:"Source Code Pro",monospace;font-size:12px}.value .input-body a.value-language{margin-right:0;vertical-align:top;position:absolute;top:0;right:0;height:36px;width:36px;line-height:36px;border:1px solid #dfdfdf;border-width:0 0 1px 1px;overflow:hidden;text-align:center;color:#f19d9d;z-index:1}.value .input-body a.value-language~textarea{padding-right:42px}.value .input-body .language-wrapper.active a.value-language{border-color:transparent;color:#a91919}.value .language-wrapper:not(.active)~textarea{padding-right:48px}.value .actions a.o-icon-more{display:block;height:36px}.more-actions.active a.o-icon-more{border-bottom:1px solid #dfdfdf}.language-wrapper input[type=text].value-language{line-height:24px;background-color:transparent;border:0;min-height:0;padding:6px 42px 6px 6px;display:block;background-color:#fff}.language-wrapper.active input[type=text].value-language~textarea{padding-left:6px;border-top:0}.input-body .language-wrapper:not(.active) .language-label{display:none}.sidebar .language-label{font-weight:inherit}.language-wrapper .language-label,.value[data-data-type=uri] .input-body label{display:flex;align-items:flex-start;background-color:#fff;margin:0;padding:0 42px 0 6px;box-shadow:0 0 0 1px #dfdfdf}.value-label-text{background-color:rgba(0,0,0,.04);border-radius:2px;font-size:14px;margin:6px;padding:0 6px}.sidebar .value-annotation .value{padding-bottom:0}.sidebar .value-annotation label:after{content:none}.sidebar .value-annotation p.selected-resource{border-bottom:1px solid #dfdfdf}.sidebar .value-annotation-resource-select{margin:6px !important}.sidebar [data-data-type^=resource] .o-title:not(:empty){padding:0;border-bottom:0}.sidebar [data-data-type^=resource] .o-title:not(:empty) a:empty{display:none}.sidebar [data-data-type^=resource] .o-title:not(:empty) img{margin:6px}.sidebar [data-data-type^=resource] .o-title:not(:empty) a{padding:6px;width:100%}.non-properties{margin-bottom:12px}.resource-form .values .sortable-handle{width:12px;background-color:rgba(0,0,0,.04);border:1px solid #dfdfdf;border-radius:2px 0 0 2px;align-self:stretch;border-right:0;margin:0;display:flex;align-items:center;justify-content:center}.resource-form .values .sortable-handle:before{font-size:10px}.visibility{display:inline-block;padding:6px;margin-right:12px}.add .visibility:before,.edit .visibility:before{margin-right:.25em}.add .visibility [type=checkbox],.edit .visibility [type=checkbox]{margin-left:.5em}#add-item .remove.field{background-color:#ea7171;opacity:.6}.resource.input-option span{display:block;background-color:rgba(255,255,255,.5);padding:6px 10px 0;width:100%;float:left}.field-meta{width:30%;padding-right:6px;position:relative}.field-meta legend,.field-meta label,.field-meta .label{max-width:80%;padding:6px 0;display:inline-block}.field-meta legend{position:static;float:left}.field-meta .error{float:left}.field-meta ul{margin:0}.field-label-text{display:block}.template{display:none}.selector ul{list-style:none;padding-left:0}.selector>ul{margin-top:6px}.selector li{position:relative}.selector li.total-count-heading{background-color:#404e61;color:#fff;border-radius:3px;text-transform:uppercase;font-size:12px;padding:6px 10px}.selector li.total-count-heading>ul{margin:6px -10px -6px;border-radius:0 0 3px 3px}.selector li.selector-parent.empty{display:none}.selector li.show>ul{position:relative;top:0;left:0;overflow:visible}.selector .selectable-list{background-color:#fff;color:#676767;overflow:visible;border-radius:3px;font-weight:bold;position:relative;border:1px solid #dfdfdf;margin:6px 0 0;text-transform:uppercase;font-size:12px}.selector .selectable-list li{padding:6px 12px}.selector .selectable-list .selector-parent{cursor:pointer;padding-right:24px;margin-bottom:0}.selector .selectable-list .selector-parent:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;position:absolute;right:0;top:6px;width:18px}.selector .selectable-list .selector-parent.show:after{content:""}.selector .selectable-list .selector-parent:hover:before{content:"";position:absolute;top:0;bottom:0;left:0;width:5px;background-color:#dfdfdf}.selector .selectable-list .selector-parent:not(:last-of-type){border-bottom:1px solid #dfdfdf;padding-bottom:5px;border-color:#dfdfdf}.selector-parent ul{position:absolute;top:-9999px;left:-9999px}.selector-child{border-radius:0;font-weight:normal;padding:6px 10px;margin:0 -12px;font-size:16px;text-transform:none;width:calc(100% + 36px)}.selector-child:hover{background-color:rgba(0,0,0,.04)}.selector-child:last-of-type{margin-bottom:-6px}.selector .description{display:inline-block;vertical-align:top}.selector .description.no-comment{opacity:0}.selector .description .o-icon-info{display:inline-block;margin:0 6px 0 0;opacity:.75;width:1em}.selector .description .o-icon-info:hover+.field-comment{left:5px;right:0;top:36px;padding:3px 10px 3px 36px;line-height:18px;background-color:#fff;z-index:1;margin:0;border-bottom:1px solid #dfdfdf;font-size:12px}.selector .description .o-icon-info:hover+.field-comment:before{content:"";position:absolute;left:7px;top:-6px;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff}.selector .description .o-icon-info:hover+.field-comment.above{bottom:100%;top:auto}.selector .description .o-icon-info:hover+.field-comment.above:before{top:calc(100% - 6px);transform:rotate(180deg)}.selector .description .o-icon-info+.field-comment{position:absolute;top:-9999px;left:-9999px;width:calc(100% - 5px)}.selector .selectable{display:inline-block;width:calc(100% - 36px);word-wrap:break-word}.field-actions{width:60%;display:inline-block;margin:24px 0 0 30%}.field .field-label{display:inline-block}.field .field-description,.field .docs-link{font-size:14px;line-height:18px;position:static;text-align:left;height:auto}.field .field-description:not(:only-child){margin-bottom:6px}.field-description{display:block;margin-right:10px;line-height:36px;height:36px;position:absolute;top:0;right:0;text-align:right;left:0}.field-description .o-icon-info{margin:0;cursor:pointer}.field-description .field-comment.open{left:inherit;right:0px;top:36px;background-color:#333;color:#fff;border-radius:3px;z-index:1;max-width:100%;font-size:14px;padding:6px 5px;margin:12px 0}.field-description .field-comment.open.above{top:auto;bottom:30px}.field-description .field-comment.open:before{content:"";display:block;height:0;width:0;position:absolute;top:-6px;bottom:0;right:3px;font-size:16px;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:12px solid #333}.field-description .field-comment.open.above:before{top:auto;bottom:-12px;transform:rotate(180deg)}.field .docs-link:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-right:6px;font-size:14px;line-height:18px}.field-meta .expand,.field-meta .collapse{display:inline-block !important;margin-left:.5em !important;padding:0 !important;border:0 !important;width:auto !important}.field-meta .expand:after,.field-meta .collapse:after{float:none !important;margin-right:0 !important}.collapsible{display:none}.collapse+.collapsible{display:block;clear:both;overflow:hidden}.field-description .field-comment{position:absolute;top:-9999px;left:-9999px}.resource-property .field-term{display:block}.inputs{line-height:36px;width:70%}.inputs:only-child{width:100%}.inputs p:only-child{margin:0}.inputs label,.inputs select,.inputs textarea,.inputs input[type=text],.inputs input[type=password],.inputs input[type=email],.inputs input[type=url],.inputs input[type=date],.inputs input[type=datetime-local]{width:100%;min-height:36px;margin:6px 0}.inputs label:only-child,.inputs select:only-child,.inputs textarea:only-child,.inputs input[type=text]:only-child,.inputs input[type=password]:only-child,.inputs input[type=email]:only-child,.inputs input[type=url]:only-child,.inputs input[type=date]:only-child,.inputs input[type=datetime-local]:only-child{margin:0}.inputs textarea{resize:vertical;line-height:1.5;background-color:#fff;min-width:0}.inputs label{padding:6px 0;margin:0 24px 0 0}.inputs .button,.inputs button,.inputs input[type=submit]{margin:6px 0;line-height:24px}.inputs input:focus,.inputs textarea:focus{position:relative;z-index:100}#resource-values div.value{display:flex;align-items:stretch}#resource-values div.value:only-of-type .sortable-handle{display:none}.value{margin-bottom:6px}.value:last-of-type{margin-bottom:0}.value:last-of-type .remove-value{margin-bottom:0;box-shadow:none}.value.template{display:none}.inputs p.no-values{padding:12px;border-radius:3px;background-color:rgba(0,0,0,.04);line-height:24px}.inputs p.no-values:not(:only-child){display:none}.add-values{margin:6px 0 -3px}.add-values *{display:inline-block;min-width:36px;height:36px;border-radius:2px;text-align:center;margin:0}.inputs .add-values a.button{margin:0 0 3px}.inputs .add-values a.button:before{margin-right:.25em}.add-values label{background-color:rgba(0,0,0,.04);line-height:36px;margin-right:0;overflow:hidden;width:12px;vertical-align:top}.input-footer{display:flex;width:30px}.input-footer .actions{margin-left:6px;flex-direction:column}.input-footer .actions a:before{line-height:36px;height:36px;text-align:center}.more-actions ul{padding:0;display:none}.more-actions.active{box-shadow:0 0 0 1px #dfdfdf;background-color:#fff;border-radius:2px}.more-actions.active ul{display:block}.value.delete{background-color:#fcc;overflow:hidden}.value .restore-value,.value.delete a.tab,.value.delete [class*=o-icon-]:not(.restore-value),.value.delete .block-page-layout-grid-controls{display:none}.value.delete .input-footer{background-color:transparent;width:100%}.value.delete .restore-value{display:inline-block}.value [class*=o-icon-].label{position:absolute;top:0;left:0;height:36px;width:36px;background-color:rgba(0,0,0,.04);text-align:center;line-height:36px;overflow:hidden}.value label,.add-values label{margin:0;min-height:0;line-height:24px}.block.value .inputs label{margin-right:24px}.add-values button,.add-values .button{line-height:24px}.inputs .value textarea,.inputs .value input[type=text]{width:100%;margin:0}.inputs .value textarea{min-height:72px;border:0;box-shadow:0 0 0 1px #dfdfdf}.inputs .value .input-body>textarea{padding:6px 12px}[data-data-type^=resource] .default,[data-data-type^=resource] .o-title:not(:empty){padding:6px;border-bottom:1px solid #dfdfdf;word-wrap:break-word;line-height:24px;display:flex}[data-data-type^=resource].delete .o-icon-undo:before{padding-right:0}.input-body{clear:both;background-color:#fff;flex:1;position:relative;box-shadow:0 0 0 1px inset #dfdfdf;max-width:calc(100% - 30px)}.value:not(:only-of-type) .input-body{max-width:calc(100% - 48px)}.inputs .input-body input[type=text]{margin:0;background-color:transparent}.inputs .input-body input[type=text]:focus,.inputs .input-body textarea:focus{z-index:10}.inputs .input-body .chosen-container{max-width:calc(100% - 12px);margin:6px}[data-data-type^=resource] .button{font-size:14px;padding:0 6px;line-height:24px;min-height:0;margin-right:3px}[data-data-type^=resource] .button:before{margin-right:6px}.value.delete span.restore-value{display:inline-block;padding:0 6px;width:calc(100% - 36px)}.value.delete>*:not(.input-footer){display:none}.sortable-handle~.input-body{background-color:transparent}.resource-inputs{background-color:#fff;box-shadow:0 0 0 1px #dfdfdf}p.selected-resource{position:relative;width:100%;margin:0}.selected-resource a{width:calc(100% - 72px)}.selected-resource+a.button{margin-left:6px}.selected-resource img{height:24px;margin-right:6px}.selected-resource .o-title a:after{font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin:0 6px}.selected-resource .items a:after{content:""}.selected-resource .item_sets a:after{content:""}.selected-resource .media a:after{content:""}[data-data-type=literal] .sortable-handle~.input-body{background-color:#fff}.inputs [data-data-type=literal] textarea.input-value{background-color:transparent;padding-right:42px}[data-data-type=uri] .input{position:relative;clear:both;background-color:#fff;box-shadow:0 0 0 1px #dfdfdf}[data-data-type=uri] .input:first-child{border-bottom:1px solid #dfdfdf}.value[data-data-type=uri] .input-body label{padding-right:0}.sidebar [data-data-type=uri] label{font-weight:inherit}[data-data-type=uri] .input-body input.uri-value,[data-data-type=uri] textarea.value-label{height:36px;border:0;box-shadow:none;padding:6px 42px 6px 6px;font-weight:normal;background:transparent;min-height:36px}[data-data-type=uri] textarea.value-label{border-top-width:0}.annotation-form{padding-bottom:12px}.annotation-form>div,.annotation-form>select{margin-bottom:6px}.value-annotation:not(:last-child){border-bottom:1px solid #dfdfdf;padding-bottom:12px;margin-bottom:12px}.value-annotation .restore-value{line-height:36px}#resource-files button{margin:24px 0 0}#add-media-field{margin-bottom:0}.media.row{padding:6px;margin-bottom:6px;display:flex;align-items:center;word-wrap:break-word}.media.row img{width:36px;height:auto;margin-right:12px}.media.row .resource-name{margin-right:12px;min-width:0}.media.row .primary-media{text-transform:uppercase;font-size:12px;font-weight:bold;margin:0 0 0 auto}.media.row .primary-media input{margin-left:6px}.media.row .actions{margin-left:24px}.media.value.delete span.restore-value{padding:0}.media.value.delete>*:not(.restore-value),.media.value.delete .actions a:not(.o-icon-undo){display:none}.media.value.delete>.actions{display:block;top:18px}.media-header{font-size:16px;margin:6px -6px;margin-top:-12px;background-color:rgba(0,0,0,.04);padding:0 6px;display:flex;align-items:center}.value.delete>.actions{display:inline-block}.media-render{margin-bottom:24px}.media-render>*{max-width:100%}.media-render img{max-width:100%;height:auto}#item-media .sidebar button{width:100%;text-align:left}.media-file-info{display:flex;align-items:flex-start;flex-wrap:wrap}.media-file-thumbnail img{vertical-align:bottom;margin:6px 12px 0 0}#item-item-sets+.no-resources:before,#site-item-sets+.no-resources:before{content:""}#item-item-sets tr.delete{background-color:#fcc}#page-actions [class*=o-icon-].button{background-color:transparent;width:auto;padding:6px 6px;box-shadow:none}.o-icon-private.button,.o-icon-public.button{margin-right:6px;box-shadow:none}#item-sites.empty+.no-resources:before{content:""}.media.edit #media .cke_contents{min-height:500px}.search-nav{width:100%}.search-nav .resource-search{width:100%;position:relative;margin-bottom:6px;display:flex;flex-wrap:wrap}.search-nav .chosen-container{margin-bottom:6px}.search-nav button.o-icon-search{height:36px;width:36px;line-height:24px;padding:0 10px;border-radius:0 3px 3px 0;min-height:0;position:relative;text-indent:-9999px;margin:0}.search-nav button.o-icon-search:before{text-indent:0px;position:absolute;left:0;top:6px;line-height:24px;width:100%}.search-nav .resource-search>input[type=text]{width:calc(100% - 36px);border-right:0;margin-bottom:6px}.resource-search-filters{padding-bottom:5px;border-bottom:1px solid #dfdfdf;margin-bottom:6px;width:100%}.resource-search-filters a.expand:after,.resource-search-filters a.collapse:after{float:right}.resource-search-filters .collapsible{margin-top:6px;overflow:visible}.sidebar .pagination{font-size:13.08px;border-bottom:1px solid rgba(0,0,0,.08);padding-bottom:11px;margin-bottom:0;overflow:hidden;width:100%}.sidebar .pagination li{float:left}.sidebar .pagination li:first-of-type{padding-right:10px}.sidebar .pagination input{width:3em;text-align:center;color:#333;margin:0 3px}.sidebar .pagination .next.button{margin-right:5px}.sidebar .pagination input[type=text]{float:left;line-height:19.62px;height:24px;border:1px solid #dfdfdf;margin-left:0}.sidebar .pagination .page-count{float:left;margin-right:12px}.sidebar .pagination .inactive{background-color:#e6e6e6;color:#b9b9b9}.sidebar textarea{resize:vertical}#item-results+.confirm-panel,#item-results .select-resource-checkbox-wrapper{display:none}#item-results.active{padding-bottom:72px}#item-results.active+.confirm-panel{display:block}#item-results.active .select-resource-checkbox-wrapper{display:inline-flex;align-items:center}.sidebar button.select-all,.sidebar button.quick-select-toggle{background-color:transparent;color:#676767;box-shadow:none;margin:12px;padding:0;line-height:1;min-height:0}.success-statuses{position:absolute}.success-statuses .status,.sidebar button .sr-only{display:none}.sidebar button:not(.active) .sr-only.off,.sidebar button.active .sr-only.on,.success-statuses:not(.active) .sr-only.off,.success-statuses.active .sr-only.on{display:block}.sidebar button.select-all:before,.sidebar button.quick-select-toggle:before{font-family:"Font Awesome 5 Free";font-weight:900;content:"";display:inline-block;margin-right:6px}.sidebar button.quick-select-toggle.active:before{content:""}.sidebar button.select-all:before{content:"";font-weight:400}.sidebar button.select-all.active:before{content:""}.sidebar button.quick-select-toggle+.resource-list{border-top:1px solid #dfdfdf}.resource-link{display:inline-flex;align-items:center;max-width:100%;min-width:0}.resource-link img{height:36px;margin-right:6px}.resource-link .resource-name{flex:1;min-width:0}.resource-list{width:100%}.resource-list .resource{padding:6px 12px 5px;border-bottom:1px solid rgba(0,0,0,.08);position:relative;width:100%;overflow:hidden;display:flex;align-items:center;word-wrap:break-word}.resource-list .resource:hover{background-color:rgba(255,255,255,.8)}.resource-list .resource:hover .select{right:0px}.resource-list .resource .select-resource-checkbox-wrapper{height:24px;margin-right:12px}#resource-details{background-color:#fff;overflow:hidden;padding:0}#resource-details .o-description,#resource-details .property{margin-bottom:0}.confirm-main{position:absolute;top:0;bottom:60px;overflow-y:auto;left:0;right:0;padding:12px 12px 0}.confirm-panel{position:absolute;bottom:0;right:0;left:0;padding:12px;background-color:#f7f7f7;border-top:1px solid #dfdfdf}.confirm-panel button,.confirm-panel .button{width:100%;margin:0}.sidebar .field-meta{width:100%;position:relative;padding-right:36px;margin-bottom:12px;border-bottom:3px solid #dfdfdf}.sidebar .field-meta .label,.sidebar .field-meta label{margin:0;width:auto;display:inline-block;padding:0 0 6px}.sidebar .field-meta .label:after,.sidebar .field-meta label:after{content:none}.sidebar .field-meta .collapsible{margin-bottom:12px}.sidebar .field-meta button.add-value{padding:0;background:transparent;color:#676767;min-height:0;position:absolute;top:0;right:0}.sidebar .field-meta button.add-value:before{height:auto;line-height:1.5}.sidebar .inputs{width:100%}.sidebar #advanced-search .value{flex-wrap:wrap}.sidebar #advanced-search .value:not(:first-child){margin-top:6px}.sidebar .multi-value .value:not(:only-child){width:calc(100% - 36px);position:relative;padding-bottom:0;margin-bottom:5px;border-bottom:0}.sidebar .multi-value .value:only-child .remove-value{display:none}.sidebar .multi-value .remove-value{position:absolute;right:-36px;bottom:0}.sidebar #advanced-search .value select,.sidebar #advanced-search .value input{margin-left:0}.sidebar #advanced-search .confirm-panel{display:flex;justify-content:space-between}.sidebar #advanced-search .confirm-panel button{width:calc(33.33% - 6px)}.block .block-content input[type=hidden]+button{padding-top:6px}.query-form-element .active{display:block}.query-form-element .inactive{display:none}.query-display .search-filters{margin-bottom:0}.query-display .filter{background-color:#fff;box-shadow:0 0 0 1px #dfdfdf inset}.query-display .filter-label{background-color:#dfdfdf}.query-form-element button.active{display:inline-block}.query-display{min-height:42px}input[type=text].query-form-query{margin-top:0}.query-display .filter-value:not(:last-child):after{content:none}#save-search{display:none}#save-search.active{display:flex;margin-top:-6px;padding:0 6px 12px calc(30% + 3px);background-color:rgba(0,0,0,.04)}#save-search.active input{margin-left:6px}.vocabs .field [type=file]{margin:6px 0 0}.vocabulary ul{padding-left:0;list-style:none;overflow:hidden}.vocabulary h2{margin-bottom:0}.vocabs.update td{vertical-align:top}.vocabs.update td:first-of-type,.vocabs.update td:nth-of-type(2){width:15%;word-wrap:break-word}.vocabs.update td:nth-of-type(3),.vocabs.update td:nth-of-type(4){width:35%}.vocabs.update td:nth-of-type(3):last-child{width:auto}.vocabs.update td:nth-of-type(3):not(:last-child){background-color:#ffe6e6}.vocabs.update td:nth-of-type(4){background-color:#cdffcd}.show .property,.meta-group{overflow:hidden;display:flex;justify-content:flex-end;flex-wrap:wrap}.show .property dt,.meta-group dt{width:22.2222222222%;vertical-align:top;padding:6px 0;font-weight:bold}.show .property dd,.show .property .values,.meta-group dd,.meta-group .values{padding:6px;margin:0;word-wrap:break-word;width:77.7777777778%}.show .property dd:not(:first-of-type),.show .property .values:not(:first-of-type),.meta-group dd:not(:first-of-type),.meta-group .values:not(:first-of-type){padding-top:0}.show .property .language,.meta-group .language{font-size:12px;padding:0 6px;margin-right:6px;background-color:rgba(0,0,0,.04)}#linked-filter label{display:flex;align-items:center;margin-bottom:24px}#linked-filter label select{margin-left:12px}#linked-resources table{margin-bottom:24px}#linked-resources caption{background-color:rgba(0,0,0,.04);font-family:bold;padding:6px;font-family:"Lato",sans-serif;font-weight:bold;text-align:left;font-size:20px}#linked-resources th{border-bottom:3px solid #dfdfdf}.linked-resource{margin-bottom:12px;padding-bottom:11px;border-bottom:1px solid #dfdfdf}.has-annotation:before{display:inline-block}.o-icon-annotation:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}.show .value.resource,.show .value.resource .value-content{display:flex;flex-wrap:wrap;align-items:center}.show .value .o-icon-private,.show .value .value-content{margin-right:12px}.collapsible.annotation{border-left:3px solid #dfdfdf;padding:0;border-radius:3px;margin:6px 0 12px 24px;width:100%}.collapsible.annotation h4,.collapsible.annotation .values{width:100%;padding:0}.collapsible.annotation .property{padding:0 12px}.collapsible.annotation .property:not(:first-child){margin-top:12px;border-top:1px solid #dfdfdf;padding-top:12px}.property .value .resource-name:after,.property .value.uri .uri-value-link:after{font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-left:.5em}.property .value.uri .uri-value-link:after{content:""}.property .value.items .resource-name:after{content:""}.property .value.media .resource-name:after{content:""}.property .value.item_sets .resource-name:after{content:""}.sidebar .meta-group.item-sites .o-icon-external{float:right}.class-row{border-bottom:1px solid #dfdfdf;padding-bottom:11px}.class-label{font-weight:bold}.class-label:after{content:": "}.sidebar{position:fixed;top:48px;left:100%;visibility:hidden;bottom:0;background-color:#f7f7f7;z-index:3;border-left:1px solid #dfdfdf;overflow-y:auto;overflow-x:hidden;width:25%;padding:12px}body.transitions-enabled .sidebar{transition:left .5s,visibility .5s}.sidebar.active,.sidebar.always-open{left:75%;visibility:visible}.sidebar.loading{overflow:hidden}.sidebar.loading *{visibility:hidden}.sidebar.loading:after{font-family:"Font Awesome 5 Free";font-weight:900;content:"";line-height:1;position:absolute;top:.75em;left:calc(50% - .5em);font-size:4em;animation:fa-spin 1s infinite linear;height:1em;width:1em;text-align:center}.sidebar a.o-icon-close{position:absolute;right:12px;top:12px;z-index:3;color:#666}.sidebar .vocabulary,.sidebar .meta-group{margin-bottom:0}.sidebar .value{margin-bottom:6px;border-bottom:1px solid #dfdfdf;padding-bottom:5px;vertical-align:middle}.sidebar .value *:last-child{margin-bottom:0}.sidebar .value:last-child{border-color:transparent;margin-bottom:0}.sidebar input,.sidebar textarea,.sidebar select{width:100%}.sidebar input[type=checkbox],.sidebar input[type=radio]{width:auto}.sidebar h2{font-size:24px;margin-bottom:12px}.sidebar h3,.sidebar label,.sidebar .label{display:block;font-size:16px;font-weight:bold;margin:0 0 12px 0;padding:0 24px 12px 0;position:relative;width:100%;word-wrap:break-word;max-width:none}.sidebar h3:after,.sidebar label:after,.sidebar .label:after{content:"";position:absolute;left:-12px;right:-12px;bottom:0;top:-12px;background-color:#dfdfdf;z-index:-1}.sidebar .field{background-color:transparent;padding:0;margin-bottom:24px;flex-wrap:wrap;justify-content:flex-start}.sidebar .field .option{width:100%}.sidebar .field div.option+div.option{padding-top:11px;border-top:1px solid #dfdfdf;margin-top:12px}.sidebar .button,.sidebar button{background-color:#676767;border-color:#676767;color:#fff}.sidebar .button:disabled,.sidebar .button.disabled,.sidebar button:disabled,.sidebar button.disabled{background-color:rgba(0,0,0,.04);border-color:rgba(0,0,0,.04);color:#676767;box-shadow:none !important}.sidebar button.option{width:100%;text-align:left;border-color:#dfdfdf;background-color:#fff;color:#676767;display:inline-flex;justify-content:space-between}.sidebar button.option:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;color:#dfdfdf}#sidebar-confirm{display:block;padding-bottom:12px;margin-bottom:12px}#sidebar-confirm input[type=submit]{background-color:#a91919;color:#fff;box-shadow:none}body.sidebar-open #content{width:56.25%}.sidebar .meta-group{margin-bottom:12px}.sidebar .meta-group .value{width:100%;padding:6px 0;margin:0;word-wrap:break-word;display:block}.sidebar .meta-group .value:not(:last-child){border-bottom:1px solid #dfdfdf;padding-bottom:5px}.sidebar .meta-group h4{display:block;background-color:transparent;border-color:#dfdfdf;padding:6px 0;border-bottom:2px solid #dfdfdf;padding-bottom:4px;margin-bottom:0;width:100%}.sidebar .media a:first-child img,.sidebar>img:first-child{height:168px;width:auto;display:block;margin-bottom:12px}.sidebar .meta-group img{height:48px;box-shadow:0 0 0 1px #dfdfdf}.source-type{font-weight:bold}.resource-templates #properties{list-style:none;padding-left:0;margin-left:0}.resource-templates table{width:100%}.resource-templates th,.resource-templates td{padding:6px;vertical-align:top}.resource-templates .property.row{display:flex}.resource-templates .property.row.delete{background-color:#fcc}.resource-templates .property.row.delete .actions li:not(:last-child){display:none}.resource-templates .property.row:not(.delete) .sortable-handle{display:inline-flex}.resource-templates #properties{margin:24px 0 0;clear:both;padding:0}.resource-templates #edit-sidebar{padding-bottom:48px}.resource-templates #edit-sidebar .field h4,.resource-templates #edit-sidebar .field h4+span{width:100%}.resource-templates #edit-sidebar .field h4+span{margin-bottom:12px}.resource-templates #edit-sidebar .field label:not(:first-child),.resource-templates #edit-sidebar .field .option label{margin:0;padding-bottom:6px;padding-right:0;display:flex;justify-content:space-between}.resource-templates #edit-sidebar .field label:not(:first-child):only-child,.resource-templates #edit-sidebar .field .option label:only-child{padding-bottom:0}.resource-templates #edit-sidebar .field label:not(:first-child):after,.resource-templates #edit-sidebar .field .option label:after{padding:0;margin:0;background:transparent}.alternate-label-cell:not(:empty){background-color:#dfdfdf;display:inline-block;padding:0 6px;margin:0 6px;position:relative}.alternate-label-cell:not(:empty):after{content:"";border-top:12px solid transparent;border-bottom:12px solid transparent;border-left:6px solid #dfdfdf;width:0;height:0;position:absolute;left:100%;top:0}.title-property-cell,.description-property-cell{text-transform:uppercase;font-size:12px;font-weight:bold;margin-left:auto;margin-right:12px}.title-property-cell:after,.description-property-cell:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin-left:6px}.title-property-cell~.actions,.description-property-cell~.actions{margin-left:0}.title-property-cell~.description-property-cell,.description-property-cell~.title-property-cell{margin-left:12px}#modules.installed tbody tr:not(.installed),#modules.uninstalled tbody tr:not(.uninstalled),#modules.needs-upgrade tbody tr:not(.needs-upgrade),#modules.active tbody tr:not(.active),#modules.deactivated tbody tr:not(.deactivated){display:none}.state-filter select{margin-bottom:12px}.module-name{font-weight:bold}.module-author{display:block}#modules .module{border-bottom:1px solid #dfdfdf;padding-bottom:11px;margin-bottom:12px;overflow:hidden}#modules .module-meta{float:left;max-width:50%}#modules .module-actions{float:right;max-width:50%;text-align:right}#modules .module form{display:inline-block}#modules button,#modules .button{display:inline-block;margin-left:6px;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset}#modules button:hover,#modules .button:hover{box-shadow:0 0 0 1px rgba(0,0,0,.3) inset}#modules button:before,#modules .button:before{margin-right:6px}#modules .o-icon-install{box-shadow:0 0 0 1px #addead inset}#modules .o-icon-install:hover{box-shadow:0 0 0 1px #63c363 inset}#modules .o-icon-uninstall{margin-left:24px;box-shadow:0 0 0 1px #e0c3c3 inset}#modules .o-icon-uninstall:hover{box-shadow:0 0 0 1px #da8b8b inset}#edit-keys td{word-wrap:break-word}.api-delete{width:10%}.api-label{width:25%}#system-info-table .label-col{width:25%}#system-info-table th,#system-info-table td{font-size:.875em;padding:0;line-height:1.75;border:none;vertical-align:top}#system-info-table th[scope=rowgroup]{font-size:1em;border-bottom:1px solid #dfdfdf;padding-left:6px}#system-info-table tbody:not(:last-child) tr:last-child td{padding-bottom:24px}#system-info-table th[scope=row]{padding-left:1.5em}.breadcrumbs{border-bottom:1px solid #dfdfdf;padding-bottom:11px;margin-bottom:24px}.breadcrumbs+.field{margin-top:24px}.breadcrumbs a:before{margin-right:6px}.breadcrumbs>*:not(:last-child):after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;display:inline-block;margin:0 calc(12px - 3px) 0 12px;color:#000;cursor:default}#site-item-sets th:first-child,#site-item-sets th:last-child{width:36px}.manual-assignment .inputs label{display:block;padding:0;margin:6px 0 0;min-height:0;line-height:24px}.manual-assignment .inputs label:last-child{margin-bottom:6px}.manual-assignment #advanced-search{margin-top:-6px;padding:12px 0 6px;background-color:rgba(0,0,0,.04);border-top:1px solid #dfdfdf}.manual-assignment #advanced-search.inactive{display:none}.manual-assignment .advanced-search-header{padding:0 6px}.manual-assignment .advanced-search-header a.button{margin-bottom:6px}.manual-assignment .advanced-search-content .field{background-color:transparent}.keep-search,.keep-search input{margin:0 0 0 6px}tr.value.delete>td:not(.input-footer){display:table-cell}tr.value.delete .user-name,tr.value.delete select,tr.value.delete .o-icon-delete{display:none}td.user-meta{width:50%}#site-user-permissions.empty+.no-resources:before{content:""}#site-user-permissions .actions{justify-content:flex-end;padding:6px 0}#block-controls-header{display:flex;justify-content:space-between;flex-wrap:wrap;margin-top:12px}#page-layout-controls{display:flex;align-items:center;justify-content:flex-end;margin-bottom:12px}#page-layout-label{display:flex;align-items:center}#page-layout-select{margin-left:6px}#page-layout-controls>*:not(:last-child){margin-right:6px}#page-layout-controls button{margin-bottom:0}.indent:before{content:"—";margin-right:-1px}.expand-collapse-all{text-align:right}.block{margin-bottom:6px}.block .block-header{position:relative;display:flex;align-items:center;background-color:rgba(0,0,0,.12);padding:6px;font-weight:bold}.block .block-header .actions a:before{text-align:center}.block .block-header .block-type{margin-right:auto}.block .block-header select{margin-right:6px;font-weight:normal}.block-page-layout-grid-controls+.actions{margin-left:0}.block .block-content input[type=hidden]+*{padding-top:0;margin-top:0}.block.html>div{border:1px solid #dfdfdf}.block .field{padding:0;border-color:transparent;background-color:transparent;margin-top:6px}.block .field:last-child{margin-bottom:0}.block.delete>.block-header{font-weight:normal;display:flex;background:transparent}.block.delete>*:not(.block-header){display:none}.block.delete span.restore-value{padding:0 3px;text-transform:lowercase;width:auto}.block.delete a.restore-value:before{padding:0}.block.delete .sortable-handle{display:none}.delete .block-type,.block .delete div.item-title{margin-left:30px}.delete .block-type{font-weight:bold}.block div.item-title{margin:6px 0;display:flex;align-items:center}.block .item-title img{height:36px;width:auto;display:inline-block;margin-right:6px;vertical-align:top}.block .delete.attachment{background-color:#fcc}.block .delete.attachment .actions .undo{display:inline-block}.block .delete.attachment .sortable-handle,.block .delete.attachment .actions li:not(.undo){display:none}.block .attachments-form{margin-bottom:12px}.block .attachments-form a h4{display:inline-block}.block .attachment .actions{margin-left:auto}.block .attachment .actions .button{background-color:transparent;color:#a91919;padding:0;min-height:0}.block .attachment .actions .button:hover{color:#a91919}.block .attachment .actions .undo{display:none}.block .block-content{clear:both;background-color:rgba(0,0,0,.04);padding:6px}.block.sortable-ghost .block-content{display:none}.block-content fieldset:last-of-type{margin-bottom:0}.block .attachment{display:flex;align-items:center;position:relative;padding:0 6px}.block .attachment:not(:last-child){border-bottom:1px solid #dfdfdf;padding-bottom:-1px}.block .attachment .button{margin-bottom:0}.block .attachment-add{margin:6px 0 0}.block-header.collapse:after{content:none}.block-content .expand,.block-content .collapse{width:100%;display:flex;padding:0 6px 0 0;justify-content:space-between}.block .field-meta .collapse+.collapsible{width:auto;border:0}.block .expand h4,.block .collapse h4{display:inline-block;padding:0}.block-content .collapse+.collapsible{border-top:1px solid #dfdfdf;padding:-1px 0 0 24px;margin-top:6px}.block[data-block-layout=html] [contenteditable=true]{resize:vertical;min-height:72px;max-height:288px}#attachment-options .option{position:relative;margin-bottom:12px}#attachment-options .expand,#attachment-options .collapse{position:absolute;right:0;top:0}#attachment-options h3{overflow:visible;white-space:normal}#attachment-item-select{display:block;margin:12px 0 0}#attachment-options .selected-attachment{margin-bottom:12px;margin-top:-12px;box-sizing:content-box;margin-right:-12px;margin-left:-12px;padding-right:12px;padding-left:12px;padding-top:12px;padding-bottom:12px;overflow:hidden}#attachment-options .selected-attachment img{height:96px;width:auto;float:right;margin:0 0 0 12px}#attachment-options .selected-attachment p:first-child{margin:0}#attachment-options h3.item-title{text-align:left}#attachment-options .item-thumbnail~h3.item-title{width:100%}#attachment-options .media-title{font-size:12px;display:block;width:calc(100% - 108px);float:left;word-wrap:break-word;text-align:left;clear:left}#attachment-options .item-thumbnail~#attachment-item-select{font-size:12px;display:inline-block;width:calc(100% - 108px);word-wrap:break-word}#attachment-options h3{word-wrap:break-word}#attachment-options .media-list{list-style:none;padding:0;margin:0 0 12px}#attachment-options .media-list li.media{position:relative;height:48px;width:48px;cursor:pointer;display:inline-block;padding:3px;border:1px solid #dfdfdf}#attachment-options .media-list li.media.attached,#attachment-options .media-list li.media:hover{background-color:rgba(0,0,0,.04)}#attachment-options .media-list img{width:100%;height:auto}#asset-options .selected-asset{overflow:hidden}#asset-options .selected-asset-image{float:left;margin:0 12px 0 0;max-width:50%}#asset-list.active{z-index:6}#asset-options .selected-asset .selected-asset-name{display:none}.asset-attachments-form{margin-bottom:12px}.add-asset-attachment{margin-top:6px}#asset-options .sidebar-content>div{margin-bottom:2rem}.asset-attachment-select{margin-top:.5rem}.asset-title{display:flex;align-items:center}.asset-title img{height:100%;width:auto}.asset-title .thumbnail:not(:empty){height:2rem;position:relative;width:2rem;margin:.25rem .25rem .25rem 0;overflow:hidden;display:inline-flex;justify-content:center}#asset-options .none-selected.inactive{display:none}#asset-options .none-selected:not(.inactive)~*{display:none}#asset-options .page-status{margin-bottom:12px}#asset-options .selected-page+.o-icon-external{margin-left:6px}#grid-layout-preview{display:grid;gap:6px}.grid-layout-previewing-block{min-height:60px;background-color:#dfdfdf}.hovered-block{box-shadow:0 0 0 1px #676767 inset}#grid-layout-preview .grid-layout-previewing{box-shadow:0 0 0 2px #676767 inset;display:flex;justify-content:center;align-items:center}.grid-layout-previewing.block{box-shadow:0 0 0 2px #676767 inset}.selected-tooltip:before{content:"";font-family:"Font Awesome 5 Free";font-weight:900}.browse-defualts-form-element{display:flex;justify-content:space-between}.browse-defualts-form-element select{width:49.5%}input[type=text].page-selector-filter{width:100%;margin-bottom:12px}#nav-page-links,#nav-custom-links{width:100%}.page-selector-filter.empty,#nav-page-links .nav-page-link,#nav-page-links .added.active.nav-page-link,#no-pages{display:none}#nav-page-links .active.nav-page-link{display:flex}.empty~#no-pages{display:block}.site-page-add{margin:0}.jstree>.jstree-node:first-child .jstree-anchor{margin-top:0}.block-pagelist-tree li:last-child{margin-bottom:6px}.selectable-themes,.current-theme{display:flex;flex-wrap:wrap}.selectable-themes img,.current-theme img{max-width:100%;height:auto;vertical-align:bottom;position:relative;z-index:1}.selectable-themes .error,.current-theme .error{background-color:#f4b4b4;border-radius:3px;padding:6px 10px;margin:6px 0;display:block;width:100%;order:2}.theme-thumbnail{align-self:flex-start}.current-theme .error+ul{font-family:monospace;padding:11px;border:1px solid #dfdfdf;list-style-type:none}.invalid .theme-thumbnail img{opacity:.5}.selectable-themes .theme{width:calc(33.33% - 24px);margin:0 24px 24px 0;padding:11px;border:1px solid #dfdfdf;background-color:#fff;display:flex;flex-wrap:wrap}.selectable-themes .theme:hover{border:3px solid #9f9f9f;padding:9px}.selectable-themes .invalid.theme:hover{border:1px solid #dfdfdf;padding:11px}.selectable-themes .theme-thumbnail{width:100%;margin-bottom:12px;border:1px solid #dfdfdf}.selectable-themes .active.theme{background-color:#e7e7e7;position:relative;overflow:hidden;border-width:3px;padding:9px}.selectable-themes .active.theme:after{content:"";font-family:"Font Awesome 5 Free";font-weight:900;position:absolute;bottom:0;right:0;opacity:.15;font-size:96px;line-height:96px}.current-theme{padding-bottom:23px;border-bottom:1px solid #dfdfdf;margin-bottom:24px;flex-wrap:nowrap}.current-theme .theme-thumbnail{width:50%;margin:0 24px 0 0;border:1px solid #dfdfdf}.current-theme .current-theme-info{width:calc(50% - 24px)}.current-theme-label{font-size:16px;text-transform:uppercase;display:block;margin-bottom:6px}.theme-meta{display:flex;flex-direction:column;width:100%}.theme-resource-pages .blocks{list-style:none;padding-left:0;border:1px solid #dfdfdf;padding:12px;min-height:30px}.theme-resource-pages .block{width:100%;background-color:rgba(0,0,0,.04);padding:6px;position:relative;margin-bottom:6px;display:flex;height:36px}.theme-resource-pages .block.delete{background-color:#fcc;padding-left:36px}.theme-resource-pages .block.delete>*:not(.block-header){display:block}.theme-resource-pages .block.delete .sortable-handle{display:none}.theme-resource-pages button:disabled{display:none}.jobs.browse th:first-child,.jobs.browse td:first-child{width:10%}body.minimal{padding:0;margin:48px 0;width:93.75%;max-width:100%;margin-left:auto;margin-right:auto;height:auto;background-color:#404e61}body.minimal:after{content:" ";display:block;clear:both}body.minimal div[role=main]>h1:first-of-type{position:static;padding:0;width:100%;height:auto;display:inline-block;margin:0 0 24px 0}body.minimal h2{font-size:20px;margin-bottom:12px}body.minimal h3{font-size:18px;margin-bottom:12px}body.minimal fieldset legend{font-weight:bold;font-size:20px;margin-bottom:12px}body.minimal .logo{position:static;width:auto;float:none;padding:0;text-align:center;font-size:32px;line-height:48px}body.minimal div[role=main]{width:100%;min-height:0;margin:0;padding:48px 6.25%;overflow:hidden}body.minimal .inputs{width:70%}body.minimal .inputs input{width:calc(66.66% - 6px);vertical-align:top}body.minimal .inputs *:only-child{width:100%}body.minimal [type=submit]{width:100%;display:block;margin:auto;clear:both}body.minimal .field:last-child{margin-bottom:0}body.minimal .site-list{margin-bottom:24px;display:flex;flex-wrap:wrap}body.minimal .site-list .site{margin-bottom:12px;overflow:auto;max-width:60rem;width:50%;padding-right:1rem}body.minimal .site-list .site-link{display:inline-block;font-size:18px}body.minimal .site-list .site-summary{margin:0;line-height:20px}body.minimal .site-list .site-thumbnail{float:left;display:block;margin-right:1rem}body.minimal .site-list .site-thumbnail-image{max-width:15rem;vertical-align:bottom}body.minimal .results{margin-bottom:24px}body.minimal .results>ul{padding-left:0}body.minimal .results>ul>li{list-style-type:none}body.minimal .advanced-search{margin:-12px 0 24px;display:block}body.minimal .advanced-search-actions{margin:12px 0}body.minimal .advanced-search-actions input[type=submit]{width:auto;display:inline-block}.forgot-password{margin:6px 0}.sitewide-search-form{display:flex;margin-bottom:24px}.sitewide-search-form input[type=text]{min-width:60%;margin-right:6px}.sitewide-search-form input[type=submit]{width:auto;margin:0}body.minimal .site.results thead{background-color:rgba(0,0,0,.04)}.results>ul{display:flex;flex-wrap:wrap;align-items:flex-start;margin-bottom:0}.results>ul>li{border:1px solid #dfdfdf;border-radius:3px;padding:6px 6px 0;margin-bottom:12px;width:calc(50% - 12px)}.results>ul>li:nth-child(2n){margin-left:12px}.results ul ul{list-style:none;padding:0;margin-top:6px}.results li li{padding:6px;border-top:1px solid #dfdfdf;margin:0px -6px}.results .result-title{background-color:rgba(0,0,0,.04);display:block;padding:6px;margin:-6px;font-weight:bold}.results+.pagination{margin-top:-24px}.site.results .result-title{border-bottom:1px solid #dfdfdf;margin-bottom:6px}.site.results .result-site{margin-bottom:6px;display:block}.asset-form-element{line-height:36px}.asset-form-element.empty .asset-form-clear{display:none}.asset-form-element:not(.empty) .no-selected-asset{display:none}.selected-asset,.no-selected-asset{display:block}.selected-asset-name:not(:empty)~.none-selected,.selected-page:empty+a,.selected-page:not(:empty)~.none-selected{display:none}.selected-asset-image{max-width:100%}.asset-form-select{margin-top:12px}.new.attachment{display:none}.asset-upload{overflow:hidden;margin-bottom:24px}.asset-upload button{margin:6px 0 0;display:none}.asset-upload button.active{display:inline-block}.asset-upload ul.errors{color:#a91919;margin-top:0;word-wrap:break-word}.asset-upload ul.errors:empty{display:none}.asset-upload ul.errors a{border-bottom:1px solid #a91919}.asset-upload label{margin:6px 0;padding:0}.asset-upload label:after{content:none}.asset-upload input[type=file]{width:100%}.asset-filters{margin-bottom:6px}.asset-list .asset{padding-bottom:5px;border-bottom:1px solid #dfdfdf;margin-bottom:6px}.asset-list .asset:last-child{border-bottom-color:transparent}.asset-entry{display:flex;align-items:center;word-wrap:break-word}.asset-entry img{margin-right:6px;max-height:48px;max-width:50%}.asset-entry .asset-name{flex-grow:1}.color-picker{display:flex}.color-picker input[type=text]{margin:0}.color-picker .color-picker-sample{border:1px solid #dfdfdf;width:30%;margin-left:6px}}@media screen and (max-width: 640px){script{display:none !important}body{padding:0}.mobile-only{display:block}button.mobile-only{width:100%}header{width:100%;float:none;text-align:center;position:fixed;top:0;left:0;padding:0;right:0;z-index:1000;min-height:0}header .button{border-radius:0px;position:absolute;top:0;z-index:1001;color:#fff;background-color:#222933;box-shadow:none}header .o-icon-menu.button{left:0;border-right:1px solid rgba(0,0,0,.08);width:36px}header .o-icon-search.button{left:36px}header .o-icon-user.button{right:0}header nav ul.navigation>li:not(:first-of-type){margin-top:0}.logo{line-height:36px;padding:0 16.6666666667%;width:100%;text-align:center;display:block;background-color:#404e61}#user,#search,header nav{position:fixed;top:-9999px;left:-9999px;z-index:1000}header nav#site-nav{position:static;background-color:#fff;padding:0;margin-bottom:0}header nav#site-nav h5{border-top:1px solid #dfdfdf;padding-top:6px -1px;margin-bottom:0}header nav#site-nav h5 a{padding:0;border-bottom:0}#menu.active,#user.active,#search.active{top:36px;left:0;bottom:0;right:0;background-color:#fff;margin:0}footer{margin:0;padding:0;position:static;width:100%;text-align:center}footer:after{position:static;background:transparent}.browse td:first-child,.browse th:first-child{width:100%}td .o-icon-private,td .o-icon-user-inactive{vertical-align:top;margin:0}div[role=main]{margin:36px 0 0 0;width:100%;min-height:calc(100% - 72px);position:relative;padding-top:48px}div[role=main]>h1:first-of-type{width:auto;position:static;padding:12px 1.0416666667%;height:auto;margin:0 -1.0416666667% 12px;white-space:normal;line-height:36px}#menu{text-align:left;background-color:#fff;position:fixed;overflow:scroll}#menu ul{margin-bottom:0;border-bottom:0;padding-bottom:0}#menu a{display:block;padding:6px 12px 5px;color:#676767;border-bottom:1px solid #dfdfdf}#menu li:last-child a{border-bottom:0;padding-bottom:6px}#menu h5 a{padding:0;border-bottom:0}#menu h5{height:36px;color:#676767;background-color:rgba(0,0,0,.04);padding:6px 12px 5px;border:1px solid #dfdfdf;border-width:1px 0}#menu h4{background-color:rgba(0,0,0,.12);margin-bottom:0}#menu h4:not(:first-of-type){margin-top:0}#menu a.public,#menu a.expand,#menu a.collapse{height:36px;margin:-36px 0 0;padding:0 12px 0 0}#menu a.public:before,#menu a.public:after,#menu a.expand:before,#menu a.expand:after,#menu a.collapse:before,#menu a.collapse:after{height:36px;line-height:36px}#mobile-nav{display:block}#mobile-nav a.active{background-color:#500c0c}#user{text-align:center}#user .user-id{color:#676767;width:100%;margin:0 6px 24px}#user .user-id a{color:#a91919}#user .logout{display:block;margin:12px 6px;font-size:16px;color:#676767;border-radius:3px;width:calc(100% - 12px);min-height:36px;background-color:rgba(0,0,0,.08);border-radius:3px;border:0;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset;padding:6px 10px;display:inline-block;text-align:center;cursor:pointer;margin:0 6px}#user .logout:last-of-type:before{content:""}#user .logout a{color:#676767}#page-actions{top:36px;background-color:#fff;width:100%;border-bottom:1px solid rgba(0,0,0,.08);height:48px;padding-bottom:5px}#sidebar{position:fixed;top:36px;z-index:100;width:100%}#sidebar #content.sidebar-open{left:0}body.sidebar-open #content{width:100%}.sidebar{width:100%;top:36px;z-index:1000}.sidebar.always-open{left:100%}.sidebar.active,.confirm-panel{left:0;width:100%}fieldset.section>.always.active{content:"";bottom:0;left:0;right:0;height:48px;background-color:#fff;position:fixed;border-top:1px solid rgba(0,0,0,.04)}fieldset.section>.always.active button{width:100%;margin:6px}#modules .module-meta,#modules .module-actions{width:100%;max-width:100%}#modules .module-meta{margin-bottom:12px}#modules .module-actions{text-align:left}#modules button,#modules .button{margin:0 6px 0 0}.vocabs.update td{width:100% !important}#search-form{margin:48px 4.1666666667%}.batch-edit.button{margin:0;border-radius:0px;position:relative;z-index:1}.browse table{position:relative}.browse .sorting{float:left}.browse .pagination{margin-right:48px}.jobs.browse th:first-child,.jobs.browse td:first-child{width:100%}fieldset.section,fieldset.section{margin-bottom:0;position:relative}fieldset.section>legend:first-child{position:relative;left:auto;display:block;width:100%;font-size:20px;padding:6px 9px 6px 0;color:#a91919;cursor:pointer;border-bottom:3px solid rgba(0,0,0,.08);padding-bottom:-3px;margin-bottom:12px}fieldset.section>legend:after{content:"";font-family:"Font Awesome 5 Free";position:absolute;right:9px;top:12px}fieldset.section.mobile-active>legend:after{content:""}.add .active.section>.button,.edit .active.section>.button{display:inline-block}.field-meta,.inputs{width:100%}.field-actions{position:absolute;top:9px;right:1.6666666667%;z-index:1;width:50%}.field-actions a{float:right;display:block}.field-actions a.button{margin-left:.5em !important}.field-meta label,.field-description p{line-height:24px;margin-bottom:6px}.field-meta label{font-weight:bold}.unset .field-meta{width:100%}.show .sidebar.active{position:static;border:1px solid #dfdfdf;padding:11px;margin-top:24px}.show .section .property,.show .section .meta-group{margin-bottom:6px;box-shadow:0 0 0 1px #dfdfdf;border-radius:2px}.show .section .meta-group h4,.show .section .property h4{padding-bottom:6px;border-bottom:1px solid #dfdfdf;background-color:rgba(0,0,0,.04)}.show .section .meta-group h4,.show .section .meta-group .value,.show .section .property h4,.show .section .property .values{width:100% !important;padding:6px !important}.show .section .meta-group .value:not(:first-of-type),.show .section .property .value:not(:first-of-type){border-top:1px solid #dfdfdf;padding-top:6px -1px;margin-top:6px}.show .sidebar .meta-group .value:not(:first-of-type),.show .sidebar .property .value:not(:first-of-type){padding-top:6px}body.minimal{width:100%;margin:0}body.minimal .logo{background-color:transparent}body.minimal div[role=main]{padding:24px 6.25%}body.minimal div[role=main]>.messages{margin-top:24px}body.minimal .inputs{width:100%;margin-left:0}body.minimal footer{color:#fff}.tablesaw tr{overflow:hidden;margin-bottom:0}.tablesaw tr:first-of-type{border-top:1px solid #dfdfdf}.browse td:not(:first-of-type) .tablesaw-cell-content,#properties td:not(:first-of-type) .tablesaw-cell-content{display:inline-block}.tablesaw td:first-of-type{background-color:rgba(0,0,0,.04)}.tablesaw td:first-of-type .tablesaw-cell-label{width:0;height:0;overflow:hidden;padding:0;display:block}.tablesaw td:first-of-type .tablesaw-cell-content{width:100%;max-width:100%}.batch-edit.tablesaw td:first-of-type{width:100%;background:rgba(0,0,0,.04)}.batch-edit.tablesaw td:first-of-type img{margin-bottom:0}.batch-edit.tablesaw td:first-of-type .tablesaw-cell-label{width:0;overflow:hidden;padding:0}.batch-edit .tablesaw-cell-content{display:inline-flex}.tablesaw-cell-content{width:70%;max-width:70%}.tablesaw-cell-content img{margin:0 6px 0 0}.tablesaw tr:last-of-type td,.tablesaw tr:last-of-type th,.tablesaw th,.tablesaw td{padding-top:6px;padding-bottom:6px;vertical-align:top}.tablesaw th:not(:last-of-type),.tablesaw td:not(:last-of-type){border-bottom:1px solid #dfdfdf}.tablesaw tr.delete{border:0}.tablesaw tr.delete td{border:0}.tablesaw tr.delete td:not(:first-of-type){display:none}.resource-template th:first-of-type,.resource-template td:first-of-type{width:100%}#site-user-permissions tr.user.value{position:relative}#site-user-permissions td:nth-child(3){position:absolute;top:0;right:0;padding:0 6px 0 0}#site-user-permissions td:nth-child(3) .tablesaw-cell-label{display:none}#site-user-permissions td:nth-child(3) .tablesaw-cell-content{width:100%;max-width:100%}#site-user-permissions.tablesaw-stack tbody tr{border-bottom:0}} \ No newline at end of file diff --git a/application/asset/js/asset-browse.js b/application/asset/js/asset-browse.js index b612c6d8e3..0ac32dd29f 100644 --- a/application/asset/js/asset-browse.js +++ b/application/asset/js/asset-browse.js @@ -12,14 +12,20 @@ jQuery(function ($) { processData: false }).done(function () { window.location.reload(); - }).fail(function (jqXHR) { + }).fail(function (jqXHR, textStatus, errorThrown) { var errorList = form.find('ul.errors'); errorList.empty(); - $.each(JSON.parse(jqXHR.responseText), function () { + if ('application/json' === jqXHR.getResponseHeader('content-type')) { + $.each(JSON.parse(jqXHR.responseText), function () { + errorList.append($('
%1$s"
-"code>
key_credential: %2$s
"
+"you navigate away from this page.
key_identity=%1$s"
+"code>
key_credential=%2$s
"
msgstr ""
-#: application/src/Controller/Admin/UserController.php:270
+#: application/src/Controller/Admin/UserController.php:281
msgid "user"
msgstr ""
-#: application/src/Controller/Admin/UserController.php:283
+#: application/src/Controller/Admin/UserController.php:294
msgid "User successfully deleted"
msgstr ""
-#: application/src/Controller/Admin/UserController.php:305
+#: application/src/Controller/Admin/UserController.php:316
msgid "You must select at least one user to batch delete."
msgstr ""
-#: application/src/Controller/Admin/UserController.php:312
+#: application/src/Controller/Admin/UserController.php:323
msgid "You can’t delete yourself."
msgstr ""
-#: application/src/Controller/Admin/UserController.php:321
+#: application/src/Controller/Admin/UserController.php:332
msgid "Users successfully deleted"
msgstr ""
-#: application/src/Controller/Admin/UserController.php:347
+#: application/src/Controller/Admin/UserController.php:358
msgid "Deleting users. This may take a while."
msgstr ""
-#: application/src/Controller/Admin/UserController.php:366
+#: application/src/Controller/Admin/UserController.php:377
msgid "You must select at least one user to batch edit."
msgstr ""
-#: application/src/Controller/Admin/UserController.php:373
+#: application/src/Controller/Admin/UserController.php:384
msgid "For security reasons, you can’t batch edit yourself."
msgstr ""
-#: application/src/Controller/Admin/UserController.php:394
+#: application/src/Controller/Admin/UserController.php:405
msgid "Users successfully edited"
msgstr ""
-#: application/src/Controller/Admin/UserController.php:447
+#: application/src/Controller/Admin/UserController.php:458
msgid "Editing users. This may take a while."
msgstr ""
@@ -5236,28 +5410,28 @@ msgstr ""
msgid "Editing item sets. This may take a while."
msgstr ""
-#: application/src/Controller/Admin/VocabularyController.php:59
+#: application/src/Controller/Admin/VocabularyController.php:58
msgid "vocabulary"
msgstr ""
-#: application/src/Controller/Admin/VocabularyController.php:97
+#: application/src/Controller/Admin/VocabularyController.php:92
#, php-format
msgid "Vocabulary successfully imported. %s"
msgstr ""
-#: application/src/Controller/Admin/VocabularyController.php:176
-msgid "Please review these changes before you accept them."
+#: application/src/Controller/Admin/VocabularyController.php:162
+msgid "Vocabulary successfully updated"
msgstr ""
-#: application/src/Controller/Admin/VocabularyController.php:184
-msgid "Vocabulary successfully updated"
+#: application/src/Controller/Admin/VocabularyController.php:167
+msgid "Please review these changes before you accept them."
msgstr ""
-#: application/src/Controller/Admin/VocabularyController.php:204
+#: application/src/Controller/Admin/VocabularyController.php:192
msgid "Changes to the vocabulary successfully made"
msgstr ""
-#: application/src/Controller/Admin/VocabularyController.php:220
+#: application/src/Controller/Admin/VocabularyController.php:208
msgid "Vocabulary successfully deleted"
msgstr ""
@@ -5283,65 +5457,65 @@ msgstr ""
msgid "Resource template successfully created. %s"
msgstr ""
-#: application/config/module.config.php:676
+#: application/config/module.config.php:704
msgid "Owner email"
msgstr ""
-#: application/config/module.config.php:682
-#: application/config/module.config.php:698
-#: application/config/module.config.php:703
+#: application/config/module.config.php:710
+#: application/config/module.config.php:726
+#: application/config/module.config.php:731
msgid "Item count"
msgstr ""
-#: application/config/module.config.php:692
+#: application/config/module.config.php:720
msgid "Resource class count"
msgstr ""
-#: application/config/module.config.php:693
+#: application/config/module.config.php:721
msgid "Property count"
msgstr ""
-#: application/config/module.config.php:865
+#: application/config/module.config.php:894
msgid "Something went wrong"
msgstr ""
-#: application/config/module.config.php:870
+#: application/config/module.config.php:899
msgid "You have unsaved changes."
msgstr ""
-#: application/config/module.config.php:871
+#: application/config/module.config.php:900
msgid "Restore item set"
msgstr ""
-#: application/config/module.config.php:872
+#: application/config/module.config.php:901
msgid "Close icon set"
msgstr ""
-#: application/config/module.config.php:873
+#: application/config/module.config.php:902
msgid "Open icon set"
msgstr ""
-#: application/config/module.config.php:875
+#: application/config/module.config.php:904
msgid "Failed loading resource template from API"
msgstr ""
-#: application/config/module.config.php:876
+#: application/config/module.config.php:905
msgid "Restore property"
msgstr ""
-#: application/config/module.config.php:878
+#: application/config/module.config.php:907
msgid "Please enter a valid language tag"
msgstr ""
-#: application/config/module.config.php:880
+#: application/config/module.config.php:909
msgid "Description"
msgstr ""
-#: application/config/module.config.php:881
+#: application/config/module.config.php:910
msgid "Unknown block layout"
msgstr ""
-#: application/config/module.config.php:882
+#: application/config/module.config.php:911
msgid "Required field must be completed"
msgstr ""
@@ -5349,6 +5523,30 @@ msgstr ""
msgid "Site admin"
msgstr ""
+#: application/view/common/advanced-search/visibility.phtml:3
+msgid "Search by visibility"
+msgstr ""
+
+#: application/view/common/advanced-search/visibility.phtml:8
+msgid "Select visibility…"
+msgstr ""
+
+#: application/view/common/advanced-search/sort.phtml:20
+msgid "Select sort by…"
+msgstr ""
+
+#: application/view/common/advanced-search/sort.phtml:26
+msgid "Select sort order…"
+msgstr ""
+
+#: application/view/common/advanced-search/has-media.phtml:4
+msgid "Search by media presence"
+msgstr ""
+
+#: application/view/common/advanced-search/has-media.phtml:9
+msgid "Select media presence…"
+msgstr ""
+
#: application/view/common/advanced-search/properties.phtml:70
msgid "[Any Property]"
msgstr ""
diff --git a/application/src/Api/Adapter/AbstractEntityAdapter.php b/application/src/Api/Adapter/AbstractEntityAdapter.php
index 7fcc24793b..9bca791536 100644
--- a/application/src/Api/Adapter/AbstractEntityAdapter.php
+++ b/application/src/Api/Adapter/AbstractEntityAdapter.php
@@ -121,20 +121,21 @@ public function buildBaseQuery(QueryBuilder $qb, array $query)
{
if (isset($query['id'])) {
$ids = $query['id'];
- if (is_string($ids) || is_int($ids)) {
+ if (is_int($ids)) {
+ $ids = [(string) $ids];
+ } elseif (is_string($ids)) {
// Account for comma-delimited IDs.
$ids = false === strpos($ids, ',') ? [$ids] : explode(',', $ids);
- } elseif (!is_array($ids)) {
+ } elseif (is_array($ids)) {
+ $ids = array_map('strval', $ids);
+ } else {
// This is an invalid ID. Set to an empty array.
$ids = [];
}
// Exclude null and empty-string IDs. Previous resource-only version
// used is_numeric, but we want this to be able to work for possible
// string IDs also.
- $ids = array_map('trim', $ids);
- $ids = array_filter($ids, function ($id) {
- return !($id === null || $id === '');
- });
+ $ids = array_filter(array_map('trim', $ids), 'strlen');
if ($ids) {
$qb->andWhere($qb->expr()->in(
'omeka_root.id',
diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php
index 16285a0519..12d3c26618 100644
--- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php
+++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php
@@ -4,6 +4,7 @@
use DateTime;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\QueryBuilder;
+use Laminas\EventManager\Event;
use Omeka\Api\Representation\ValueRepresentation;
use Omeka\Api\Request;
use Omeka\Entity\EntityInterface;
@@ -254,6 +255,11 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
return str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], (string) $string);
};
+ // See below "Consecutive OR optimization" comment
+ $previousPropertyId = null;
+ $previousAlias = null;
+ $previousPositive = null;
+
foreach ($query['property'] as $queryRow) {
if (!(is_array($queryRow)
&& array_key_exists('property', $queryRow)
@@ -270,13 +276,41 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
continue;
}
- $valuesAlias = $this->createAlias();
$positive = true;
+ if (in_array($queryType, ['neq', 'nin', 'nsw', 'new', 'nres', 'nex'])) {
+ $positive = false;
+ $queryType = substr($queryType, 1);
+ }
+ if (!in_array($queryType, ['eq', 'in', 'sw', 'ew', 'res', 'ex'])) {
+ continue;
+ }
+
+ // Consecutive OR optimization
+ //
+ // When we have a run of query rows that are joined by OR and share
+ // the same property ID (or lack thereof), we don't actually need a
+ // separate join to the values table; we can just tack additional OR
+ // clauses onto the WHERE while using the same join and alias. The
+ // extra joins are expensive, so doing this improves performance where
+ // many ORs are used.
+ //
+ // Rows using "negative" searches need their own separate join to the
+ // values table, so they're excluded from this optimization on both
+ // sides: if either the current or previous row is a negative query,
+ // the current row does a new join.
+ if ($previousPropertyId === $propertyId
+ && $previousPositive
+ && $positive
+ && $joiner === 'or'
+ ) {
+ $valuesAlias = $previousAlias;
+ $usePrevious = true;
+ } else {
+ $valuesAlias = $this->createAlias();
+ $usePrevious = false;
+ }
switch ($queryType) {
- case 'neq':
- $positive = false;
- // No break.
case 'eq':
$param = $this->createNamedParameter($qb, $value);
$subqueryAlias = $this->createAlias();
@@ -292,9 +326,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;
- case 'nin':
- $positive = false;
- // No break.
case 'in':
$param = $this->createNamedParameter($qb, '%' . $escapeSqlLike($value) . '%');
$subqueryAlias = $this->createAlias();
@@ -310,9 +341,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;
- case 'nsw':
- $positive = false;
- // No break.
case 'sw':
$param = $this->createNamedParameter($qb, $escapeSqlLike($value) . '%');
$subqueryAlias = $this->createAlias();
@@ -328,9 +356,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;
- case 'new':
- $positive = false;
- // No break.
case 'ew':
$param = $this->createNamedParameter($qb, '%' . $escapeSqlLike($value));
$subqueryAlias = $this->createAlias();
@@ -346,9 +371,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;
- case 'nres':
- $positive = false;
- // No break.
case 'res':
$predicateExpr = $qb->expr()->eq(
"$valuesAlias.valueResource",
@@ -356,9 +378,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;
- case 'nex':
- $positive = false;
- // No break.
case 'ex':
$predicateExpr = $qb->expr()->isNotNull("$valuesAlias.id");
break;
@@ -390,10 +409,13 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
$whereClause = $qb->expr()->isNull("$valuesAlias.id");
}
- if ($joinConditions) {
- $qb->leftJoin($valuesJoin, $valuesAlias, 'WITH', $qb->expr()->andX(...$joinConditions));
- } else {
- $qb->leftJoin($valuesJoin, $valuesAlias);
+ // See above "Consecutive OR optimization" comment
+ if (!$usePrevious) {
+ if ($joinConditions) {
+ $qb->leftJoin($valuesJoin, $valuesAlias, 'WITH', $qb->expr()->andX(...$joinConditions));
+ } else {
+ $qb->leftJoin($valuesJoin, $valuesAlias);
+ }
}
if ($where == '') {
@@ -403,6 +425,11 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
} else {
$where .= " AND $whereClause";
}
+
+ // See above "Consecutive OR optimization" comment
+ $previousPropertyId = $propertyId;
+ $previousPositive = $positive;
+ $previousAlias = $valuesAlias;
}
if ($where) {
@@ -550,6 +577,14 @@ public function getSubjectValues(Resource $resource, $page = null, $perPage = nu
->orderBy('property.id, resource_template_property.alternateLabel, resource.title')
->setMaxResults($perPage)
->setFirstResult($offset);
+ $event = new Event('api.subject_values.query', $this, [
+ 'queryBuilder' => $qb,
+ 'resource' => $resource,
+ 'propertyId' => $propertyId,
+ 'resourceType' => $resourceType,
+ 'siteId' => $siteId,
+ ]);
+ $this->getEventManager()->triggerEvent($event);
$results = $qb->getQuery()->getResult();
return $results;
}
@@ -573,6 +608,14 @@ public function getSubjectValuesSimple(Resource $resource, $propertyId = null, $
->join('value.property', 'property')
->join('property.vocabulary', 'vocabulary')
->select("CONCAT(vocabulary.prefix, ':', property.localName) term, IDENTITY(value.resource) id, resource.title title");
+ $event = new Event('api.subject_values_simple.query', $this, [
+ 'queryBuilder' => $qb,
+ 'resource' => $resource,
+ 'propertyId' => $propertyId,
+ 'resourceType' => $resourceType,
+ 'siteId' => $siteId,
+ ]);
+ $this->getEventManager()->triggerEvent($event);
return $qb->getQuery()->getResult();
}
@@ -677,7 +720,14 @@ public function getFulltextText($resource)
$services = $this->getServiceLocator();
$dataTypes = $services->get('Omeka\DataTypeManager');
$view = $services->get('ViewRenderer');
+ $eventManager = $this->getEventManager();
+
$criteria = Criteria::create()->where(Criteria::expr()->eq('isPublic', true));
+ $args = $eventManager->prepareArgs(['resource' => $resource, 'criteria' => $criteria]);
+ $event = new Event('api.get_fulltext_text.value_criteria', $this, $args);
+ $eventManager->triggerEvent($event);
+ $criteria = $args['criteria'];
+
$texts = [];
foreach ($resource->getValues()->matching($criteria) as $value) {
$valueRepresentation = new ValueRepresentation($value, $services);
@@ -685,7 +735,17 @@ public function getFulltextText($resource)
// Add value annotation text, if any.
$valueAnnotation = $value->getValueAnnotation();
if ($valueAnnotation) {
- foreach ($valueAnnotation->getValues()->matching($criteria) as $value) {
+ $valueAnnotationCriteria = Criteria::create()->where(Criteria::expr()->eq('isPublic', true));
+ $args = $eventManager->prepareArgs([
+ 'resource' => $resource,
+ 'value' => $value,
+ 'criteria' => $valueAnnotationCriteria,
+ ]);
+ $event = new Event('api.get_fulltext_text.value_annotation_criteria', $this, $args);
+ $eventManager->triggerEvent($event);
+ $valueAnnotationCriteria = $args['criteria'];
+
+ foreach ($valueAnnotation->getValues()->matching($valueAnnotationCriteria) as $value) {
$valueRepresentation = new ValueRepresentation($value, $services);
$texts[] = $dataTypes->getForExtract($value)->getFulltextText($view, $valueRepresentation);
}
diff --git a/application/src/Api/Adapter/AssetAdapter.php b/application/src/Api/Adapter/AssetAdapter.php
index a19ea2f190..9cf4d64854 100644
--- a/application/src/Api/Adapter/AssetAdapter.php
+++ b/application/src/Api/Adapter/AssetAdapter.php
@@ -9,8 +9,6 @@
class AssetAdapter extends AbstractEntityAdapter
{
- const ALLOWED_MEDIA_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/svg', 'image/svgz', 'image/svg+xml'];
-
protected $sortFields = [
'id' => 'id',
'media_type' => 'mediaType',
@@ -81,7 +79,8 @@ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $e
}
$tempFile->setSourceName($fileData['file']['name']);
- $validator = new Validator(self::ALLOWED_MEDIA_TYPES);
+ $config = $this->getServiceLocator()->get('Config');
+ $validator = new Validator($config['api_assets']['allowed_media_types'], $config['api_assets']['allowed_extensions']);
if (!$validator->validate($tempFile, $errorStore)) {
return;
}
diff --git a/application/src/Api/Adapter/MediaAdapter.php b/application/src/Api/Adapter/MediaAdapter.php
index a3779ff706..d16f4e5a21 100644
--- a/application/src/Api/Adapter/MediaAdapter.php
+++ b/application/src/Api/Adapter/MediaAdapter.php
@@ -4,6 +4,7 @@
use Doctrine\ORM\QueryBuilder;
use Omeka\Api\Request;
use Omeka\Media\Ingester\MutableIngesterInterface;
+use Omeka\Media\Renderer\FulltextSearchableInterface;
use Omeka\Entity\EntityInterface;
use Omeka\Entity\Item;
use Omeka\Media\Ingester\Fallback;
@@ -200,4 +201,16 @@ public function preprocessBatchUpdate(array $data, Request $request)
return $data;
}
+
+ public function getFulltextText($resource)
+ {
+ $renderer = $this->getServiceLocator()
+ ->get('Omeka\Media\Renderer\Manager')
+ ->get($resource->getRenderer());
+ $fulltextText = parent::getFulltextText($resource);
+ if ($renderer instanceof FulltextSearchableInterface) {
+ $fulltextText .= ' ' . $renderer->getFulltextText($this->getRepresentation($resource));
+ }
+ return $fulltextText;
+ }
}
diff --git a/application/src/Api/Adapter/SitePageAdapter.php b/application/src/Api/Adapter/SitePageAdapter.php
index e18600db6e..5a4fb6c83a 100644
--- a/application/src/Api/Adapter/SitePageAdapter.php
+++ b/application/src/Api/Adapter/SitePageAdapter.php
@@ -143,6 +143,14 @@ public function hydrate(Request $request, EntityInterface $entity,
$entity->setIsPublic($request->getValue('o:is_public', true));
}
+ if ($this->shouldHydrate($request, 'o:layout')) {
+ $entity->setLayout($request->getValue('o:layout', null));
+ }
+
+ if ($this->shouldHydrate($request, 'o:layout_data')) {
+ $entity->setLayoutData($request->getValue('o:layout_data', null));
+ }
+
$appendBlocks = $request->getOperation() === Request::UPDATE && $request->getOption('isPartial', false);
$this->hydrateBlocks($blockData, $entity, $errorStore, $appendBlocks);
$this->updateTimestamps($request, $entity);
@@ -226,6 +234,7 @@ private function hydrateBlocks(array $blockData, SitePage $page, ErrorStore $err
$block->setLayout($inputBlock['o:layout']);
$block->setData($inputBlock['o:data']);
+ $block->setLayoutData($inputBlock['o:layout_data'] ?? null);
// (Re-)order blocks by their order in the input
$block->setPosition($position++);
diff --git a/application/src/Api/Representation/AbstractResourceEntityRepresentation.php b/application/src/Api/Representation/AbstractResourceEntityRepresentation.php
index 6f0cd1a4ad..ec2bc60d34 100644
--- a/application/src/Api/Representation/AbstractResourceEntityRepresentation.php
+++ b/application/src/Api/Representation/AbstractResourceEntityRepresentation.php
@@ -67,6 +67,8 @@ public function getJsonLdType()
public function getJsonLd()
{
+ $settings = $this->getServiceLocator()->get('Omeka\Settings');
+
// Set the date time value objects.
$dateTime = [
'o:created' => [
@@ -109,8 +111,11 @@ public function getJsonLd()
// According to the JSON-LD spec, the value of the @reverse key "MUST be
// a JSON object containing members representing reverse properties."
// Here, we include the key only if the resource has reverse properties.
- $reverse = $this->subjectValuesForReverse();
- $reverse = $reverse ? ['@reverse' => $reverse] : [];
+ $reverse = [];
+ if (!$settings->get('disable_jsonld_reverse')) {
+ $reverse = $this->subjectValuesForReverse();
+ $reverse = $reverse ? ['@reverse' => $reverse] : [];
+ }
return array_merge(
[
@@ -427,6 +432,19 @@ public function subjectValuesForReverse($propertyId = null, $resourceType = null
return $subjectValues;
}
+ /**
+ * Get the total count of this resource's subject values.
+ *
+ * @param int|string|null $propertyId Filter by property ID
+ * @param string|null $resourceType Filter by resource type
+ * @param int|null $siteId Filter by site ID
+ * @return int
+ */
+ public function subjectValueTotalCount($propertyId = null, $resourceType = null, $siteId = null)
+ {
+ return $this->getAdapter()->getSubjectValueTotalCount($this->resource, $propertyId, $resourceType, $siteId);
+ }
+
/**
* Get value representations where this resource is the RDF subject.
*
@@ -515,7 +533,7 @@ public function displayValues(array $options = [])
* The should follow the pattern laid out in
* AbstractResourceEntityAdapter::getSubjectValuesQueryBuilder(). If a
* $resourceProperty isn't passed or is invalid, the default is all
- * properties for the "items" resource type.
+ * properties for the current resource type.
*
* @param array $options
* @return string
@@ -528,10 +546,34 @@ public function displaySubjectValues(array $options = [])
$viewName = $options['viewName'] ?? 'common/linked-resources';
$page = $options['page'] ?? null;
$perPage = $options['perPage'] ?? null;
- $resourceProperty = $options['resourceProperty'] ?? null;
$siteId = $options['siteId'] ?? null;
- $resourceType = 'items';
+ $subjectValuePropertiesItems = $adapter->getSubjectValueProperties($this->resource, 'items', $siteId);
+ $subjectValuePropertiesItemSets = $adapter->getSubjectValueProperties($this->resource, 'item_sets', $siteId);
+ $subjectValuePropertiesMedia = $adapter->getSubjectValueProperties($this->resource, 'media', $siteId);
+
+ if (!$subjectValuePropertiesItems && !$subjectValuePropertiesItemSets && !$subjectValuePropertiesMedia) {
+ // This resource has no subject values;
+ return null;
+ }
+
+ $resourcePropertiesAll = [
+ 'items' => $subjectValuePropertiesItems,
+ 'item_sets' => $subjectValuePropertiesItemSets,
+ 'media' => $subjectValuePropertiesMedia,
+ ];
+ // Find the default resource property by detecting the first resource
+ // type that has properties.
+ $defaultResourceProperty = null;
+ foreach ($resourcePropertiesAll as $resourceType => $resourceProperties) {
+ if ($resourceProperties) {
+ $defaultResourceProperty = sprintf('%s:', $resourceType);
+ break;
+ }
+ }
+ $resourceProperty = $options['resourceProperty'] ?? $defaultResourceProperty;
+
+ $resourceType = $adapter->getResourceName();
$propertyId = null;
if ($resourceProperty && false !== strpos($resourceProperty, ':')) {
// Derive the resource type and property ID from $resourceProperty.
@@ -539,18 +581,7 @@ public function displaySubjectValues(array $options = [])
}
$totalCount = $adapter->getSubjectValueTotalCount($this->resource, $propertyId, $resourceType, $siteId);
- if (!$totalCount) {
- return;
- }
$subjectValues = $this->subjectValues($page, $perPage, $propertyId, $resourceType, $siteId);
- if (!$subjectValues) {
- return;
- }
- $resourcePropertiesAll = [
- 'items' => $adapter->getSubjectValueProperties($this->resource, 'items', $siteId),
- 'item_sets' => $adapter->getSubjectValueProperties($this->resource, 'item_sets', $siteId),
- 'media' => $adapter->getSubjectValueProperties($this->resource, 'media', $siteId),
- ];
$partial = $this->getViewHelper('partial');
return $partial($viewName, [
diff --git a/application/src/Api/Representation/SitePageBlockRepresentation.php b/application/src/Api/Representation/SitePageBlockRepresentation.php
index eaa470df6a..dcc941107b 100644
--- a/application/src/Api/Representation/SitePageBlockRepresentation.php
+++ b/application/src/Api/Representation/SitePageBlockRepresentation.php
@@ -29,6 +29,7 @@ public function jsonSerialize(): array
return [
'o:layout' => $this->layout(),
'o:data' => $this->data(),
+ 'o:layout_data' => $this->layoutData(),
'o:attachment' => $this->attachments(),
];
}
@@ -79,6 +80,27 @@ public function dataValue($key, $default = null)
return $data[$key] ?? $default;
}
+ /**
+ * Get block layout data by key.
+ *
+ * @param string $key The layout data key
+ * @param mixed $default Return this if key does not exist
+ * @return mixed
+ */
+ public function layoutDataValue($key, $default = null)
+ {
+ $layoutData = $this->block->getLayoutData();
+ return $layoutData[$key] ?? $default;
+ }
+
+ /**
+ * @return array
+ */
+ public function layoutData()
+ {
+ return $this->block->getLayoutData();
+ }
+
public function attachments()
{
$attachments = [];
diff --git a/application/src/Api/Representation/SitePageRepresentation.php b/application/src/Api/Representation/SitePageRepresentation.php
index 96b87cde50..1d00bcc85a 100644
--- a/application/src/Api/Representation/SitePageRepresentation.php
+++ b/application/src/Api/Representation/SitePageRepresentation.php
@@ -25,6 +25,8 @@ public function getJsonLd()
'o:slug' => $this->slug(),
'o:title' => $this->title(),
'o:is_public' => $this->isPublic(),
+ 'o:layout' => $this->layout(),
+ 'o:layout_data' => $this->layoutData() ?? [],
'o:block' => $this->blocks(),
'o:site' => $this->site()->getReference(),
'o:created' => $created,
@@ -72,6 +74,35 @@ public function isPublic()
return $this->resource->isPublic();
}
+ /**
+ * @return ?string
+ */
+ public function layout()
+ {
+ return $this->resource->getLayout();
+ }
+
+ /**
+ * @return ?array
+ */
+ public function layoutData()
+ {
+ return $this->resource->getLayoutData();
+ }
+
+ /**
+ * Get layout data by key.
+ *
+ * @param string $key The layout data key
+ * @param mixed $default Return this if key does not exist
+ * @return mixed
+ */
+ public function layoutDataValue($key, $default = null)
+ {
+ $layoutData = $this->resource->getLayoutData();
+ return $layoutData[$key] ?? $default;
+ }
+
/**
* Get the blocks assigned to this page.
*
diff --git a/application/src/Controller/Admin/SystemInfoController.php b/application/src/Controller/Admin/SystemInfoController.php
index 9304ce6167..c16e4c9b95 100644
--- a/application/src/Controller/Admin/SystemInfoController.php
+++ b/application/src/Controller/Admin/SystemInfoController.php
@@ -82,6 +82,7 @@ private function getSystemInfo()
'Version' => sprintf('%s %s %s', php_uname('s'), php_uname('r'), php_uname('m')),
],
'Modules' => [],
+ 'Free space' => [],
'Paths' => [
'PHP CLI path' => sprintf(
'%s %s',
@@ -124,6 +125,25 @@ private function getSystemInfo()
}
}
+ $freeSpaceSystem = disk_free_space('.');
+ $info['Free space']['System'] = $this->formatSpace($freeSpaceSystem);
+ $freeSpaceFilesDir = $this->getDirFiles();
+ if ($freeSpaceFilesDir) {
+ $freeSpaceFiles = disk_free_space($freeSpaceFilesDir);
+ if ($freeSpaceFiles !== $freeSpaceSystem) {
+ $info['Free space']['Local files'] = $this->formatSpace($freeSpaceFiles);
+ }
+ // Manage the case where directory "original" is mounted separately.
+ $freeSpaceOriginal = disk_free_space($freeSpaceFilesDir . '/original');
+ if ($freeSpaceFiles !== $freeSpaceOriginal) {
+ $info['Free space']['Local files (original)'] = $this->formatSpace($freeSpaceOriginal);
+ }
+ }
+ $freeSpaceTemp = disk_free_space($this->getDirTemp());
+ if ($freeSpaceTemp !== $freeSpaceSystem) {
+ $info['Free space']['Temp dir'] = $this->formatSpace($freeSpaceTemp);
+ }
+
return $info;
}
@@ -171,4 +191,23 @@ public function getImagemagickPath()
{
return sprintf('%s/convert', $this->getImagemagickDir());
}
+
+ protected function getDirFiles(): ?string
+ {
+ $fileStore = $this->config['service_manager']['aliases']['Omeka\File\Store'];
+ if ($fileStore === 'Omeka\File\Store\Local') {
+ return $this->config['file_store']['local']['base_path'] ?: (OMEKA_PATH . '/files');
+ }
+ return null;
+ }
+
+ protected function getDirTemp(): ?string
+ {
+ return $this->config['temp_dir'] ?: sys_get_temp_dir();
+ }
+
+ protected function formatSpace($bytes): string
+ {
+ return sprintf('%1$.1f GiB', $bytes / (1024 * 1024 * 1024));
+ }
}
diff --git a/application/src/Controller/Admin/UserController.php b/application/src/Controller/Admin/UserController.php
index 8bbdf05edf..56844d59cb 100644
--- a/application/src/Controller/Admin/UserController.php
+++ b/application/src/Controller/Admin/UserController.php
@@ -8,6 +8,7 @@
use Omeka\Form\UserForm;
use Omeka\Mvc\Exception;
use Omeka\Stdlib\Message;
+use Laminas\Mail\Exception\ExceptionInterface as MailException;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
@@ -110,7 +111,12 @@ public function addAction()
$response = $this->api($form)->create('users', $formData['user-information']);
if ($response) {
$user = $response->getContent()->getEntity();
- $this->mailer()->sendUserActivation($user);
+ try {
+ $this->mailer()->sendUserActivation($user);
+ } catch (MailException $e) {
+ $this->logger()->err((string) $e);
+ $this->messenger()->addWarning('Unable to send user activation email.'); // @translate
+ }
$message = new Message(
'User successfully created. %s', // @translate
sprintf(
@@ -139,6 +145,11 @@ public function editAction()
$readResponse = $this->api()->read('users', $id);
$user = $readResponse->getContent();
$userEntity = $user->getEntity();
+
+ if (!$this->userIsAllowed($userEntity, 'update')) {
+ throw new Exception\PermissionDeniedException;
+ }
+
$currentUser = $userEntity === $this->identity();
$keys = $userEntity->getKeys();
@@ -241,7 +252,7 @@ public function editAction()
if ($keyPersisted) {
$message = new Message(
- 'API key successfully created.
Here is your key ID and credential for access to the API. WARNING: "key_credential" will be unretrievable after you navigate away from this page.
key_identity: %1$s
key_credential: %2$s
', // @translate
+ 'API key successfully created.
Here is your key ID and credential for access to the API. WARNING: "key_credential" will be unretrievable after you navigate away from this page.
key_identity=%1$s
key_credential=%2$s
', // @translate
$keyId, $keyCredential
);
$message->setEscapeHtml(false);
diff --git a/application/src/Controller/Admin/VocabularyController.php b/application/src/Controller/Admin/VocabularyController.php
index 4b3adbef4d..4d4bc5965f 100644
--- a/application/src/Controller/Admin/VocabularyController.php
+++ b/application/src/Controller/Admin/VocabularyController.php
@@ -1,7 +1,6 @@
getForm(VocabularyForm::class, ['include_namespace' => true]);
-
+ $form = $this->getForm(VocabularyForm::class);
$request = $this->getRequest();
if ($request->isPost()) {
$post = array_merge_recursive(
@@ -74,45 +72,39 @@ public function importAction()
$form->setData($post);
if ($form->isValid()) {
$data = $form->getData();
+ $strategy = null;
+ $options = [
+ 'format' => $data['vocabulary-file']['format'],
+ 'lang' => $data['vocabulary-advanced']['lang'],
+ 'label_property' => $data['vocabulary-advanced']['label_property'],
+ 'comment_property' => $data['vocabulary-advanced']['comment_property'],
+ ];
+ if ('upload' === $data['vocabulary-file']['import_type']) {
+ $strategy = 'file';
+ $options['file'] = $data['vocabulary-file']['file']['tmp_name'];
+ } elseif ('url' === $data['vocabulary-file']['import_type']) {
+ $strategy = 'url';
+ $options['url'] = $data['vocabulary-file']['url'];
+ }
try {
- $strategy = null;
- $options = [
- 'format' => $data['vocabulary-file']['format'],
- 'lang' => $data['vocabulary-advanced']['lang'],
- 'label_property' => $data['vocabulary-advanced']['label_property'],
- 'comment_property' => $data['vocabulary-advanced']['comment_property'],
- ];
- if (\UPLOAD_ERR_OK === $data['vocabulary-file']['file']['error']) {
- $strategy = 'file';
- $options['file'] = $data['vocabulary-file']['file']['tmp_name'];
- } elseif ($data['vocabulary-file']['url']) {
- $strategy = 'url';
- $options['url'] = $data['vocabulary-file']['url'];
- } else {
- throw new ValidationException($this->translate('Must provide a vocabulary file or a vocabulary URL'));
- }
$response = $this->rdfImporter->import($strategy, $data['vocabulary-info'], $options);
- if ($response) {
- $message = new Message(
- 'Vocabulary successfully imported. %s', // @translate
- sprintf(
- '%s',
- htmlspecialchars($this->url()->fromRoute(null, [], true)),
- $this->translate('Import another vocabulary?')
- ));
- $message->setEscapeHtml(false);
- $this->messenger()->addSuccess($message);
- return $this->redirect()->toRoute(null, ['action' => 'browse'], true);
- }
- } catch (ValidationException $e) {
+ $message = new Message(
+ 'Vocabulary successfully imported. %s', // @translate
+ sprintf('%s', htmlspecialchars($this->url()->fromRoute(null, [], true)), $this->translate('Import another vocabulary?'))
+ );
+ $message->setEscapeHtml(false);
+ $this->messenger()->addSuccess($message);
+ return $this->redirect()->toRoute(null, ['action' => 'browse'], true);
+ } catch (\Exception $e) {
$messages = [];
- // A message may be thrown directly from the RDF importer.
if ($e->getMessage()) {
$messages[] = $e->getMessage();
}
// Messages may be thrown from the API via the importer.
- foreach ($e->getErrorStore()->getErrors() as $message) {
- $messages[] = $message;
+ if (method_exists($e, 'getErrorStore')) {
+ foreach ($e->getErrorStore()->getErrors() as $message) {
+ $messages[] = $message;
+ }
}
$this->messenger()->addErrors($messages);
}
@@ -120,7 +112,6 @@ public function importAction()
$this->messenger()->addFormErrors($form);
}
}
-
$view = new ViewModel;
$view->setVariable('form', $form);
return $view;
@@ -128,24 +119,21 @@ public function importAction()
public function editAction()
{
- $form = $this->getForm(VocabularyForm::class);
$vocabulary = $this->api()->read('vocabularies', $this->params('id'))->getContent();
-
+ $form = $this->getForm(VocabularyForm::class, ['vocabulary' => $vocabulary]);
if ($vocabulary->isPermanent()) {
throw new Exception\PermissionDeniedException('Cannot edit a permanent vocabulary');
}
-
$data = [
'vocabulary-info' => [
'o:label' => $vocabulary->label(),
'o:comment' => $vocabulary->comment(),
+ 'o:namespace_uri' => $vocabulary->namespaceUri(),
],
];
$form->setData($data);
-
$view = new ViewModel;
$view->setVariable('vocabulary', $vocabulary);
-
$request = $this->getRequest();
if ($request->isPost()) {
$post = array_merge_recursive(
@@ -156,7 +144,6 @@ public function editAction()
if ($form->isValid()) {
$data = $form->getData();
$response = $this->api($form)->update('vocabularies', $this->params('id'), $data['vocabulary-info'], [], ['isPartial' => true]);
-
$strategy = null;
$options = [
'format' => $data['vocabulary-file']['format'],
@@ -164,31 +151,32 @@ public function editAction()
'label_property' => $data['vocabulary-advanced']['label_property'],
'comment_property' => $data['vocabulary-advanced']['comment_property'],
];
- if (\UPLOAD_ERR_OK === $data['vocabulary-file']['file']['error']) {
+ if ('upload' === $data['vocabulary-file']['import_type']) {
$strategy = 'file';
$options['file'] = $data['vocabulary-file']['file']['tmp_name'];
- } elseif ($data['vocabulary-file']['url']) {
+ } elseif ('url' === $data['vocabulary-file']['import_type']) {
$strategy = 'url';
$options['url'] = $data['vocabulary-file']['url'];
}
-
- if (null !== $strategy) {
- $this->messenger()->addSuccess('Please review these changes before you accept them.'); // @translate
+ if (null === $strategy) {
+ $this->messenger()->addSuccess('Vocabulary successfully updated'); // @translate
+ return $this->redirect()->toRoute(null, ['action' => 'browse'], true);
+ }
+ try {
$diff = $this->rdfImporter->getDiff($strategy, $vocabulary->namespaceUri(), $options);
+ $this->messenger()->addSuccess('Please review these changes before you accept them.'); // @translate
$form = $this->getForm(VocabularyUpdateForm::class);
$form->setAttribute('action', $this->url()->fromRoute(null, ['action' => 'update'], true));
$form->get('diff')->setValue(json_encode($diff));
$view->setVariable('diff', $diff);
$view->setTemplate('omeka/admin/vocabulary/update');
- } else {
- $this->messenger()->addSuccess('Vocabulary successfully updated'); // @translate
- return $this->redirect()->toRoute(null, ['action' => 'browse'], true);
+ } catch (\Exception $e) {
+ $this->messenger()->addError($e->getMessage());
}
} else {
$this->messenger()->addFormErrors($form);
}
}
-
$view->setVariable('form', $form);
return $view;
}
diff --git a/application/src/Controller/LoginController.php b/application/src/Controller/LoginController.php
index 9d55faacc9..f6a025ec69 100644
--- a/application/src/Controller/LoginController.php
+++ b/application/src/Controller/LoginController.php
@@ -7,6 +7,7 @@
use Omeka\Form\ActivateForm;
use Omeka\Form\ForgotPasswordForm;
use Laminas\Authentication\AuthenticationService;
+use Laminas\Mail\Exception\ExceptionInterface as MailException;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\Session\Container;
use Laminas\View\Model\ViewModel;
@@ -60,7 +61,10 @@ public function loginAction()
if ($redirectUrl = $session->offsetGet('redirect_url')) {
return $this->redirect()->toUrl($redirectUrl);
}
- return $this->redirect()->toRoute('admin');
+ if ($this->userIsAllowed('Omeka\Controller\Admin\Index', 'browse')) {
+ return $this->redirect()->toRoute('admin');
+ }
+ return $this->redirect()->toRoute('top');
} else {
$this->messenger()->addError('Email or password is invalid'); // @translate
}
@@ -163,7 +167,12 @@ public function forgotPasswordAction()
$this->entityManager->remove($passwordCreation);
$this->entityManager->flush();
}
- $this->mailer()->sendResetPassword($user);
+ try {
+ $this->mailer()->sendResetPassword($user);
+ } catch (MailException $e) {
+ $this->logger()->err((string) $e);
+ $this->messenger()->addWarning('Unable to send password reset email.'); // @translate
+ }
}
$this->messenger()->addSuccess('Check your email for instructions on how to reset your password'); // @translate
return $this->redirect()->toRoute('login');
diff --git a/application/src/Controller/Site/PageController.php b/application/src/Controller/Site/PageController.php
index 3040240815..c3b23ef91a 100644
--- a/application/src/Controller/Site/PageController.php
+++ b/application/src/Controller/Site/PageController.php
@@ -3,9 +3,17 @@
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
+use Omeka\Site\Theme\Theme;
class PageController extends AbstractActionController
{
+ protected $currentTheme;
+
+ public function __construct(Theme $currentTheme)
+ {
+ $this->currentTheme = $currentTheme;
+ }
+
public function browseAction()
{
$this->setBrowseDefaults('created');
@@ -41,6 +49,16 @@ public function showAction()
$view->setVariable('pageBodyClass', $pageBodyClass);
$view->setVariable('displayNavigation', true);
+ // Set the configured page template, if any.
+ $templateName = $page->layoutDataValue('template_name');
+ if ($templateName) {
+ // Verify that the current theme provides this template.
+ $config = $this->currentTheme->getConfigSpec();
+ if (isset($config['page_templates'][$templateName])) {
+ $view->setTemplate(sprintf('common/page-template/%s', $templateName));
+ }
+ }
+
$contentView = clone $view;
$contentView->setTemplate('omeka/site/page/content');
$contentView->setVariable('pageViewModel', $view);
diff --git a/application/src/Controller/SiteAdmin/IndexController.php b/application/src/Controller/SiteAdmin/IndexController.php
index 1b5366443b..7b4d04cb55 100644
--- a/application/src/Controller/SiteAdmin/IndexController.php
+++ b/application/src/Controller/SiteAdmin/IndexController.php
@@ -152,6 +152,7 @@ public function addPageAction()
$formData = $form->getData();
$formData['o:site']['o:id'] = $site->id();
$formData['o:is_public'] = !empty($post['o:is_public']);
+ $formData['o:layout_data']['template_name'] = $post['template_name'];
$response = $this->api($form)->create('site_pages', $formData);
if ($response) {
$page = $response->getContent();
diff --git a/application/src/Controller/SiteAdmin/PageController.php b/application/src/Controller/SiteAdmin/PageController.php
index 525c823f0a..24c7984321 100644
--- a/application/src/Controller/SiteAdmin/PageController.php
+++ b/application/src/Controller/SiteAdmin/PageController.php
@@ -1,6 +1,8 @@
pages();
$form = $this->getForm(SitePageForm::class);
- $form->setData($page->jsonSerialize());
+ $pageData = $page->jsonSerialize();
+ $form->setData($pageData);
if ($this->getRequest()->isPost()) {
$post = $this->params()->fromPost();
+ // Prepare block layout data.
+ foreach ($post['o:block'] as $key => $blockData) {
+ $post['o:block'][$key]['o:layout_data'] = json_decode($blockData['o:layout_data'], true);
+ }
$form->setData($post);
if ($form->isValid()) {
$response = $this->api($form)->update('site_pages', $page->id(), $post);
@@ -36,11 +43,21 @@ public function editAction()
}
}
+ // Populate the page layout data fieldset.
+ $pageLayoutDataForm = $this->getForm(PageLayoutDataForm::class);
+ $pageLayoutDataFormData = [];
+ foreach ($pageData['o:layout_data'] as $key => $value) {
+ $pageLayoutDataFormData[sprintf('o:layout_data[%s]', $key)] = $value;
+ }
+ $pageLayoutDataForm->setData($pageLayoutDataFormData);
+
$view = new ViewModel;
$view->setVariable('site', $site);
$view->setVariable('sitePages', $sitePages);
$view->setVariable('page', $page);
$view->setVariable('form', $form);
+ $view->setVariable('pageLayoutDataForm', $pageLayoutDataForm);
+ $view->setVariable('blockLayoutDataForm', $this->getForm(BlockLayoutDataForm::class));
return $view;
}
diff --git a/application/src/Db/Event/Subscriber/Entity.php b/application/src/Db/Event/Subscriber/Entity.php
index 75bb7fcc14..dc368a893a 100644
--- a/application/src/Db/Event/Subscriber/Entity.php
+++ b/application/src/Db/Event/Subscriber/Entity.php
@@ -2,6 +2,7 @@
namespace Omeka\Db\Event\Subscriber;
use Doctrine\Common\EventSubscriber;
+use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events as DoctrineEvent;
use Omeka\Entity\Resource as OmekaResource;
@@ -106,7 +107,7 @@ public function postUpdate(LifecycleEventArgs $args)
protected function trigger($eventName, LifecycleEventArgs $args)
{
$entity = $args->getEntity();
- $identifiers = [get_class($entity)];
+ $identifiers = [ClassUtils::getClass($entity)];
if ($entity instanceof OmekaResource) {
// Add the identifier for a generic resource entity.
$identifiers[] = 'Omeka\Entity\Resource';
diff --git a/application/src/Entity/Resource.php b/application/src/Entity/Resource.php
index e71ab1cb08..390b1985d8 100644
--- a/application/src/Entity/Resource.php
+++ b/application/src/Entity/Resource.php
@@ -12,6 +12,19 @@
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="resource_type", type="string")
+ * @Table(
+ * indexes={
+ * @Index(
+ * name="title",
+ * columns={"title"},
+ * options={"lengths":{190}}
+ * ),
+ * @Index(
+ * name="is_public",
+ * columns={"is_public"}
+ * )
+ * }
+ * )
*
* @see \Omeka\Db\Event\Listener\ResourceDiscriminatorMap
*/
diff --git a/application/src/Entity/SitePage.php b/application/src/Entity/SitePage.php
index c2dcf64dec..68e7fceb63 100644
--- a/application/src/Entity/SitePage.php
+++ b/application/src/Entity/SitePage.php
@@ -11,6 +11,12 @@
* @UniqueConstraint(
* columns={"site_id", "slug"}
* )
+ * },
+ * indexes={
+ * @Index(
+ * name="is_public",
+ * columns={"is_public"}
+ * )
* }
* )
*/
@@ -38,6 +44,16 @@ class SitePage extends AbstractEntity
*/
protected $isPublic = true;
+ /**
+ * @Column(type="string", nullable=true)
+ */
+ protected $layout;
+
+ /**
+ * @Column(type="json", nullable=true)
+ */
+ protected $layoutData;
+
/**
* @ManyToOne(targetEntity="Site", inversedBy="pages")
* @JoinColumn(nullable=false)
@@ -105,6 +121,26 @@ public function isPublic()
return (bool) $this->isPublic;
}
+ public function setLayout($layout)
+ {
+ $this->layout = $layout;
+ }
+
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+
+ public function setLayoutData($layoutData)
+ {
+ $this->layoutData = $layoutData;
+ }
+
+ public function getLayoutData()
+ {
+ return $this->layoutData;
+ }
+
public function setSite(Site $site)
{
$this->site = $site;
diff --git a/application/src/Entity/SitePageBlock.php b/application/src/Entity/SitePageBlock.php
index f039f82a9c..5a681c0e74 100644
--- a/application/src/Entity/SitePageBlock.php
+++ b/application/src/Entity/SitePageBlock.php
@@ -33,6 +33,11 @@ class SitePageBlock extends AbstractEntity
*/
protected $data;
+ /**
+ * @Column(type="json", nullable=true)
+ */
+ protected $layoutData;
+
/**
* @Column(type="integer")
*/
@@ -95,6 +100,16 @@ public function getPosition()
return $this->position;
}
+ public function setLayoutData($layoutData)
+ {
+ $this->layoutData = $layoutData;
+ }
+
+ public function getLayoutData()
+ {
+ return $this->layoutData;
+ }
+
public function setPage(SitePage $page)
{
$this->page = $page;
diff --git a/application/src/Entity/Value.php b/application/src/Entity/Value.php
index f62e503c6b..436463943b 100644
--- a/application/src/Entity/Value.php
+++ b/application/src/Entity/Value.php
@@ -7,7 +7,8 @@
* @Entity
* @Table(name="`value`", indexes={
* @Index(name="`value`", columns={"`value`"}, options={"lengths":{190}}),
- * @Index(name="`uri`", columns={"`uri`"}, options={"lengths":{190}})
+ * @Index(name="`uri`", columns={"`uri`"}, options={"lengths":{190}}),
+ * @Index(name="is_public", columns={"is_public"})
* })
*/
class Value extends AbstractEntity
diff --git a/application/src/File/Downloader.php b/application/src/File/Downloader.php
index 74199c2bab..1aff5512b8 100644
--- a/application/src/File/Downloader.php
+++ b/application/src/File/Downloader.php
@@ -73,6 +73,7 @@ public function download($uri, ErrorStore $errorStore = null)
);
$errorStore->addError('download', $message);
}
+ $tempFile->delete();
return false;
}
}
@@ -87,6 +88,7 @@ public function download($uri, ErrorStore $errorStore = null)
$errorStore->addError('download', $message);
}
$this->logger->err($message);
+ $tempFile->delete();
return false;
}
diff --git a/application/src/File/Uploader.php b/application/src/File/Uploader.php
index 34f84361f4..d50150f79e 100644
--- a/application/src/File/Uploader.php
+++ b/application/src/File/Uploader.php
@@ -48,6 +48,7 @@ public function upload(array $fileData, ErrorStore $errorStore = null)
$errorStore->addError('upload', $message);
}
}
+ $tempFile->delete();
return false;
}
$fileInput->getValue();
diff --git a/application/src/Form/BlockLayoutDataForm.php b/application/src/Form/BlockLayoutDataForm.php
new file mode 100644
index 0000000000..1f3ea46d82
--- /dev/null
+++ b/application/src/Form/BlockLayoutDataForm.php
@@ -0,0 +1,132 @@
+viewHelpers->get('escapeHtml');
+ $translate = $this->viewHelpers->get('translate');
+
+ // No need for CSRF protection on what is essentially a fieldset.
+ $this->remove('csrf');
+
+ // Get block templates configured by the current theme, if any.
+ $config = $this->currentTheme->getConfigSpec();
+ $blockTemplates = [];
+ if (isset($config['block_templates']) && is_array($config['block_templates'])) {
+ $blockTemplates = $config['block_templates'];
+ }
+ // Build select options for every block layout that has templates.
+ $valueOptions = [];
+ foreach ($blockTemplates as $layoutName => $templates) {
+ $valueOptions[$layoutName] = '';
+ foreach ($templates as $templateName => $templateLabel) {
+ $valueOptions[$layoutName] .= sprintf(
+ '',
+ $escapeHtml($templateName),
+ $escapeHtml($translate($templateLabel))
+ );
+ }
+ }
+ $this->add([
+ 'type' => 'select',
+ 'name' => 'template_name',
+ 'options' => [
+ 'label' => 'Template',
+ 'value_options' => [],
+ ],
+ 'attributes' => [
+ 'id' => 'block-layout-data-template-name',
+ 'data-block-templates' => json_encode($blockTemplates),
+ 'data-empty-option' => sprintf('', $translate('Default')),
+ 'data-value-options' => json_encode($valueOptions),
+ 'data-key' => 'template_name',
+ ],
+ ]);
+ $this->add([
+ 'name' => 'class',
+ 'type' => 'text',
+ 'options' => [
+ 'label' => 'Class', // @translate
+ ],
+ 'attributes' => [
+ 'id' => 'block-layout-data-class',
+ 'data-key' => 'class',
+ ],
+ ]);
+ $this->add([
+ 'name' => 'alignment',
+ 'type' => 'select',
+ 'options' => [
+ 'label' => 'Alignment', // @translate
+ 'empty_option' => 'Default', // @translate
+ 'value_options' => [
+ 'left' => 'Float left', // @translate
+ 'right' => 'Float right', // @translate
+ 'center' => 'Center', // @translate
+ ],
+ ],
+ 'attributes' => [
+ 'id' => 'block-layout-data-alignment',
+ 'data-key' => 'alignment',
+ ],
+ ]);
+ $this->add([
+ 'name' => 'background',
+ 'type' => 'Omeka\Form\Element\Background',
+ 'options' => [
+ 'label' => 'Background',
+ ],
+ ]);
+ $this->add([
+ 'name' => 'min_height',
+ 'type' => 'number',
+ 'options' => [
+ 'label' => 'Minimum height', // @translate
+ ],
+ 'attributes' => [
+ 'id' => 'block-layout-data-min-height',
+ 'data-key' => 'min_height',
+ 'min' => '0',
+ ],
+ ]);
+
+ /**
+ * Modules can add elements to this fieldset using the form.add_elements
+ * event. They can opt-in to automatically populate and apply the values
+ * by adding a "data-key" attribute containing the corresponding block
+ * layout data key. Elements that need more complex handling must attach
+ * to the following JS events on the document:
+ * - o:prepare-block-layout-data
+ * - o:apply-block-layout-data
+ */
+ $event = new Event('form.add_elements', $this);
+ $this->getEventManager()->triggerEvent($event);
+
+ // Note that we don't trigger form.add_input_filters because JS handles
+ // validation.
+ }
+
+ public function setCurrentTheme(Theme $currentTheme)
+ {
+ $this->currentTheme = $currentTheme;
+ }
+
+ public function setViewHelpers(HelperPluginManager $viewHelpers)
+ {
+ $this->viewHelpers = $viewHelpers;
+ }
+}
diff --git a/application/src/Form/Element/AbstractVocabularyMemberSelect.php b/application/src/Form/Element/AbstractVocabularyMemberSelect.php
index 7d40cd3ce4..4f5d282466 100644
--- a/application/src/Form/Element/AbstractVocabularyMemberSelect.php
+++ b/application/src/Form/Element/AbstractVocabularyMemberSelect.php
@@ -70,6 +70,7 @@ public function getValueOptions(): array
} elseif ('resource_classes' === $resourceName) {
$attributes['data-resource-class-id'] = $member->id();
}
+ $attributes['title'] = $member->term();
$option = [
'label' => $member->label(),
'value' => $termAsValue ? $member->term() : $member->id(),
diff --git a/application/src/Form/Element/ArrayTextarea.php b/application/src/Form/Element/ArrayTextarea.php
index 61414c2f2f..16ec8f32a4 100644
--- a/application/src/Form/Element/ArrayTextarea.php
+++ b/application/src/Form/Element/ArrayTextarea.php
@@ -121,7 +121,7 @@ protected function stringToList($string)
*/
protected function fixEndOfLine($string)
{
- return str_replace(["\r\n", "\n\r", "\r"], ["\n", "\n", "\n"], $string);
+ return str_replace(["\r\n", "\n\r", "\r"], ["\n", "\n", "\n"], (string) $string);
}
/**
diff --git a/application/src/Form/Element/Background.php b/application/src/Form/Element/Background.php
new file mode 100644
index 0000000000..214475c33a
--- /dev/null
+++ b/application/src/Form/Element/Background.php
@@ -0,0 +1,78 @@
+imageAssetElement = (new OmekaElement\Asset('background_image_asset'))
+ ->setAttributes([
+ 'id' => 'block-layout-data-background-image-asset',
+ 'data-key' => 'background_image_asset',
+ ]);
+
+ $this->positionYElement = (new LaminasElement\Select('background_position_y'))
+ ->setEmptyOption('Default') // @translate
+ ->setValueOptions([
+ 'top' => 'Top', // @translate
+ 'center' => 'Center', // @translate
+ 'bottom' => 'Bottom', // @translate
+ ])
+ ->setAttributes([
+ 'id' => 'block-layout-data-background-position-y',
+ 'data-key' => 'background_position_y',
+ ]);
+
+ $this->positionXElement = (new LaminasElement\Select('background_position_x'))
+ ->setEmptyOption('Default') // @translate
+ ->setValueOptions([
+ 'left' => 'Left', // @translate
+ 'center' => 'Center', // @translate
+ 'right' => 'Right', // @translate
+ ])
+ ->setAttributes([
+ 'id' => 'block-layout-data-background-position-x',
+ 'data-key' => 'background_position_x',
+ ]);
+ $this->sizeElement = (new LaminasElement\Select('background_size'))
+ ->setEmptyOption('Default') // @translate
+ ->setValueOptions([
+ 'cover' => 'Cover', // @translate
+ 'contain' => 'Contain', // @translate
+ ])
+ ->setAttributes([
+ 'id' => 'block-layout-data-background-size',
+ 'data-key' => 'background_size',
+ ]);
+ }
+
+ public function getImageAssetElement()
+ {
+ return $this->imageAssetElement;
+ }
+
+ public function getPositionYElement()
+ {
+ return $this->positionYElement;
+ }
+
+ public function getPositionXElement()
+ {
+ return $this->positionXElement;
+ }
+
+ public function getSizeElement()
+ {
+ return $this->sizeElement;
+ }
+}
diff --git a/application/src/Form/Element/PropertySelect.php b/application/src/Form/Element/PropertySelect.php
index daad72b61b..a882c05fd3 100644
--- a/application/src/Form/Element/PropertySelect.php
+++ b/application/src/Form/Element/PropertySelect.php
@@ -44,6 +44,7 @@ public function getValueOptions(): array
'attributes' => [
'data-term' => $property->term(),
'data-property-id' => $property->id(),
+ 'title' => $property->term(),
],
];
}
diff --git a/application/src/Form/PageLayoutDataForm.php b/application/src/Form/PageLayoutDataForm.php
new file mode 100644
index 0000000000..7d8b9f3c07
--- /dev/null
+++ b/application/src/Form/PageLayoutDataForm.php
@@ -0,0 +1,73 @@
+remove('csrf');
+
+ $config = $this->currentTheme->getConfigSpec();
+ $valueOptions = [];
+ if (isset($config['page_templates']) && is_array($config['page_templates'])) {
+ $valueOptions = $config['page_templates'];
+ }
+ $this->add([
+ 'type' => 'select',
+ 'name' => 'o:layout_data[template_name]',
+ 'options' => [
+ 'label' => 'Template',
+ 'empty_option' => 'Default', // @translate
+ 'value_options' => $valueOptions,
+ ],
+ 'attributes' => [
+ 'id' => 'template-name',
+ ],
+ ]);
+ $this->add([
+ 'type' => 'number',
+ 'name' => 'o:layout_data[grid_column_gap]',
+ 'options' => [
+ 'label' => 'Column gap',
+ ],
+ 'attributes' => [
+ 'id' => 'page-layout-grid-column-gap-input',
+ 'value' => '10',
+ 'min' => 0,
+ ],
+ ]);
+ $this->add([
+ 'type' => 'number',
+ 'name' => 'o:layout_data[grid_row_gap]',
+ 'options' => [
+ 'label' => 'Row gap',
+ ],
+ 'attributes' => [
+ 'id' => 'page-layout-grid-row-gap-input',
+ 'value' => '10',
+ 'min' => 0,
+ ],
+ ]);
+
+ $event = new Event('form.add_elements', $this);
+ $this->getEventManager()->triggerEvent($event);
+
+ // Note that we don't trigger form.add_input_filters because JS handles
+ // validation.
+ }
+
+ public function setCurrentTheme(Theme $currentTheme)
+ {
+ $this->currentTheme = $currentTheme;
+ }
+}
diff --git a/application/src/Form/ResourceBatchUpdateForm.php b/application/src/Form/ResourceBatchUpdateForm.php
index 051425342e..81cf70ad0a 100644
--- a/application/src/Form/ResourceBatchUpdateForm.php
+++ b/application/src/Form/ResourceBatchUpdateForm.php
@@ -367,7 +367,7 @@ public function preprocessData()
if (isset($data['clear_property_values'])) {
$preData['remove']['clear_property_values'] = $data['clear_property_values'];
}
- if (isset($data['set_value_visibility'])) {
+ if (!empty($data['set_value_visibility'])) {
$preData['remove']['set_value_visibility'] = $data['set_value_visibility'];
}
if (!empty($data['clear_language'])) {
diff --git a/application/src/Form/SettingForm.php b/application/src/Form/SettingForm.php
index 67fcced0eb..9e7b98f45c 100644
--- a/application/src/Form/SettingForm.php
+++ b/application/src/Form/SettingForm.php
@@ -64,6 +64,7 @@ class SettingForm extends Form
'image/pjpeg',
'image/png',
'image/tiff',
+ 'image/webp',
'image/x-icon',
// text/*
'text/css',
@@ -91,8 +92,8 @@ class SettingForm extends Form
'mp2', 'mp3', 'mp4', 'mpa', 'mpe', 'mpeg', 'mpg', 'mpp', 'odb', 'odc',
'odf', 'odg', 'odp', 'ods', 'odt', 'ogg', 'opus', 'pdf', 'png', 'pot', 'pps',
'ppt', 'pptx', 'qt', 'ra', 'ram', 'rtf', 'rtx', 'swf', 'tar', 'tif',
- 'tiff', 'txt', 'wav', 'wax', 'webm', 'wma', 'wmv', 'wmx', 'wri', 'xla', 'xls',
- 'xlsx', 'xlt', 'xlw', 'zip',
+ 'tiff', 'txt', 'wav', 'wax', 'webm', 'webp', 'wma', 'wmv', 'wmx', 'wri', 'xla',
+ 'xls', 'xlsx', 'xlt', 'xlw', 'zip',
];
/**
@@ -104,6 +105,9 @@ public function init()
{
$this->setOption('element_groups', [
'general' => 'General', // @translate
+ 'display' => 'Display', // @translate
+ 'editing' => 'Editing', // @translate
+ 'search' => 'Search', // @translate
'security' => 'Security', // @translate
]);
@@ -154,11 +158,69 @@ public function init()
],
]);
+ $this->add([
+ 'name' => 'locale',
+ 'type' => 'Omeka\Form\Element\LocaleSelect',
+ 'options' => [
+ 'element_group' => 'general',
+ 'label' => 'Locale', // @translate
+ 'info' => 'Global locale/language code for all interfaces.', // @translate
+ ],
+ 'attributes' => [
+ 'value' => $this->settings->get('locale'),
+ 'class' => 'chosen-select',
+ 'id' => 'locale',
+ ],
+ ]);
+
+ $this->add([
+ 'name' => 'version_notifications',
+ 'type' => 'Checkbox',
+ 'options' => [
+ 'element_group' => 'general',
+ 'label' => 'Enable version notifications', // @translate
+ 'info' => 'Enable notifications when a new version of Omeka S, modules, or themes are available.', // @translate
+ ],
+ 'attributes' => [
+ 'value' => $this->settings->get('version_notifications'),
+ 'id' => 'version_notifications',
+ ],
+ ]);
+
+ $this->add([
+ 'type' => 'checkbox',
+ 'name' => 'disable_jsonld_reverse',
+ 'options' => [
+ 'element_group' => 'general',
+ 'label' => 'Disable JSON-LD @reverse', // @translate
+ 'info' => 'Disable JSON-LD reverse properties in the API output for resources.', // @translate
+ ],
+ 'attributes' => [
+ 'value' => $this->settings->get('disable_jsonld_reverse'),
+ 'id' => 'disable-jsonld-reverse',
+ ],
+ ]);
+
+ $this->add([
+ 'name' => 'favicon',
+ 'type' => 'Omeka\Form\Element\Asset',
+ 'options' => [
+ 'element_group' => 'general',
+ 'label' => 'Favicon', // @translate
+ ],
+ 'attributes' => [
+ 'value' => $this->settings->get('favicon'),
+ 'id' => 'favicon',
+ ],
+ ]);
+
+ // Display element group
+
$this->add([
'name' => 'pagination_per_page',
'type' => 'Text',
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'display',
'label' => 'Results per page', // @translate
'info' => 'The maximum number of results per page on browse pages.', // @translate
],
@@ -173,7 +235,7 @@ public function init()
'name' => 'property_label_information',
'type' => 'Select',
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'display',
'label' => 'Property label information', // @translate
'info' => 'The additional information that accompanies labels on resource pages.', // @translate
'value_options' => [
@@ -192,7 +254,7 @@ public function init()
'name' => 'default_site',
'type' => SiteSelect::class,
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'display',
'label' => 'Default site', // @translate
'info' => 'Select which site should appear when users go to the front page of the installation.', // @translate
'empty_option' => '',
@@ -206,40 +268,11 @@ public function init()
],
]);
- $this->add([
- 'name' => 'locale',
- 'type' => 'Omeka\Form\Element\LocaleSelect',
- 'options' => [
- 'element_group' => 'general',
- 'label' => 'Locale', // @translate
- 'info' => 'Global locale/language code for all interfaces.', // @translate
- ],
- 'attributes' => [
- 'value' => $this->settings->get('locale'),
- 'class' => 'chosen-select',
- 'id' => 'locale',
- ],
- ]);
-
- $this->add([
- 'name' => 'version_notifications',
- 'type' => 'Checkbox',
- 'options' => [
- 'element_group' => 'general',
- 'label' => 'Enable version notifications', // @translate
- 'info' => 'Enable notifications when a new version of Omeka S, modules, or themes are available.', // @translate
- ],
- 'attributes' => [
- 'value' => $this->settings->get('version_notifications'),
- 'id' => 'version_notifications',
- ],
- ]);
-
$this->add([
'name' => 'disable_jsonld_embed',
'type' => 'Checkbox',
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'display',
'label' => 'Disable JSON-LD embed', // @translate
'info' => 'By default, Omeka embeds JSON-LD in resource browse and show pages for the purpose of machine-readable metadata discovery. Check this to disable embedding.', // @translate
],
@@ -249,11 +282,13 @@ public function init()
],
]);
+ // Editing element group
+
$this->add([
'name' => 'default_to_private',
'type' => 'Checkbox',
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'editing',
'label' => 'Default content visibility to Private', // @translate
'info' => 'If checked, all items, item sets and sites newly created will have their visibility set to private by default.', // @translate
],
@@ -267,7 +302,7 @@ public function init()
'name' => 'value_languages',
'type' => ArrayTextarea::class,
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'editing',
'label' => 'Suggested languages for values', // @translate
'info' => 'List of languages to facilitate filling of the values in the resource form. List them one by line. The label displayed for a language may be appended with a "=".', // @translate
'as_key_value' => true,
@@ -282,7 +317,7 @@ public function init()
'name' => 'media_alt_text_property',
'type' => PropertySelect::class,
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'editing',
'label' => 'Media alt text property', // @translate
'info' => 'Media property to use as alt text if no alt text is explicitly set.', // @translate
'empty_option' => '[None]', // @translate
@@ -295,11 +330,13 @@ public function init()
],
]);
+ // Search element group
+
$this->add([
'name' => 'index_fulltext_search',
'type' => 'Checkbox',
'options' => [
- 'element_group' => 'general',
+ 'element_group' => 'search',
'label' => 'Index full-text search', // @translate
],
'attributes' => [
diff --git a/application/src/Form/SitePageForm.php b/application/src/Form/SitePageForm.php
index 757e1adbf0..9f5e36c3af 100644
--- a/application/src/Form/SitePageForm.php
+++ b/application/src/Form/SitePageForm.php
@@ -2,9 +2,12 @@
namespace Omeka\Form;
use Laminas\Form\Form;
+use Omeka\Site\Theme\Theme;
class SitePageForm extends Form
{
+ protected $currentTheme;
+
public function init()
{
$this->setAttribute('id', 'site-page-form');
@@ -40,5 +43,12 @@ public function init()
],
]);
}
+
+ $inputFilter = $this->getInputFilter();
+ }
+
+ public function setCurrentTheme(Theme $currentTheme)
+ {
+ $this->currentTheme = $currentTheme;
}
}
diff --git a/application/src/Form/SiteSettingsForm.php b/application/src/Form/SiteSettingsForm.php
index 9bdfb58b13..97f7f74356 100644
--- a/application/src/Form/SiteSettingsForm.php
+++ b/application/src/Form/SiteSettingsForm.php
@@ -80,24 +80,6 @@ public function init()
'value' => $settings->get('show_page_pagination', true),
],
]);
- $this->add([
- 'name' => 'property_label_information',
- 'type' => 'Select',
- 'options' => [
- 'element_group' => 'general',
- 'label' => 'Property label information', // @translate
- 'info' => 'The additional information that accompanies labels on resource pages.', // @translate
- 'value_options' => [
- 'none' => 'None', // @translate
- 'vocab' => 'Show Vocabulary', // @translate
- 'term' => 'Show Term', // @translate
- ],
- ],
- 'attributes' => [
- 'id' => 'property_label_information',
- 'value' => $settings->get('property_label_information', 'none'),
- ],
- ]);
$this->add([
'name' => 'show_user_bar',
'type' => 'radio',
@@ -127,6 +109,35 @@ public function init()
'id' => 'disable_jsonld_embed',
],
]);
+ $this->add([
+ 'name' => 'favicon',
+ 'type' => 'Omeka\Form\Element\Asset',
+ 'options' => [
+ 'element_group' => 'general',
+ 'label' => 'Favicon', // @translate
+ ],
+ 'attributes' => [
+ 'value' => $settings->get('favicon'),
+ 'id' => 'favicon',
+ ],
+ ]);
+ $this->add([
+ 'name' => 'subnav_display',
+ 'type' => 'select',
+ 'options' => [
+ 'element_group' => 'general',
+ 'label' => 'Page subnavigation display', // @translate
+ 'empty_option' => 'Hide on leaf pages (default)', // @translate
+ 'value_options' => [
+ 'hide' => 'Hide on all pages', // @translate
+ 'show' => 'Show on all pages', // @translate
+ ],
+ ],
+ 'attributes' => [
+ 'value' => $settings->get('subnav_display'),
+ 'id' => 'disable_jsonld_embed',
+ ],
+ ]);
// Language section
$this->add([
@@ -265,6 +276,24 @@ public function init()
'value' => (bool) $settings->get('show_attached_pages', true),
],
]);
+ $this->add([
+ 'name' => 'property_label_information',
+ 'type' => 'Select',
+ 'options' => [
+ 'element_group' => 'show',
+ 'label' => 'Property label information', // @translate
+ 'info' => 'The additional information that accompanies labels on resource pages.', // @translate
+ 'value_options' => [
+ 'none' => 'None', // @translate
+ 'vocab' => 'Show Vocabulary', // @translate
+ 'term' => 'Show Term', // @translate
+ ],
+ ],
+ 'attributes' => [
+ 'id' => 'property_label_information',
+ 'value' => $settings->get('property_label_information', 'none'),
+ ],
+ ]);
$this->add([
'name' => 'show_value_annotations',
'type' => 'select',
@@ -403,6 +432,10 @@ public function init()
'name' => 'locale',
'allow_empty' => true,
]);
+ $inputFilter->add([
+ 'name' => 'subnav_display',
+ 'allow_empty' => true,
+ ]);
$inputFilter->add([
'name' => 'pagination_per_page',
'required' => false,
diff --git a/application/src/Form/View/Helper/FormBackground.php b/application/src/Form/View/Helper/FormBackground.php
new file mode 100644
index 0000000000..f850f8748b
--- /dev/null
+++ b/application/src/Form/View/Helper/FormBackground.php
@@ -0,0 +1,18 @@
+render($element);
+ }
+
+ public function render(ElementInterface $element)
+ {
+ return $this->getView()->partial('common/background-form', ['element' => $element]);
+ }
+}
diff --git a/application/src/Form/VocabularyForm.php b/application/src/Form/VocabularyForm.php
index 2ffe9fe75f..7dbf799991 100644
--- a/application/src/Form/VocabularyForm.php
+++ b/application/src/Form/VocabularyForm.php
@@ -5,8 +5,10 @@
class VocabularyForm extends Form
{
+ protected $translator;
+
protected $options = [
- 'include_namespace' => false,
+ 'vocabulary' => null,
];
public function __construct($name = null, $options = [])
@@ -16,6 +18,8 @@ public function __construct($name = null, $options = [])
public function init()
{
+ $vocabulary = $this->getOption('vocabulary');
+ $this->setAttribute('id', 'vocabulary-form');
$this->add([
'name' => 'vocabulary-info',
'type' => 'fieldset',
@@ -61,19 +65,23 @@ public function init()
'id' => 'o:comment',
],
]);
- if ($this->getOption('include_namespace')) {
- $this->get('vocabulary-info')->add([
- 'name' => 'o:namespace_uri',
- 'type' => 'text',
- 'options' => [
- 'label' => 'Namespace URI', // @translate
- 'info' => 'Enter the unique namespace URI used to identify the classes and properties of the vocabulary.', // @translate
- ],
- 'attributes' => [
- 'required' => true,
- 'id' => 'o:namespace_uri',
- ],
- ]);
+ $this->get('vocabulary-info')->add([
+ 'name' => 'o:namespace_uri',
+ 'type' => 'text',
+ 'options' => [
+ 'label' => 'Namespace URI', // @translate
+ 'info' => 'Enter the unique namespace URI used to identify the classes and properties of the vocabulary.', // @translate
+ ],
+ 'attributes' => [
+ 'required' => true,
+ 'id' => 'o:namespace_uri',
+ 'placeholder' => $vocabulary ? $vocabulary->namespaceUri() : null,
+ 'data-confirm-ends-with' => $this->translator->translate('The namespace URI you entered does not end with a / or #, as is normally expected for namespace URIs. Would you like to save anyway?'),
+ 'data-confirm-change' => $this->translator->translate('The namespace URI you entered does not match the saved namespace URI. Would you like to save anyway?'),
+ 'data-original-namespace-uri' => $vocabulary ? $vocabulary->namespaceUri() : null,
+ ],
+ ]);
+ if (!$vocabulary) {
$this->get('vocabulary-info')->add([
'name' => 'o:prefix',
'type' => 'text',
@@ -87,26 +95,41 @@ public function init()
],
]);
}
+ $this->get('vocabulary-file')->add([
+ 'name' => 'import_type',
+ 'type' => 'radio',
+ 'options' => [
+ 'label' => 'Import type', // @translate
+ 'value_options' => [
+ 'upload' => 'Upload', // @translate
+ 'url' => 'URL', // @translate
+ ],
+ ],
+ 'attributes' => [
+ 'value' => 'upload',
+ 'class' => 'import-type-select',
+ ],
+ ]);
$this->get('vocabulary-file')->add([
'name' => 'file',
'type' => 'file',
'options' => [
- 'label' => 'Vocabulary file', // @translate
- 'info' => 'Choose a RDF vocabulary file. You must choose a file or enter a URL below.', // @translate
+ 'label' => 'File upload', // @translate
+ 'info' => 'Choose a RDF vocabulary file.', // @translate
],
'attributes' => [
- 'id' => 'file',
+ 'id' => 'file-upload',
],
]);
$this->get('vocabulary-file')->add([
'name' => 'url',
'type' => 'url',
'options' => [
- 'label' => 'Vocabulary URL', // @translate
- 'info' => 'Enter a RDF vocabulary URL. You must enter a URL or choose a file above.', // @translate
+ 'label' => 'File URL', // @translate
+ 'info' => 'Enter a URL to a RDF vocabulary file.', // @translate
],
'attributes' => [
- 'id' => 'url',
+ 'id' => 'file-url',
],
]);
$this->get('vocabulary-file')->add([
@@ -120,6 +143,10 @@ public function init()
'ntriples' => 'N-Triples (.nt)', // @translate
'rdfxml' => 'RDF/XML (.rdf)', // @translate
'turtle' => 'Turtle (.ttl)', // @translate
+ [
+ 'value' => 'turtle',
+ 'label' => 'Notation3 (.n3)', // @translate
+ ],
],
],
'attributes' => [
@@ -182,4 +209,9 @@ public function init()
],
]);
}
+
+ public function setTranslator($translator)
+ {
+ $this->translator = $translator;
+ }
}
diff --git a/application/src/Installation/Task/AddDefaultSettingsTask.php b/application/src/Installation/Task/AddDefaultSettingsTask.php
index e691c4b7c1..97c5e09c6d 100644
--- a/application/src/Installation/Task/AddDefaultSettingsTask.php
+++ b/application/src/Installation/Task/AddDefaultSettingsTask.php
@@ -14,6 +14,7 @@ class AddDefaultSettingsTask implements TaskInterface
'media_type_whitelist' => SettingForm::MEDIA_TYPE_WHITELIST,
'extension_whitelist' => SettingForm::EXTENSION_WHITELIST,
'version_notifications' => '1',
+ 'use_htmlpurifier' => '1',
];
public function perform(Installer $installer)
diff --git a/application/src/Job/IndexFulltextSearch.php b/application/src/Job/IndexFulltextSearch.php
index a30dff6d65..8b1dd235e6 100644
--- a/application/src/Job/IndexFulltextSearch.php
+++ b/application/src/Job/IndexFulltextSearch.php
@@ -2,6 +2,7 @@
namespace Omeka\Job;
use Omeka\Api\Adapter\FulltextSearchableInterface;
+use Omeka\Api\Adapter\ResourceAdapter;
use Omeka\Api\Adapter\ValueAnnotationAdapter;
class IndexFulltextSearch extends AbstractJob
@@ -14,12 +15,23 @@ public function perform()
$services = $this->getServiceLocator();
$api = $services->get('Omeka\ApiManager');
$em = $services->get('Omeka\EntityManager');
+ $conn = $services->get('Omeka\Connection');
$fulltext = $services->get('Omeka\FulltextSearch');
$adapters = $services->get('Omeka\ApiAdapterManager');
+
+ // First delete all rows from the fulltext table to clear out the
+ // resources that don't belong.
+ $conn->executeStatement('DELETE FROM `fulltext_search`');
+
+ // Then iterate through all resource types and index the ones that are
+ // fulltext searchable. Note that we don't index "resource" and "value
+ // annotation" resources.
foreach ($adapters->getRegisteredNames() as $adapterName) {
$adapter = $adapters->get($adapterName);
if ($adapter instanceof FulltextSearchableInterface
- && !($adapter instanceof ValueAnnotationAdapter)) {
+ && !($adapter instanceof ResourceAdapter)
+ && !($adapter instanceof ValueAnnotationAdapter)
+ ) {
$page = 1;
do {
if ($this->shouldStop()) {
diff --git a/application/src/Media/Ingester/Upload.php b/application/src/Media/Ingester/Upload.php
index 2f8a43da5e..1f609901e8 100644
--- a/application/src/Media/Ingester/Upload.php
+++ b/application/src/Media/Ingester/Upload.php
@@ -5,7 +5,6 @@
use Omeka\Entity\Media;
use Omeka\File\Uploader;
use Omeka\Stdlib\ErrorStore;
-use Laminas\Form\Element\File;
use Laminas\View\Renderer\PhpRenderer;
class Upload implements IngesterInterface
@@ -64,16 +63,24 @@ public function ingest(Media $media, Request $request, ErrorStore $errorStore)
public function form(PhpRenderer $view, array $options = [])
{
- $fileInput = new File('file[__index__]');
- $fileInput->setOptions([
- 'label' => 'Upload file', // @translate
- 'info' => $view->uploadLimit(),
- ]);
- $fileInput->setAttributes([
- 'id' => 'media-file-input-__index__',
- 'required' => true,
- ]);
- $field = $view->formRow($fileInput);
- return $field . '';
+ $infoTemplate = '
+
+
+
+ ';
+ return '
+
+
+
+
+
+ ';
}
}
diff --git a/application/src/Media/Renderer/FulltextSearchableInterface.php b/application/src/Media/Renderer/FulltextSearchableInterface.php
new file mode 100644
index 0000000000..5b0d5a10cb
--- /dev/null
+++ b/application/src/Media/Renderer/FulltextSearchableInterface.php
@@ -0,0 +1,15 @@
+mediaData();
return $data['html'];
}
+
+ public function getFulltextText(MediaRepresentation $media)
+ {
+ $data = $media->mediaData();
+ return strip_tags($data['html']);
+ }
}
diff --git a/application/src/Mvc/Controller/Plugin/FallbackSettings.php b/application/src/Mvc/Controller/Plugin/FallbackSettings.php
new file mode 100644
index 0000000000..76f978c3cf
--- /dev/null
+++ b/application/src/Mvc/Controller/Plugin/FallbackSettings.php
@@ -0,0 +1,20 @@
+fallbackSettings = $fallbackSettings;
+ }
+
+ public function __invoke()
+ {
+ return $this->fallbackSettings;
+ }
+}
diff --git a/application/src/Mvc/Controller/Plugin/Paginator.php b/application/src/Mvc/Controller/Plugin/Paginator.php
index 3f5496d5f0..ce4ebd204e 100644
--- a/application/src/Mvc/Controller/Plugin/Paginator.php
+++ b/application/src/Mvc/Controller/Plugin/Paginator.php
@@ -36,7 +36,6 @@ public function __invoke($totalCount, $currentPage = null, $perPage = null, $par
{
// Fetch variables from the query if none provided.
$query = $this->getController()->getRequest()->getQuery();
- $query->set('sort_by', (!isset($query['sort_by_default']) && isset($query['sort_by'])) ? $query['sort_by'] : '');
$currentPage = $currentPage ?: $query->get('page', $currentPage);
$perPage = $perPage ?: $query->get('per_page', $perPage);
diff --git a/application/src/Mvc/Controller/Plugin/SetBrowseDefaults.php b/application/src/Mvc/Controller/Plugin/SetBrowseDefaults.php
index 724f2084a7..0d5b7b1540 100644
--- a/application/src/Mvc/Controller/Plugin/SetBrowseDefaults.php
+++ b/application/src/Mvc/Controller/Plugin/SetBrowseDefaults.php
@@ -19,6 +19,7 @@ class SetBrowseDefaults extends AbstractPlugin
public function __invoke($sortBy, $sortOrder = 'desc', $page = 1)
{
$query = $this->getController()->getRequest()->getQuery();
+ // Set the sort_by_default flag if the request doesn't pass a sort_by.
$query->set('sort_by_default', (null === $query->get('sort_by') || '' === $query->get('sort_by')) ? '' : null);
$query->set('sort_by', $query->get('sort_by', $sortBy));
$query->set('sort_order', $query->get('sort_order', $sortOrder));
diff --git a/application/src/Mvc/MvcListeners.php b/application/src/Mvc/MvcListeners.php
index 8c773ca316..785cb56e15 100644
--- a/application/src/Mvc/MvcListeners.php
+++ b/application/src/Mvc/MvcListeners.php
@@ -260,7 +260,7 @@ public function redirectToLogin(MvcEvent $event)
public function authenticateApiKey(MvcEvent $event)
{
$routeMatch = $event->getRouteMatch();
- if (!$routeMatch->getParam('__API__')) {
+ if (!$routeMatch->getParam('__KEYAUTH__')) {
// This is not an API request.
return;
}
diff --git a/application/src/Mvc/Status.php b/application/src/Mvc/Status.php
index 91548bd5fe..75d0c18801 100644
--- a/application/src/Mvc/Status.php
+++ b/application/src/Mvc/Status.php
@@ -22,6 +22,11 @@ class Status
*/
protected $isApiRequest;
+ /**
+ * @var bool
+ */
+ protected $isKeyauthRequest;
+
/**
* @var bool
*/
@@ -105,6 +110,20 @@ public function isApiRequest()
return $this->isApiRequest;
}
+ /**
+ * Check whether the current HTTP request requires key authentication (api).
+ *
+ * @return bool
+ */
+ public function isKeyauthRequest()
+ {
+ if (isset($this->isKeyauthRequest)) {
+ return $this->isKeyauthRequest;
+ }
+ $this->isKeyauthRequest = (bool) $this->getRouteParam('__KEYAUTH__');
+ return $this->isKeyauthRequest;
+ }
+
/**
* Check whether the current HTTP request is an admin request.
*
diff --git a/application/src/Service/AuthenticationServiceFactory.php b/application/src/Service/AuthenticationServiceFactory.php
index 2088b3dbac..1c4b3b2aa6 100644
--- a/application/src/Service/AuthenticationServiceFactory.php
+++ b/application/src/Service/AuthenticationServiceFactory.php
@@ -36,8 +36,8 @@ public function __invoke(ContainerInterface $serviceLocator, $requestedName, arr
});
} else {
$userRepository = $entityManager->getRepository('Omeka\Entity\User');
- if ($status->isApiRequest()) {
- // Authenticate using key for API requests.
+ if ($status->isKeyauthRequest()) {
+ // Authenticate using key for requests that require key authentication.
$keyRepository = $entityManager->getRepository('Omeka\Entity\ApiKey');
$storage = new DoctrineWrapper(new NonPersistent, $userRepository);
$adapter = new KeyAdapter($keyRepository, $entityManager);
diff --git a/application/src/Service/Controller/Site/PageControllerFactory.php b/application/src/Service/Controller/Site/PageControllerFactory.php
new file mode 100644
index 0000000000..e850b67660
--- /dev/null
+++ b/application/src/Service/Controller/Site/PageControllerFactory.php
@@ -0,0 +1,15 @@
+get('Omeka\Site\ThemeManager')->getCurrentTheme();
+ return new PageController($currentTheme);
+ }
+}
diff --git a/application/src/Service/ControllerPlugin/FallbackSettingsFactory.php b/application/src/Service/ControllerPlugin/FallbackSettingsFactory.php
new file mode 100644
index 0000000000..0fc2dd9ccd
--- /dev/null
+++ b/application/src/Service/ControllerPlugin/FallbackSettingsFactory.php
@@ -0,0 +1,14 @@
+get('Omeka\Settings\Fallback'));
+ }
+}
diff --git a/application/src/Service/Delegator/FormElementDelegatorFactory.php b/application/src/Service/Delegator/FormElementDelegatorFactory.php
index 1d6301443b..d1848bb5c5 100644
--- a/application/src/Service/Delegator/FormElementDelegatorFactory.php
+++ b/application/src/Service/Delegator/FormElementDelegatorFactory.php
@@ -22,6 +22,7 @@ public function __invoke(ContainerInterface $container, $name,
$formElement->addClass('Omeka\Form\Element\Query', 'formQuery');
$formElement->addClass('Omeka\Form\Element\Columns', 'formColumns');
$formElement->addClass('Omeka\Form\Element\BrowseDefaults', 'formBrowseDefaults');
+ $formElement->addClass('Omeka\Form\Element\Background', 'formBackground');
return $formElement;
}
}
diff --git a/application/src/Service/Delegator/FormSelectDelegatorFactory.php b/application/src/Service/Delegator/FormSelectDelegatorFactory.php
index fffed49a50..2c73fbc8b8 100644
--- a/application/src/Service/Delegator/FormSelectDelegatorFactory.php
+++ b/application/src/Service/Delegator/FormSelectDelegatorFactory.php
@@ -10,6 +10,7 @@ public function __invoke(ContainerInterface $container, $name,
callable $callback, array $options = null
) {
$formSelect = $callback();
+ $formSelect->addTranslatableAttribute('aria-label');
// The data-placeholder attribute is used by Chosen to display default
// field text. This will make sure that attribute is translated.
$formSelect->addTranslatableAttribute('data-placeholder');
diff --git a/application/src/Service/EntityManagerFactory.php b/application/src/Service/EntityManagerFactory.php
index e25e67b30d..0ad7164b21 100644
--- a/application/src/Service/EntityManagerFactory.php
+++ b/application/src/Service/EntityManagerFactory.php
@@ -81,7 +81,14 @@ public function __invoke(ContainerInterface $serviceLocator, $requestedName, arr
$emConfig->addFilter($name, $className);
}
- // Add user defined functions.
+ // Add custom data types.
+ foreach ($config['entity_manager']['data_types'] as $name => $className) {
+ if (!Type::hasType($name)) {
+ Type::addType($name, $className);
+ }
+ }
+
+ // Add custom functions.
$emConfig->setCustomNumericFunctions($config['entity_manager']['functions']['numeric']);
$emConfig->setCustomStringFunctions($config['entity_manager']['functions']['string']);
$emConfig->setCustomDatetimeFunctions($config['entity_manager']['functions']['datetime']);
@@ -102,6 +109,7 @@ public function __invoke(ContainerInterface $serviceLocator, $requestedName, arr
new ResourceDiscriminatorMap($config['entity_manager']['resource_discriminator_map'])
);
$em->getEventManager()->addEventSubscriber(new Entity($serviceLocator->get('EventManager')));
+
// Instantiate the visibility filters and inject the service locator.
$em->getFilters()->enable('resource_visibility');
$em->getFilters()->getFilter('resource_visibility')->setServiceLocator($serviceLocator);
@@ -110,11 +118,6 @@ public function __invoke(ContainerInterface $serviceLocator, $requestedName, arr
$em->getFilters()->enable('site_page_visibility');
$em->getFilters()->getFilter('site_page_visibility')->setServiceLocator($serviceLocator);
- // Register a custom mapping type for an IP address.
- if (!Type::hasType('ip_address')) {
- Type::addType('ip_address', 'Omeka\Db\Type\IpAddress');
- }
-
return $em;
}
}
diff --git a/application/src/Service/Form/BlockLayoutDataFormFactory.php b/application/src/Service/Form/BlockLayoutDataFormFactory.php
new file mode 100644
index 0000000000..eeefb7861f
--- /dev/null
+++ b/application/src/Service/Form/BlockLayoutDataFormFactory.php
@@ -0,0 +1,17 @@
+setCurrentTheme($services->get('Omeka\Site\ThemeManager')->getCurrentTheme());
+ $form->setViewHelpers($services->get('ViewHelperManager'));
+ return $form;
+ }
+}
diff --git a/application/src/Service/Form/PageLayoutDataFormFactory.php b/application/src/Service/Form/PageLayoutDataFormFactory.php
new file mode 100644
index 0000000000..687e3940cf
--- /dev/null
+++ b/application/src/Service/Form/PageLayoutDataFormFactory.php
@@ -0,0 +1,16 @@
+setCurrentTheme($services->get('Omeka\Site\ThemeManager')->getCurrentTheme());
+ return $form;
+ }
+}
diff --git a/application/src/Service/Form/SitePageFormFactory.php b/application/src/Service/Form/SitePageFormFactory.php
new file mode 100644
index 0000000000..032000a36a
--- /dev/null
+++ b/application/src/Service/Form/SitePageFormFactory.php
@@ -0,0 +1,16 @@
+setCurrentTheme($services->get('Omeka\Site\ThemeManager')->getCurrentTheme());
+ return $form;
+ }
+}
diff --git a/application/src/Service/Form/UserBatchUpdateFormFactory.php b/application/src/Service/Form/UserBatchUpdateFormFactory.php
index 0be06430d1..e289380783 100644
--- a/application/src/Service/Form/UserBatchUpdateFormFactory.php
+++ b/application/src/Service/Form/UserBatchUpdateFormFactory.php
@@ -9,7 +9,7 @@ class UserBatchUpdateFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $services, $requestedName, array $options = null)
{
- $form = new UserBatchUpdateForm(null, $options);
+ $form = new UserBatchUpdateForm(null, $options ?? []);
$form->setEventManager($services->get('EventManager'));
return $form;
}
diff --git a/application/src/Service/Form/VocabularyFormFactory.php b/application/src/Service/Form/VocabularyFormFactory.php
new file mode 100644
index 0000000000..d09dfcf7b1
--- /dev/null
+++ b/application/src/Service/Form/VocabularyFormFactory.php
@@ -0,0 +1,17 @@
+setTranslator($services->get('MvcTranslator'));
+ $form->setOption('vocabulary', $options['vocabulary'] ?? null);
+ return $form;
+ }
+}
diff --git a/application/src/Service/FulltextSearchFactory.php b/application/src/Service/FulltextSearchFactory.php
index 2c8a705ebb..34cfd27755 100644
--- a/application/src/Service/FulltextSearchFactory.php
+++ b/application/src/Service/FulltextSearchFactory.php
@@ -9,6 +9,6 @@ class FulltextSearchFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $services, $requestedName, array $options = null)
{
- return new FulltextSearch($services->get('Omeka\EntityManager'));
+ return new FulltextSearch($services->get('Omeka\Connection'));
}
}
diff --git a/application/src/Service/Settings/FallbackSettingsFactory.php b/application/src/Service/Settings/FallbackSettingsFactory.php
new file mode 100644
index 0000000000..2d8763dda4
--- /dev/null
+++ b/application/src/Service/Settings/FallbackSettingsFactory.php
@@ -0,0 +1,18 @@
+get('Omeka\Settings'),
+ $serviceLocator->get('Omeka\Settings\Site'),
+ $serviceLocator->get('Omeka\Settings\User')
+ );
+ }
+}
diff --git a/application/src/Service/ViewApiJsonRendererFactory.php b/application/src/Service/ViewApiJsonRendererFactory.php
new file mode 100644
index 0000000000..2e0e15814d
--- /dev/null
+++ b/application/src/Service/ViewApiJsonRendererFactory.php
@@ -0,0 +1,17 @@
+get('EventManager');
+ $jsonRenderer = new ApiJsonRenderer($eventManager);
+ return $jsonRenderer;
+ }
+}
diff --git a/application/src/Service/ViewApiJsonStrategyFactory.php b/application/src/Service/ViewApiJsonStrategyFactory.php
index feae4a6bb1..9d6b84c1b8 100644
--- a/application/src/Service/ViewApiJsonStrategyFactory.php
+++ b/application/src/Service/ViewApiJsonStrategyFactory.php
@@ -22,7 +22,8 @@ class ViewApiJsonStrategyFactory implements FactoryInterface
public function __invoke(ContainerInterface $serviceLocator, $requestedName, array $options = null)
{
$jsonRenderer = $serviceLocator->get('Omeka\ViewApiJsonRenderer');
- $jsonStrategy = new ApiJsonStrategy($jsonRenderer);
+ $eventManager = $serviceLocator->get('EventManager');
+ $jsonStrategy = new ApiJsonStrategy($jsonRenderer, $eventManager);
return $jsonStrategy;
}
}
diff --git a/application/src/Service/ViewHelper/BlockLayoutFactory.php b/application/src/Service/ViewHelper/BlockLayoutFactory.php
index fbbfae1abd..caa7ca1465 100644
--- a/application/src/Service/ViewHelper/BlockLayoutFactory.php
+++ b/application/src/Service/ViewHelper/BlockLayoutFactory.php
@@ -18,6 +18,10 @@ class BlockLayoutFactory implements FactoryInterface
*/
public function __invoke(ContainerInterface $services, $requestedName, array $options = null)
{
- return new BlockLayout($services->get('Omeka\BlockLayoutManager'));
+ return new BlockLayout(
+ $services->get('Omeka\BlockLayoutManager'),
+ $services->get('EventManager'),
+ $services->get('Omeka\Site\ThemeManager')->getCurrentTheme()
+ );
}
}
diff --git a/application/src/Service/ViewHelper/FallbackSettingFactory.php b/application/src/Service/ViewHelper/FallbackSettingFactory.php
new file mode 100644
index 0000000000..bdbf321b37
--- /dev/null
+++ b/application/src/Service/ViewHelper/FallbackSettingFactory.php
@@ -0,0 +1,15 @@
+get('Omeka\Settings\Fallback'));
+ }
+}
diff --git a/application/src/Service/ViewHelper/PageLayoutFactory.php b/application/src/Service/ViewHelper/PageLayoutFactory.php
new file mode 100644
index 0000000000..8855aa5f88
--- /dev/null
+++ b/application/src/Service/ViewHelper/PageLayoutFactory.php
@@ -0,0 +1,15 @@
+get('EventManager'));
+ }
+}
diff --git a/application/src/Settings/FallbackSettings.php b/application/src/Settings/FallbackSettings.php
new file mode 100644
index 0000000000..a9da298aad
--- /dev/null
+++ b/application/src/Settings/FallbackSettings.php
@@ -0,0 +1,56 @@
+settings = $settings;
+ $this->siteSettings = $siteSettings;
+ $this->userSettings = $userSettings;
+ }
+
+ /**
+ * Get a setting prioritized by source.
+ *
+ * Can select from the following sources: global, site, user.
+ *
+ * @param string $id The setting ID
+ * @param array $sources An array of setting sources in fallback order
+ * @param mixed $default The default value
+ * @return mixed
+ */
+ public function get($id, array $sources, $default = null)
+ {
+ $setting = null;
+ foreach (array_unique($sources) as $source) {
+ switch ($source) {
+ case 'global':
+ $setting = $this->settings->get($id);
+ break;
+ case 'site':
+ try {
+ $setting = $this->siteSettings->get($id);
+ } catch (\Exception $e) {
+ // Not in a site context
+ }
+ break;
+ case 'user':
+ try {
+ $setting = $this->userSettings->get($id);
+ } catch (\Exception $e) {
+ // No authenticated user
+ }
+ break;
+ }
+ if (!(null === $setting || '' === $setting)) {
+ return $setting;
+ }
+ }
+ return $default;
+ }
+}
diff --git a/application/src/Site/BlockLayout/Asset.php b/application/src/Site/BlockLayout/Asset.php
index 9b479b8ca6..95fde12417 100644
--- a/application/src/Site/BlockLayout/Asset.php
+++ b/application/src/Site/BlockLayout/Asset.php
@@ -7,10 +7,9 @@
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Omeka\Entity\SitePageBlock;
use Omeka\Stdlib\ErrorStore;
-use Laminas\Form\Element\Select;
use Laminas\View\Renderer\PhpRenderer;
-class Asset extends AbstractBlockLayout
+class Asset extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -28,31 +27,6 @@ public function onHydrate(SitePageBlock $block, ErrorStore $errorStore)
$block->setData($data);
}
- public function alignmentClassSelect(PhpRenderer $view, SitePageBlockRepresentation $block = null
- ) {
- $alignmentLabels = [
- 'default', // @translate
- 'float left', // @translate
- 'float right', // @translate
- 'center', // @translate
- ];
- $alignmentValues = [
- 'default', // @translate
- 'left', // @translate
- 'right', // @translate
- 'center', // @translate
- ];
- $alignment = $block ? $block->dataValue('alignment', 'default') : 'default';
- $select = new Select('o:block[__blockIndex__][o:data][alignment]');
- $select->setValueOptions(array_combine($alignmentValues, $alignmentLabels))->setValue($alignment);
- $selectLabel = 'Alignment'; // @translate
- $select->setAttributes(['title' => $selectLabel, 'aria-label' => $selectLabel]);
- $html = '
+ ' . $view->formSelect($select) . '';
- return $html;
- }
-
public function prepareAssetAttachments(PhpRenderer $view, $blockData, SiteRepresentation $site)
{
$attachments = [];
@@ -93,27 +67,22 @@ public function form(PhpRenderer $view, SiteRepresentation $site, SitePageRepres
$apiUrl = $site->apiUrl();
$blockData = ($block) ? $block->data() : '';
$attachments = $this->prepareAssetAttachments($view, $blockData, $site);
- $alignmentClassSelect = $this->alignmentClassSelect($view, $block);
return $view->partial('common/asset-block-form', [
'block' => $blockData,
'siteId' => $siteId,
'apiUrl' => $apiUrl,
'attachments' => $attachments,
- 'alignmentClassSelect' => $alignmentClassSelect,
]);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/asset')
{
$blockData = ($block) ? $block->data() : '';
$site = $view->site;
$attachments = $this->prepareAssetAttachments($view, $blockData, $site);
- $customClass = $block->dataValue('className');
- $alignment = $block->dataValue('alignment');
- return $view->partial('common/block-layout/asset', [
- 'attachments' => $attachments,
- 'className' => $customClass,
- 'alignment' => $alignment,
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
+ 'attachments' => $attachments,
]);
}
}
diff --git a/application/src/Site/BlockLayout/BrowsePreview.php b/application/src/Site/BlockLayout/BrowsePreview.php
index fad3ff0ea7..02099c117b 100644
--- a/application/src/Site/BlockLayout/BrowsePreview.php
+++ b/application/src/Site/BlockLayout/BrowsePreview.php
@@ -9,7 +9,7 @@
use Laminas\Form\Form;
use Laminas\View\Renderer\PhpRenderer;
-class BrowsePreview extends AbstractBlockLayout
+class BrowsePreview extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -123,7 +123,7 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $view->formCollection($form);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/browse-preview')
{
$resourceType = $block->dataValue('resource_type', 'items');
@@ -162,7 +162,8 @@ public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
'media' => 'media',
];
- return $view->partial('common/block-layout/browse-preview', [
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
'resourceType' => $resourceTypes[$resourceType],
'resources' => $resources,
'heading' => $block->dataValue('heading'),
diff --git a/application/src/Site/BlockLayout/Html.php b/application/src/Site/BlockLayout/Html.php
index e51b8efec8..158e7b4359 100644
--- a/application/src/Site/BlockLayout/Html.php
+++ b/application/src/Site/BlockLayout/Html.php
@@ -11,7 +11,7 @@
use Laminas\Form\Form;
use Laminas\View\Renderer\PhpRenderer;
-class Html extends AbstractBlockLayout
+class Html extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
/**
* @var HtmlPurifier
@@ -42,35 +42,17 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
$form = new Form();
$html = new Element\Textarea("o:block[__blockIndex__][o:data][html]");
$html->setAttribute('class', 'block-html full wysiwyg');
- $divClass = new Element\Text("o:block[__blockIndex__][o:data][divclass]");
- $divClass->setOptions([
- 'label' => 'Class', // @translate
- 'info' => 'Optional CSS class for styling HTML.', // @translate
- ]);
if ($block) {
$html->setValue($block->dataValue('html'));
- $divClass->setValue($block->dataValue('divclass'));
}
$form->add($html);
- $form->add($divClass);
return $view->formCollection($form);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/html')
{
- $htmlBlock = $block->dataValue('html', '');
- $divClass = $view->escapeHtml($block->dataValue('divclass'));
- if (!empty($divClass)) {
- //wrap HTML in div with specified class, if present
- $htmlFinal = ' ';
- $html .= '';
- $htmlFinal .= $htmlBlock;
- $htmlFinal .= '';
- } else {
- $htmlFinal = $htmlBlock;
- }
-
- return $htmlFinal;
+ return $view->partial($templateViewScript, ['block' => $block]);
}
public function getFulltextText(PhpRenderer $view, SitePageBlockRepresentation $block)
diff --git a/application/src/Site/BlockLayout/ItemShowcase.php b/application/src/Site/BlockLayout/ItemShowcase.php
index 7fd8a47d35..9a1fd57aa8 100644
--- a/application/src/Site/BlockLayout/ItemShowcase.php
+++ b/application/src/Site/BlockLayout/ItemShowcase.php
@@ -6,7 +6,7 @@
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Laminas\View\Renderer\PhpRenderer;
-class ItemShowcase extends AbstractBlockLayout
+class ItemShowcase extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -28,7 +28,7 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $html;
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/item-showcase')
{
$attachments = $block->attachments();
if (!$attachments) {
@@ -37,7 +37,7 @@ public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
$thumbnailType = $block->dataValue('thumbnail_type', 'square');
$showTitleOption = $block->dataValue('show_title_option', 'item_title');
- return $view->partial('common/block-layout/item-showcase', [
+ return $view->partial($templateViewScript, [
'block' => $block,
'attachments' => $attachments,
'thumbnailType' => $thumbnailType,
diff --git a/application/src/Site/BlockLayout/ItemWithMetadata.php b/application/src/Site/BlockLayout/ItemWithMetadata.php
index 8f398fd6f0..dbe23e55e2 100644
--- a/application/src/Site/BlockLayout/ItemWithMetadata.php
+++ b/application/src/Site/BlockLayout/ItemWithMetadata.php
@@ -6,7 +6,7 @@
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Laminas\View\Renderer\PhpRenderer;
-class ItemWithMetadata extends AbstractBlockLayout
+class ItemWithMetadata extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -19,14 +19,15 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $view->blockAttachmentsForm($block, true);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/item-with-metadata')
{
$attachments = $block->attachments();
if (!$attachments) {
return 'No item selected'; // @translate
}
- return $view->partial('common/block-layout/item-with-metadata', [
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
'attachments' => $attachments,
]);
}
diff --git a/application/src/Site/BlockLayout/LineBreak.php b/application/src/Site/BlockLayout/LineBreak.php
index 9c03dbc0be..534417a1d7 100644
--- a/application/src/Site/BlockLayout/LineBreak.php
+++ b/application/src/Site/BlockLayout/LineBreak.php
@@ -7,7 +7,7 @@
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Laminas\View\Renderer\PhpRenderer;
-class LineBreak extends AbstractBlockLayout
+class LineBreak extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -20,11 +20,9 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $this->breakTypeSelect($view, $site, $block);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/line-break')
{
- $breakType = $block->dataValue('break_type');
-
- return "";
+ return $view->partial($templateViewScript, ['block' => $block]);
}
public function breakTypeSelect(PhpRenderer $view, SiteRepresentation $site,
diff --git a/application/src/Site/BlockLayout/ListOfPages.php b/application/src/Site/BlockLayout/ListOfPages.php
index 53b82c72fb..125f3aa38d 100644
--- a/application/src/Site/BlockLayout/ListOfPages.php
+++ b/application/src/Site/BlockLayout/ListOfPages.php
@@ -9,7 +9,7 @@
use Laminas\Form\Element\Hidden;
use Laminas\View\Renderer\PhpRenderer;
-class ListOfPages extends AbstractBlockLayout
+class ListOfPages extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
/**
* @var LinkManager
@@ -64,7 +64,7 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $html;
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/list-of-pages')
{
$nodes = json_decode($block->dataValue('pagelist'), true);
if (!is_array($nodes)) {
@@ -73,7 +73,8 @@ public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
$pageTree = $this->getPageNodeURLs($nodes, $block);
- return $view->partial('common/block-layout/list-of-pages', [
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
'pageList' => $pageTree,
]);
}
diff --git a/application/src/Site/BlockLayout/ListOfSites.php b/application/src/Site/BlockLayout/ListOfSites.php
index a9bb6f5025..098d80bb19 100644
--- a/application/src/Site/BlockLayout/ListOfSites.php
+++ b/application/src/Site/BlockLayout/ListOfSites.php
@@ -8,7 +8,7 @@
use Laminas\Form\Form;
use Laminas\View\Renderer\PhpRenderer;
-class ListOfSites extends AbstractBlockLayout
+class ListOfSites extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
protected $defaults = [
'sort' => 'alpha',
@@ -112,7 +112,7 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $view->formCollection($form, false);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/list-of-sites')
{
$sort = $block->dataValue('sort', $this->defaults['sort']);
$limit = $block->dataValue('limit', $this->defaults['limit']);
@@ -157,7 +157,8 @@ public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
$sites = $response->getContent();
- return $view->partial('common/block-layout/list-of-sites', [
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
'sites' => $sites,
'pagination' => $pagination,
'summaries' => $summaries,
diff --git a/application/src/Site/BlockLayout/Media.php b/application/src/Site/BlockLayout/Media.php
index 83008d506e..d831ec1596 100644
--- a/application/src/Site/BlockLayout/Media.php
+++ b/application/src/Site/BlockLayout/Media.php
@@ -1,13 +1,12 @@
' . $view->translate('Options') . '
';
$html .= '';
$html .= $view->blockThumbnailTypeSelect($block);
- $html .= $this->alignmentClassSelect($view, $block);
$html .= $view->blockShowTitleSelect($block);
$html .= '';
return $html;
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/file')
{
$attachments = $block->attachments();
if (!$attachments) {
return '';
}
- $alignmentClass = $block->dataValue('alignment', 'left');
$thumbnailType = $block->dataValue('thumbnail_type', 'square');
$linkType = $view->siteSetting('attachment_link_type', 'item');
$showTitleOption = $block->dataValue('show_title_option', 'item_title');
- return $view->partial('common/block-layout/file', [
+ return $view->partial($templateViewScript, [
'block' => $block,
'attachments' => $attachments,
- 'alignmentClass' => $alignmentClass,
'thumbnailType' => $thumbnailType,
'link' => $linkType,
'showTitleOption' => $showTitleOption,
]);
}
-
- public function alignmentClassSelect(PhpRenderer $view,
- SitePageBlockRepresentation $block = null
- ) {
- $alignmentLabels = ['float left', 'float right', 'center'];
- $alignmentValues = ['left', 'right', 'center'];
- $alignment = $block ? $block->dataValue('alignment', 'left') : 'left';
- $select = new Select('o:block[__blockIndex__][o:data][alignment]');
- $select->setValueOptions(array_combine($alignmentValues, $alignmentLabels))->setValue($alignment);
- $selectLabel = 'Alignment'; // @translate
- $select->setAttributes(['title' => $selectLabel, 'aria-label' => $selectLabel]);
- $html = '' . $view->formSelect($select) . '';
- return $html;
- }
}
diff --git a/application/src/Site/BlockLayout/Oembed.php b/application/src/Site/BlockLayout/Oembed.php
index 47723b6b2e..474cd73274 100644
--- a/application/src/Site/BlockLayout/Oembed.php
+++ b/application/src/Site/BlockLayout/Oembed.php
@@ -9,7 +9,7 @@
use Laminas\Form;
use Laminas\View\Renderer\PhpRenderer;
-class Oembed extends AbstractBlockLayout
+class Oembed extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
protected $oembed;
@@ -118,9 +118,12 @@ public function form(PhpRenderer $view, SiteRepresentation $site, SitePageRepres
);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/oembed')
{
- $data = $block->data() + $this->defaultData;
- return sprintf(' ';
- $html .= '%s', $this->oembed->renderOembed($view, $data['oembed']));
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
+ 'oembed' => $this->oembed,
+ 'data' => $block->data() + $this->defaultData,
+ ]);
}
}
diff --git a/application/src/Site/BlockLayout/PageDateTime.php b/application/src/Site/BlockLayout/PageDateTime.php
index 6cdb274840..b7c912a005 100644
--- a/application/src/Site/BlockLayout/PageDateTime.php
+++ b/application/src/Site/BlockLayout/PageDateTime.php
@@ -7,7 +7,7 @@
use Laminas\Form;
use Laminas\View\Renderer\PhpRenderer;
-class PageDateTime extends AbstractBlockLayout
+class PageDateTime extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
protected $defaultData = [
'display' => 'created_modified',
@@ -72,9 +72,9 @@ public function form(PhpRenderer $view, SiteRepresentation $site, SitePageRepres
return $view->formCollection($form, false);
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/page-date-time')
{
- return $view->partial('common/block-layout/page-date-time', [
+ return $view->partial($templateViewScript, [
'block' => $block,
]);
}
diff --git a/application/src/Site/BlockLayout/PageTitle.php b/application/src/Site/BlockLayout/PageTitle.php
index 5efc4bf113..90c235072d 100644
--- a/application/src/Site/BlockLayout/PageTitle.php
+++ b/application/src/Site/BlockLayout/PageTitle.php
@@ -6,7 +6,7 @@
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Laminas\View\Renderer\PhpRenderer;
-class PageTitle extends AbstractBlockLayout
+class PageTitle extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -19,9 +19,10 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $view->escapeHtml($page->title());
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/page-title')
{
- return $view->partial('common/block-layout/page-title', [
+ return $view->partial($templateViewScript, [
+ 'block' => $block,
'pageTitle' => $block->page()->title(),
]);
}
diff --git a/application/src/Site/BlockLayout/TableOfContents.php b/application/src/Site/BlockLayout/TableOfContents.php
index c4ff544d80..5d80c44cef 100644
--- a/application/src/Site/BlockLayout/TableOfContents.php
+++ b/application/src/Site/BlockLayout/TableOfContents.php
@@ -8,7 +8,7 @@
use Laminas\Form\Element\Number;
use Laminas\View\Renderer\PhpRenderer;
-class TableOfContents extends AbstractBlockLayout
+class TableOfContents extends AbstractBlockLayout implements TemplateableBlockLayoutInterface
{
public function getLabel()
{
@@ -33,7 +33,7 @@ public function form(PhpRenderer $view, SiteRepresentation $site,
return $html;
}
- public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
+ public function render(PhpRenderer $view, SitePageBlockRepresentation $block, $templateViewScript = 'common/block-layout/table-of-contents')
{
$view->pageViewModel->setVariable('displayNavigation', false);
@@ -55,7 +55,7 @@ public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
$depth = $block->dataValue('depth', 1);
- return $view->partial('common/block-layout/table-of-contents', [
+ return $view->partial($templateViewScript, [
'block' => $block,
'subNav' => $subNav,
'maxDepth' => $depth - 1,
diff --git a/application/src/Site/BlockLayout/TemplateableBlockLayoutInterface.php b/application/src/Site/BlockLayout/TemplateableBlockLayoutInterface.php
new file mode 100644
index 0000000000..f513cb13da
--- /dev/null
+++ b/application/src/Site/BlockLayout/TemplateableBlockLayoutInterface.php
@@ -0,0 +1,10 @@
+ 'uri',
'uri' => $data['url'],
+ 'target' => (isset($data['target_blank']) && $data['target_blank']) ? '_blank' : null,
+
];
}
@@ -48,6 +50,7 @@ public function toJstree(array $data, SiteRepresentation $site)
return [
'label' => $data['label'],
'url' => $data['url'],
+ 'target_blank' => $data['target_blank'] ?? false,
];
}
}
diff --git a/application/src/Site/ResourcePageBlockLayout/Manager.php b/application/src/Site/ResourcePageBlockLayout/Manager.php
index b89afdb215..8461eefbf5 100644
--- a/application/src/Site/ResourcePageBlockLayout/Manager.php
+++ b/application/src/Site/ResourcePageBlockLayout/Manager.php
@@ -33,6 +33,7 @@ class Manager extends AbstractPluginManager
],
'media' => [
'main' => [
+ 'mediaRender',
'values',
],
],
diff --git a/application/src/Stdlib/Environment.php b/application/src/Stdlib/Environment.php
index c45cc2f95f..2c935e575a 100644
--- a/application/src/Stdlib/Environment.php
+++ b/application/src/Stdlib/Environment.php
@@ -14,13 +14,15 @@ class Environment
/**
* The MySQL minimum version
+ * @see https://dev.mysql.com/doc/relnotes/mysql/5.7/en/
*/
- const MYSQL_MINIMUM_VERSION = '5.6.4';
+ const MYSQL_MINIMUM_VERSION = '5.7.9';
/**
* The MariaDB minimum version
+ * @see https://mariadb.com/kb/en/changes-improvements-in-mariadb-10-2/#list-of-all-mariadb-102-releases
*/
- const MARIADB_MINIMUM_VERSION = '10.0.5';
+ const MARIADB_MINIMUM_VERSION = '10.2.6';
/**
* The required PHP extensions
diff --git a/application/src/Stdlib/FulltextSearch.php b/application/src/Stdlib/FulltextSearch.php
index 2b72426f9e..8ec27a56f0 100644
--- a/application/src/Stdlib/FulltextSearch.php
+++ b/application/src/Stdlib/FulltextSearch.php
@@ -4,15 +4,15 @@
use Omeka\Api\Adapter\AdapterInterface;
use Omeka\Api\Adapter\FulltextSearchableInterface;
use Omeka\Api\ResourceInterface;
-use Omeka\Entity\FulltextSearch as FulltextSearchEntity;
+use PDO;
class FulltextSearch
{
- protected $em;
+ protected $conn;
- public function __construct($em)
+ public function __construct($conn)
{
- $this->em = $em;
+ $this->conn = $conn;
}
/**
@@ -26,21 +26,26 @@ public function save(ResourceInterface $resource, AdapterInterface $adapter)
if (!($adapter instanceof FulltextSearchableInterface)) {
return;
}
- $searchId = $resource->getId();
- $searchResource = $adapter->getResourceName();
- $search = $this->em->find(
- 'Omeka\Entity\FulltextSearch',
- ['id' => $searchId, 'resource' => $searchResource]
- );
- if (!$search) {
- $search = new FulltextSearchEntity($searchId, $searchResource);
- $this->em->persist($search);
- }
- $search->setOwner($adapter->getFulltextOwner($resource));
- $search->setIsPublic($adapter->getFulltextIsPublic($resource));
- $search->setTitle($adapter->getFulltextTitle($resource));
- $search->setText($adapter->getFulltextText($resource));
- $this->em->flush($search);
+ $resourceId = $resource->getId();
+ $resourceName = $adapter->getResourceName();
+ $owner = $adapter->getFulltextOwner($resource);
+ $ownerId = $owner ? $owner->getId() : null;
+
+ $sql = 'INSERT INTO `fulltext_search` (
+ `id`, `resource`, `owner_id`, `is_public`, `title`, `text`
+ ) VALUES (
+ :id, :resource, :owner_id, :is_public, :title, :text
+ ) ON DUPLICATE KEY UPDATE
+ `owner_id` = :owner_id, `is_public` = :is_public, `title` = :title, `text` = :text';
+ $stmt = $this->conn->prepare($sql);
+
+ $stmt->bindValue('id', $resourceId, PDO::PARAM_INT);
+ $stmt->bindValue('resource', $resourceName, PDO::PARAM_STR);
+ $stmt->bindValue('owner_id', $ownerId, PDO::PARAM_INT);
+ $stmt->bindValue('is_public', $adapter->getFulltextIsPublic($resource), PDO::PARAM_BOOL);
+ $stmt->bindValue('title', $adapter->getFulltextTitle($resource), PDO::PARAM_STR);
+ $stmt->bindValue('text', $adapter->getFulltextText($resource), PDO::PARAM_STR);
+ $stmt->executeStatement();
}
/**
@@ -54,14 +59,13 @@ public function delete($resourceId, AdapterInterface $adapter)
if (!($adapter instanceof FulltextSearchableInterface)) {
return;
}
- $searchResource = $adapter->getResourceName();
- $search = $this->em->find(
- 'Omeka\Entity\FulltextSearch',
- ['id' => $resourceId, 'resource' => $searchResource]
- );
- if ($search) {
- $this->em->remove($search);
- $this->em->flush($search);
- }
+ $resourceName = $adapter->getResourceName();
+
+ $sql = 'DELETE FROM `fulltext_search` WHERE `id` = :id AND `resource` = :resource';
+ $stmt = $this->conn->prepare($sql);
+
+ $stmt->bindValue('id', $resourceId, PDO::PARAM_INT);
+ $stmt->bindValue('resource', $resourceName, PDO::PARAM_STR);
+ $stmt->executeStatement();
}
}
diff --git a/application/src/Stdlib/RdfImporter.php b/application/src/Stdlib/RdfImporter.php
index 1e40934232..8b53ddfdf7 100644
--- a/application/src/Stdlib/RdfImporter.php
+++ b/application/src/Stdlib/RdfImporter.php
@@ -99,12 +99,12 @@ public function getMembers($strategy, $namespaceUri, array $options = [])
}
$file = $options['file'];
if (!is_readable($file)) {
- throw new ValidationException('File not readable.');
+ throw new ValidationException('Could not read vocabulary file.');
}
try {
$graph->parseFile($file, $options['format'], $namespaceUri);
} catch (\EasyRdf\Exception $e) {
- throw new ValidationException($e->getMessage(), $e->getCode(), $e);
+ throw new ValidationException('Could not parse vocabulary file.');
}
break;
case 'url':
@@ -115,7 +115,7 @@ public function getMembers($strategy, $namespaceUri, array $options = [])
try {
$graph->load($options['url'], $options['format']);
} catch (\EasyRdf\Exception $e) {
- throw new ValidationException($e->getMessage(), $e->getCode(), $e);
+ throw new ValidationException('Could not load vocabulary from URL.');
}
break;
default:
@@ -335,8 +335,7 @@ protected function getMembersOfTypes(RdfGraph $graph, array $types,
foreach ($types as $type) {
foreach ($graph->allOfType($type) as $resource) {
// The resource must be a local member of the vocabulary.
- $output = strncmp($resource->getUri(), $namespaceUri, strlen($namespaceUri));
- if (0 === $output) {
+ if ($resource->getUri() === $namespaceUri . $resource->localName()) {
$members[$resource->localName()] = [
'label' => $this->getLabel($resource, $labelProperty, $lang, $resource->localName()),
'comment' => $this->getComment($resource, $commentProperty, $lang),
diff --git a/application/src/View/Helper/BlockLayout.php b/application/src/View/Helper/BlockLayout.php
index a9ffab4e55..31851737c4 100644
--- a/application/src/View/Helper/BlockLayout.php
+++ b/application/src/View/Helper/BlockLayout.php
@@ -5,6 +5,10 @@
use Omeka\Api\Representation\SitePageRepresentation;
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Omeka\Site\BlockLayout\Manager as BlockLayoutManager;
+use Omeka\Site\BlockLayout\TemplateableBlockLayoutInterface;
+use Omeka\Site\Theme\Theme;
+use Laminas\EventManager\Event;
+use Laminas\EventManager\EventManager;
use Laminas\View\Helper\AbstractHelper;
/**
@@ -22,9 +26,15 @@ class BlockLayout extends AbstractHelper
*/
protected $manager;
- public function __construct(BlockLayoutManager $manager)
+ protected $eventManager;
+
+ protected $currentTheme;
+
+ public function __construct(BlockLayoutManager $manager, EventManager $eventManager, ?Theme $currentTheme)
{
$this->manager = $manager;
+ $this->eventManager = $eventManager;
+ $this->currentTheme = $currentTheme;
}
/**
@@ -86,11 +96,13 @@ public function form($layout, SiteRepresentation $site = null,
) {
$view = $this->getView();
$block = null;
+ $layoutData = [];
if ($layout instanceof SitePageBlockRepresentation) {
$block = $layout;
$layout = $block->layout();
$page = $block->page();
$site = $page->site();
+ $layoutData = $block->layoutData();
}
$partialName = $partialName ?: self::PARTIAL_NAME;
return $view->partial(
@@ -98,6 +110,7 @@ public function form($layout, SiteRepresentation $site = null,
[
'layout' => $layout,
'layoutLabel' => $this->getLayoutLabel($layout),
+ 'layoutData' => $layoutData,
'blockContent' => $this->manager->get($layout)->form($this->getView(), $site, $page, $block),
]
);
@@ -121,6 +134,123 @@ public function prepareRender($layout)
*/
public function render(SitePageBlockRepresentation $block)
{
- return $this->manager->get($block->layout())->render($this->getView(), $block);
+ $view = $this->getView();
+
+ // Allow modules to add classes for styling the layout.
+ $eventArgs = $this->eventManager->prepareArgs(['classes' => []]);
+ $this->eventManager->triggerEvent(new Event('block_layout.classes', $block, $eventArgs));
+ $classes = $eventArgs['classes'];
+
+ // Allow modules to add inline styles for styling the layout.
+ $eventArgs = $this->eventManager->prepareArgs(['inline_styles' => []]);
+ $this->eventManager->triggerEvent(new Event('block_layout.inline_styles', $block, $eventArgs));
+ $inlineStyles = $eventArgs['inline_styles'];
+
+ // Add classes and inline styles, if any.
+ $class = $block->layoutDataValue('class');
+ if (is_string($class) && '' !== trim($class)) {
+ $classes[] = $class;
+ }
+ $alignment = $block->layoutDataValue('alignment');
+ switch ($alignment) {
+ case 'left':
+ $classes[] = 'block-layout-alignment-left';
+ break;
+ case 'right':
+ $classes[] = 'block-layout-alignment-right';
+ break;
+ case 'center':
+ $classes[] = 'block-layout-alignment-center';
+ break;
+ default:
+ // No alignment
+ }
+ $backgroundImageAsset = $block->layoutDataValue('background_image_asset');
+ if ($backgroundImageAsset) {
+ $asset = $view->api()->searchOne('assets', ['id' => $backgroundImageAsset])->getContent();
+ if ($asset) {
+ $inlineStyles[] = sprintf('background-image: url("%s");', $view->escapeCss($asset->assetUrl()));
+ }
+ }
+ $backgroundPositionY = $block->layoutDataValue('background_position_y');
+ if ($backgroundPositionY) {
+ switch ($backgroundPositionY) {
+ case 'top':
+ $classes[] = 'block-layout-background-position-y-top';
+ break;
+ case 'center':
+ $classes[] = 'block-layout-background-position-y-center';
+ break;
+ case 'bottom':
+ $classes[] = 'block-layout-background-position-y-bottom';
+ break;
+ default:
+ // No background position Y
+ }
+ }
+ $backgroundPositionX = $block->layoutDataValue('background_position_x');
+ if ($backgroundPositionX) {
+ switch ($backgroundPositionX) {
+ case 'left':
+ $classes[] = 'block-layout-background-position-x-left';
+ break;
+ case 'center':
+ $classes[] = 'block-layout-background-position-x-center';
+ break;
+ case 'right':
+ $classes[] = 'block-layout-background-position-x-right';
+ break;
+ default:
+ // No background position X
+ }
+ }
+ $backgroundSize = $block->layoutDataValue('background_size');
+ if ($backgroundSize) {
+ switch ($backgroundSize) {
+ case 'cover':
+ $classes[] = 'block-layout-background-size-cover';
+ break;
+ case 'contain':
+ $classes[] = 'block-layout-background-size-contain';
+ break;
+ default:
+ // No background size
+ }
+ }
+ $minHeight = $block->layoutDataValue('min_height');
+ if ($minHeight) {
+ $inlineStyles[] = sprintf('min-height: %spx', (int) $minHeight);
+ }
+
+ $view = $this->getView();
+ $blockLayout = $this->manager->get($block->layout());
+
+ // Set the configured block template, if any.
+ $templateName = $block->layoutDataValue('template_name');
+ $templateViewScript = null;
+ if ($templateName && $blockLayout instanceof TemplateableBlockLayoutInterface) {
+ // Verify that the current theme provides this template.
+ $config = $this->currentTheme->getConfigSpec();
+ if (isset($config['block_templates'][$block->layout()][$templateName])) {
+ $templateViewScript = sprintf('common/block-template/%s', $templateName);
+ }
+ }
+
+ // Wrap block markup in a div only if the layout declares special
+ // styling via classes or inline styles.
+ if ($classes || $inlineStyles) {
+ return sprintf(
+ '%s',
+ $view->escapeHtml(implode(' ', $classes)),
+ $view->escapeHtml(implode(' ', $inlineStyles)),
+ $templateViewScript
+ ? $blockLayout->render($this->getView(), $block, $templateViewScript)
+ : $blockLayout->render($this->getView(), $block)
+ );
+ }
+
+ return $templateViewScript
+ ? $blockLayout->render($this->getView(), $block, $templateViewScript)
+ : $blockLayout->render($this->getView(), $block);
}
}
diff --git a/application/src/View/Helper/BlockThumbnailTypeSelect.php b/application/src/View/Helper/BlockThumbnailTypeSelect.php
index ee39f45e62..3cdfcf4f4d 100644
--- a/application/src/View/Helper/BlockThumbnailTypeSelect.php
+++ b/application/src/View/Helper/BlockThumbnailTypeSelect.php
@@ -39,7 +39,7 @@ public function __invoke(SitePageBlockRepresentation $block = null)
$type = $block->dataValue('thumbnail_type');
}
- $selectLabel = $view->translate('Thumbnail type');
+ $selectLabel = 'Thumbnail type'; // @translate
$select = new Select('o:block[__blockIndex__][o:data][thumbnail_type]');
$select->setValueOptions(array_combine($this->thumbnailTypes, $this->thumbnailTypes))->setValue($type);
$select->setAttributes(['title' => $selectLabel, 'aria-label' => $selectLabel]);
diff --git a/application/src/View/Helper/Browse.php b/application/src/View/Helper/Browse.php
index 2be2e19316..3ae49c2ed1 100644
--- a/application/src/View/Helper/Browse.php
+++ b/application/src/View/Helper/Browse.php
@@ -51,12 +51,14 @@ public function renderSortSelector($resourceTypeOrSortConfig) : string
return '';
}
$query = $view->params()->fromQuery();
- if (isset($query['fulltext_search']) && '' !== trim($query['fulltext_search'])) {
+ $isFulltextSearch = (isset($query['fulltext_search']) && '' !== trim($query['fulltext_search']));
+ if ($isFulltextSearch) {
+ // Add "Relevance" to sort_by if this is a fulltext search.
$sortConfig[''] = 'Relevance'; // @translate
}
$args = [
'sortConfig' => $sortConfig,
- 'sortByQuery' => isset($query['sort_by_default']) ? '' : $view->params()->fromQuery('sort_by'),
+ 'sortByQuery' => (isset($query['sort_by_default']) && $isFulltextSearch) ? '' : $view->params()->fromQuery('sort_by'),
'sortOrderQuery' => $view->params()->fromQuery('sort_order'),
];
$args = $view->trigger('view.sort-selector', $args, true);
diff --git a/application/src/View/Helper/FallbackSetting.php b/application/src/View/Helper/FallbackSetting.php
new file mode 100644
index 0000000000..7900ac2d58
--- /dev/null
+++ b/application/src/View/Helper/FallbackSetting.php
@@ -0,0 +1,20 @@
+fallbackSettings = $fallbackSettings;
+ }
+
+ public function __invoke($id, array $sources, $default = null)
+ {
+ return $this->fallbackSettings->get($id, $sources, $default);
+ }
+}
diff --git a/application/src/View/Helper/LightGalleryOutput.php b/application/src/View/Helper/LightGalleryOutput.php
index 4d4a607948..b711e88373 100644
--- a/application/src/View/Helper/LightGalleryOutput.php
+++ b/application/src/View/Helper/LightGalleryOutput.php
@@ -51,8 +51,8 @@ public function __invoke($files = null)
if (isset($file['tracks'])) {
foreach ($file['tracks'] as $key => $track) {
$label = $track->displayTitle();
- $srclang = ($track->value('Dublin Core, Language')) ? $track->value('dcterms:language') : '';
- $type = ($track->value('Dublin Core, Type')) ? $track->value('dcterms:type') : 'captions';
+ $srclang = (string) $track->value('dcterms:language', ['default' => '']);
+ $type = (string) $track->value('dcterms:type', ['default' => 'captions']);
$videoSrcObject['tracks'][$key]['src'] = $track->originalUrl();
$videoSrcObject['tracks'][$key]['label'] = $label;
$videoSrcObject['tracks'][$key]['srclang'] = $srclang;
diff --git a/application/src/View/Helper/PageLayout.php b/application/src/View/Helper/PageLayout.php
new file mode 100644
index 0000000000..0013787df5
--- /dev/null
+++ b/application/src/View/Helper/PageLayout.php
@@ -0,0 +1,89 @@
+eventManager = $eventManager;
+ }
+
+ public function render(SitePageRepresentation $page)
+ {
+ $view = $this->getView();
+
+ // Allow modules to add classes for styling the layout.
+ $eventArgs = $this->eventManager->prepareArgs(['classes' => []]);
+ $this->eventManager->triggerEvent(new Event('page_layout.classes', $page, $eventArgs));
+ $classes = $eventArgs['classes'];
+
+ // Allow modules to add inline styles for styling the layout.
+ $eventArgs = $this->eventManager->prepareArgs(['inline_styles' => []]);
+ $this->eventManager->triggerEvent(new Event('page_layout.inline_styles', $page, $eventArgs));
+ $inlineStyles = $eventArgs['inline_styles'];
+
+ // Prepare the page layout.
+ switch ($page->layout()) {
+ case 'grid':
+ $view->headLink()->appendStylesheet($view->assetUrl('css/page-grid.css', 'Omeka'));
+ $classes[] = 'page-layout-grid';
+ $inlineStyles[] = sprintf(
+ 'grid-template-columns: repeat(%s, 1fr);',
+ (int) $page->layoutDataValue('grid_columns')
+ );
+ $inlineStyles[] = sprintf(
+ 'column-gap: %spx;',
+ (int) $page->layoutDataValue('grid_column_gap', 10)
+ );
+ $inlineStyles[] = sprintf(
+ 'row-gap: %spx;',
+ (int) $page->layoutDataValue('grid_row_gap', 10)
+ );
+ break;
+ case '':
+ default:
+ $classes[] = 'page-layout-normal';
+ break;
+ }
+ echo sprintf(
+ '',
+ $view->escapeHtml(implode(' ', $classes)),
+ $view->escapeHtml(implode(' ', $inlineStyles))
+ );
+ $layouts = [];
+ foreach ($page->blocks() as $block) {
+ if (!array_key_exists($block->layout(), $layouts)) {
+ // Prepare render only once per block layout type.
+ $layouts[$block->layout()] = null;
+ $view->blockLayout()->prepareRender($block->layout());
+ }
+ // Render each block according to page layout.
+ switch ($page->layout()) {
+ case 'grid':
+ $gridColumns = (int) $page->layoutDataValue('grid_columns');
+ $blockLayoutData = $block->layoutData();
+ $getValidPosition = fn ($columnPosition) => in_array($columnPosition, ['auto',...range(1, $gridColumns)]) ? $columnPosition : 'auto';
+ $getValidSpan = fn ($columnSpan) => in_array($columnSpan, range(1, $gridColumns)) ? $columnSpan : $gridColumns;
+ echo sprintf(
+ '%s',
+ $getValidPosition($blockLayoutData['grid_column_position'] ?? 'auto'),
+ $getValidSpan($blockLayoutData['grid_column_span'] ?? $gridColumns),
+ $view->blockLayout()->render($block)
+ );
+ break;
+ case '':
+ default:
+ echo $view->blockLayout()->render($block);
+ break;
+ }
+ }
+ echo '';
+ }
+}
diff --git a/application/src/View/Helper/Pagination.php b/application/src/View/Helper/Pagination.php
index 1a9f762114..b767c22d47 100644
--- a/application/src/View/Helper/Pagination.php
+++ b/application/src/View/Helper/Pagination.php
@@ -128,6 +128,12 @@ protected function getUrl($page)
{
$query = $this->getView()->params()->fromQuery();
$query['page'] = (int) $page;
+ if (isset($query['sort_by_default'])) {
+ // Do not emit sort_by if the sort_by_default flag is set.
+ unset($query['sort_by']);
+ }
+ // Do not emit the sort_by_default flag
+ unset($query['sort_by_default']);
$options = ['query' => $query];
if (is_string($this->fragment)) {
$options['fragment'] = $this->fragment;
diff --git a/application/src/View/Helper/SearchFilters.php b/application/src/View/Helper/SearchFilters.php
index 3928501d8e..aa928dc946 100644
--- a/application/src/View/Helper/SearchFilters.php
+++ b/application/src/View/Helper/SearchFilters.php
@@ -218,16 +218,19 @@ public function __invoke($partialName = null, array $query = null)
case 'id':
$filterLabel = $translate('ID');
+ // Avoid a deprecated issue, so convert ids as string.
$ids = $value;
- if (is_string($ids) || is_int($ids)) {
- $ids = false === strpos($ids, ',') ? [$ids] : explode(',', $ids);
- } elseif (!is_array($ids)) {
+ if (is_int($ids)) {
+ $ids = [(string) $ids];
+ } elseif (is_string($ids)) {
+ $ids = strpos($ids, ',') === false ? [$ids] : explode(',', $ids);
+ } elseif (is_array($ids)) {
+ $ids = array_map('strval', $ids);
+ } else {
$ids = [];
}
$ids = array_map('trim', $ids);
- $ids = array_filter($ids, function ($id) {
- return !($id === null || $id === '');
- });
+ $ids = array_filter($ids, 'strlen');
$filters[$filterLabel][] = implode(', ', $ids);
break;
}
diff --git a/application/src/View/Helper/SortMedia.php b/application/src/View/Helper/SortMedia.php
index 838e155d7c..3a44d15fc9 100644
--- a/application/src/View/Helper/SortMedia.php
+++ b/application/src/View/Helper/SortMedia.php
@@ -8,7 +8,7 @@ class SortMedia extends AbstractHelper
public function __invoke($files = null)
{
$sortedMedia = [];
- $whitelist = ['image/bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/svg+xml', 'video/flv', 'video/x-flv', 'video/mp4', 'video/m4v',
+ $whitelist = ['image/bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/webp', 'video/flv', 'video/x-flv', 'video/mp4', 'video/m4v',
'video/webm', 'video/wmv', 'video/quicktime', 'application/pdf', ];
$html5videos = [];
$mediaCount = 0;
diff --git a/application/src/View/Renderer/ApiJsonRenderer.php b/application/src/View/Renderer/ApiJsonRenderer.php
index e2e58e3abe..605c6445cd 100644
--- a/application/src/View/Renderer/ApiJsonRenderer.php
+++ b/application/src/View/Renderer/ApiJsonRenderer.php
@@ -2,8 +2,8 @@
namespace Omeka\View\Renderer;
use Omeka\Api\Exception\ValidationException;
-use Omeka\Api\Representation\RepresentationInterface;
use Omeka\Api\Response;
+use Laminas\EventManager\EventManager;
use Laminas\Json\Json;
use Laminas\View\Renderer\JsonRenderer;
@@ -17,16 +17,18 @@ class ApiJsonRenderer extends JsonRenderer
*/
protected $hasJsonpCallback = false;
- /**
- * @var array The JSON-LD context
- */
- protected $context;
-
/**
* @var string The output format
*/
protected $format;
+ protected $eventManager;
+
+ public function __construct(EventManager $eventManager)
+ {
+ $this->eventManager = $eventManager;
+ }
+
/**
* Return whether the response is JSONP
*
@@ -41,6 +43,11 @@ public function hasJsonpCallback()
return $this->hasJsonpCallback;
}
+ public function setHasJsonpCallback(bool $hasJsonpCallback)
+ {
+ $this->hasJsonpCallback = $hasJsonpCallback;
+ }
+
public function render($model, $values = null)
{
$response = $model->getApiResponse();
@@ -61,82 +68,17 @@ public function render($model, $values = null)
return null;
}
- // Render a format that is not JSON-LD, if requested.
- if ('jsonld' !== $this->format) {
- // Render a single representation (get).
- if ($payload instanceof RepresentationInterface) {
- $jsonLd = $this->getJsonLdWithContext($payload);
- return $this->serializeJsonLdToFormat($jsonLd, $this->format);
- }
- // Render multiple representations (getList);
- if (is_array($payload) && isset($payload[0]) && $payload[0] instanceof RepresentationInterface) {
- $jsonLd = [];
- foreach ($payload as $representation) {
- $jsonLd[] = $this->getJsonLdWithContext($representation);
- }
- return $this->serializeJsonLdToFormat($jsonLd, $this->format);
- }
- }
-
$output = parent::render($payload);
- if ($payload instanceof RepresentationInterface) {
- $eventManager = $payload->getEventManager();
- $args = $eventManager->prepareArgs(['jsonLd' => $output]);
- $eventManager->trigger('rep.resource.json_output', $payload, $args);
- $output = $args['jsonLd'];
- }
-
- if (null !== $model->getOption('pretty_print')) {
- // Pretty print the JSON.
- $output = Json::prettyPrint($output);
- }
-
- $jsonpCallback = (string) $model->getOption('callback');
- if (!empty($jsonpCallback)) {
- // Wrap the JSON in a JSONP callback. Normally this would be done
- // via `$this->setJsonpCallback()` but we don't want to pass the
- // wrapped string to `rep.resource.json_output` handlers.
- $output = sprintf('%s(%s);', $jsonpCallback, $output);
- $this->hasJsonpCallback = true;
- }
-
- return $output;
- }
-
- /**
- * Get the JSON-LD array of a representation, adding the @context.
- *
- * @param RepresentationInterface $representation
- * @return array
- */
- public function getJsonLdWithContext(RepresentationInterface $representation)
- {
- // Add the @context by encoding the output as JSON, then decoding to an array.
- $eventManager = $representation->getEventManager();
- $jsonLd = Json::decode(Json::encode($representation), true);
- if (!$this->context) {
- // Get the JSON-LD @context
- $args = $eventManager->prepareArgs(['context' => []]);
- $eventManager->trigger('api.context', null, $args);
- $this->context = $args['context'];
- }
- $jsonLd['@context'] = $this->context;
- return $jsonLd;
- }
-
- /**
- * Serialize JSON-LD to another format.
- *
- * @param array $jsonLd
- * @param string $format
- * @param string
- */
- public function serializeJsonLdToFormat(array $jsonLd, string $format)
- {
- $graph = new \EasyRdf\Graph;
- $graph->parse(Json::encode($jsonLd), 'jsonld');
- return $graph->serialise($format);
+ // Allow modules to return custom output.
+ $args = $this->eventManager->prepareArgs([
+ 'model' => $model,
+ 'payload' => $payload,
+ 'format' => $this->format,
+ 'output' => $output,
+ ]);
+ $this->eventManager->trigger('api.output.serialize', $this, $args);
+ return $args['output'];
}
/**
diff --git a/application/src/View/Strategy/ApiJsonStrategy.php b/application/src/View/Strategy/ApiJsonStrategy.php
index 95aa311a82..62d50addfb 100644
--- a/application/src/View/Strategy/ApiJsonStrategy.php
+++ b/application/src/View/Strategy/ApiJsonStrategy.php
@@ -8,6 +8,7 @@
use Omeka\Mvc\Exception as MvcException;
use Omeka\View\Model\ApiJsonModel;
use Omeka\View\Renderer\ApiJsonRenderer;
+use Laminas\EventManager\EventManager;
use Laminas\View\Strategy\JsonStrategy;
use Laminas\View\ViewEvent;
@@ -27,14 +28,18 @@ class ApiJsonStrategy extends JsonStrategy
'jsonld' => 'application/ld+json',
];
+ protected $eventManager;
+
/**
* Constructor, sets the renderer object
*
- * @param \Omeka\View\Renderer\ApiJsonRenderer
+ * @param ApiJsonRenderer
+ * @param EventManager
*/
- public function __construct(ApiJsonRenderer $renderer)
+ public function __construct(ApiJsonRenderer $renderer, EventManager $eventManager)
{
$this->renderer = $renderer;
+ $this->eventManager = $eventManager;
}
public function selectRenderer(ViewEvent $e)
@@ -128,6 +133,11 @@ protected function getStatusCodeForException(\Exception $exception = null)
*/
protected function getFormat(ApiJsonModel $model)
{
+ // Allow modules to register formats.
+ $args = $this->eventManager->prepareArgs(['formats' => $this->formats]);
+ $this->eventManager->trigger('api.output.formats', $this, $args);
+ $this->formats = $args['formats'];
+
// Prioritize the "format" query parameter.
$format = $model->getOption('format');
if (array_key_exists($format, $this->formats)) {
diff --git a/application/test/OmekaTest/View/Renderer/ApiJsonRendererTest.php b/application/test/OmekaTest/View/Renderer/ApiJsonRendererTest.php
index 34c46ba656..6f80a6a67f 100644
--- a/application/test/OmekaTest/View/Renderer/ApiJsonRendererTest.php
+++ b/application/test/OmekaTest/View/Renderer/ApiJsonRendererTest.php
@@ -9,6 +9,19 @@
class ApiJsonRendererTest extends TestCase
{
+ protected $eventManager;
+
+ public function setUp(): void
+ {
+ $this->eventManager = $this->createMock('Laminas\EventManager\EventManager');
+ $this->eventManager->expects($this->any())
+ ->method('prepareArgs')
+ ->will($this->returnCallback(function ($arg) {
+ return $arg;
+ })
+ );
+ }
+
public function testRendererUsesApiResponse()
{
$testValue = ['test' => 'foo'];
@@ -22,7 +35,7 @@ public function testRendererUsesApiResponse()
->method('getApiResponse')
->will($this->returnValue($response));
- $renderer = new ApiJsonRenderer;
+ $renderer = new ApiJsonRenderer($this->eventManager);
$this->assertEquals(Json::encode($testValue), $renderer->render($model));
}
@@ -38,7 +51,7 @@ public function testRendererPassesOnNullResponse()
->method('getApiResponse')
->will($this->returnValue($response));
- $renderer = new ApiJsonRenderer;
+ $renderer = new ApiJsonRenderer($this->eventManager);
$this->assertEquals(null, $renderer->render($model));
}
@@ -57,7 +70,7 @@ public function testRendererShowsErrors()
->method('getException')
->will($this->returnValue($exception));
- $renderer = new ApiJsonRenderer;
+ $renderer = new ApiJsonRenderer($this->eventManager);
$this->assertEquals(Json::encode(['errors' => ['foo' => ['bar']]]), $renderer->render($model));
}
}
diff --git a/application/test/OmekaTest/View/Strategy/ApiJsonStrategyTest.php b/application/test/OmekaTest/View/Strategy/ApiJsonStrategyTest.php
index b67e93d935..87e651d166 100644
--- a/application/test/OmekaTest/View/Strategy/ApiJsonStrategyTest.php
+++ b/application/test/OmekaTest/View/Strategy/ApiJsonStrategyTest.php
@@ -11,14 +11,22 @@
class ApiJsonStrategyTest extends TestCase
{
public $renderer;
+ public $eventManager;
public $strategy;
public $event;
public function setUp(): void
{
$this->renderer = $this->createMock('Omeka\View\Renderer\ApiJsonRenderer');
-
- $this->strategy = new ApiJsonStrategy($this->renderer);
+ $this->eventManager = $this->createMock('Laminas\EventManager\EventManager');
+ $this->eventManager->expects($this->any())
+ ->method('prepareArgs')
+ ->will($this->returnCallback(function ($arg) {
+ return $arg;
+ })
+ );
+
+ $this->strategy = new ApiJsonStrategy($this->renderer, $this->eventManager);
$this->event = new ViewEvent;
$httpResponse = new HttpResponse;
diff --git a/application/view/common/advanced-search.phtml b/application/view/common/advanced-search.phtml
index 748094ad16..a5db20092b 100644
--- a/application/view/common/advanced-search.phtml
+++ b/application/view/common/advanced-search.phtml
@@ -20,6 +20,7 @@ $addPartial = function($partial) use (&$partials, $partialExcludelist) {
}
};
+$addPartial('common/advanced-search/sort');
$addPartial('common/advanced-search/fulltext');
$addPartial('common/advanced-search/properties');
$addPartial('common/advanced-search/resource-class');
@@ -48,7 +49,6 @@ if ($this->status()->isSiteRequest()) {
$addPartial('common/advanced-search/resource-template-restrict');
}
$addPartial('common/advanced-search/ids');
-$addPartial('common/advanced-search/sort');
$filterResults = $this->trigger(
'view.advanced_search',
diff --git a/application/view/common/advanced-search/has-media.phtml b/application/view/common/advanced-search/has-media.phtml
index ae8dd02972..47c161eddc 100644
--- a/application/view/common/advanced-search/has-media.phtml
+++ b/application/view/common/advanced-search/has-media.phtml
@@ -1,11 +1,12 @@
setLabel($this->translate('Search by media presence'))
+$element
+ ->setLabel('Search by media presence') // @translate
->setValueOptions([
- '1' => $this->translate('Has media'),
- '0' => $this->translate('Has no media'),
+ '1' => 'Has media', // @translate
+ '0' => 'Has no media', // @translate
])
- ->setEmptyOption($this->translate('Select media presence…'))
- ->setValue($query['has_media'] ?? '');
+ ->setEmptyOption('Select media presence…') // @translate
+ ->setValue($query['has_media'] ?? '')
+ ->setAttribute('id', 'has_media');
echo $this->formRow($element);
-?>
diff --git a/application/view/common/advanced-search/item-sets.phtml b/application/view/common/advanced-search/item-sets.phtml
index 0cd2dfa3ae..80a157e2f9 100644
--- a/application/view/common/advanced-search/item-sets.phtml
+++ b/application/view/common/advanced-search/item-sets.phtml
@@ -38,7 +38,7 @@ if ($this->status()->isSiteRequest()) {
$selectOptions = [];
}
?>
-
+