diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 12c50d8f86f1dbdc41d7db7a68fd37dff1322aa9..a375d807c25d18083144a77b5e67846368843cd0 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -610,6 +610,8 @@ $config = [ // driver is not defined here, it will inherit configuration from a configured // parent class. The defaultTab setting may be used to specify the default // active tab; if null, the value from the relevant .ini file will be used. + // You can also specify which tabs are loaded in the background when arriving + // at a record tabs view with backgroundLoadedTabs as a list of tab indexes. 'recorddriver_tabs' => [ 'VuFind\RecordDriver\EDS' => [ 'tabs' => [ @@ -654,6 +656,7 @@ $config = [ 'Details' => 'StaffViewArray', ], 'defaultTab' => null, + // 'backgroundLoadedTabs' => ['UserComments', 'Details'] ], 'VuFind\RecordDriver\SolrMarc' => [ 'tabs' => [ diff --git a/module/VuFind/src/VuFind/Controller/AbstractBase.php b/module/VuFind/src/VuFind/Controller/AbstractBase.php index 16b6701f572f65e6d55933c44b5d055ff048a3d5..5c9900cd4d983c49cec7fd9273f46b04f53ff630 100644 --- a/module/VuFind/src/VuFind/Controller/AbstractBase.php +++ b/module/VuFind/src/VuFind/Controller/AbstractBase.php @@ -637,4 +637,15 @@ class AbstractBase extends AbstractActionController { $this->followup()->clear('url'); } + + /** + * Get the tab configuration for this controller. + * + * @return array + */ + protected function getRecordTabConfig() + { + $cfg = $this->getServiceLocator()->get('Config'); + return $cfg['vufind']['recorddriver_tabs']; + } } diff --git a/module/VuFind/src/VuFind/Controller/AbstractRecord.php b/module/VuFind/src/VuFind/Controller/AbstractRecord.php index 317c6fd665795ab7ebd46109dbd589c2af5c0714..7ea90a10dba3ca1796b86e05966640ce39671f53 100644 --- a/module/VuFind/src/VuFind/Controller/AbstractRecord.php +++ b/module/VuFind/src/VuFind/Controller/AbstractRecord.php @@ -614,14 +614,15 @@ class AbstractRecord extends AbstractBase } /** - * Get the tab configuration for this controller. + * Alias to getRecordTabConfig for backward compatibility. + * + * @deprecated use getRecordTabConfig instead * * @return array */ protected function getTabConfiguration() { - $cfg = $this->getServiceLocator()->get('Config'); - return $cfg['vufind']['recorddriver_tabs']; + return $this->getRecordTabConfig(); } /** @@ -635,11 +636,14 @@ class AbstractRecord extends AbstractBase $request = $this->getRequest(); $rtpm = $this->getServiceLocator()->get('VuFind\RecordTabPluginManager'); $details = $rtpm->getTabDetailsForRecord( - $driver, $this->getTabConfiguration(), $request, + $driver, $this->getRecordTabConfig(), $request, $this->fallbackDefaultTab ); $this->allTabs = $details['tabs']; $this->defaultTab = $details['default'] ? $details['default'] : false; + $this->backgroundTabs = $rtpm->getBackgroundTabNames( + $driver, $this->getRecordTabConfig() + ); } /** @@ -669,6 +673,19 @@ class AbstractRecord extends AbstractBase return $this->allTabs; } + /** + * Get names of tabs to be loaded in the background. + * + * @return array + */ + protected function getBackgroundTabs() + { + if (null === $this->backgroundTabs) { + $this->loadTabDetails(); + } + return $this->backgroundTabs; + } + /** * Is the result scroller active? * @@ -709,6 +726,7 @@ class AbstractRecord extends AbstractBase $view->tabs = $this->getAllTabs(); $view->activeTab = strtolower($tab); $view->defaultTab = strtolower($this->getDefaultTab()); + $view->backgroundTabs = $this->getBackgroundTabs(); $view->loadInitialTabWithAjax = isset($config->Site->loadInitialTabWithAjax) ? (bool) $config->Site->loadInitialTabWithAjax : false; diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php index 98c7b7f50d4406259e076cbc6c1bb023b725b8b2..af4244d91d1318d60d490e66ad2aad6efbfefa4f 100644 --- a/module/VuFind/src/VuFind/Controller/AjaxController.php +++ b/module/VuFind/src/VuFind/Controller/AjaxController.php @@ -796,6 +796,7 @@ class AjaxController extends AbstractBase 'Information' ); + $rtpm = $this->getServiceLocator()->get('VuFind\RecordTabPluginManager'); $html = $this->getViewRenderer() ->render( "record/ajaxview-" . $viewtype . ".phtml", @@ -803,6 +804,9 @@ class AjaxController extends AbstractBase 'defaultTab' => $details['default'], 'driver' => $driver, 'tabs' => $details['tabs'], + 'backgroundTabs' => $rtpm->getBackgroundTabNames( + $driver, $this->getRecordTabConfig() + ) ] ); return $this->output($html, self::STATUS_OK); diff --git a/module/VuFind/src/VuFind/Controller/CollectionController.php b/module/VuFind/src/VuFind/Controller/CollectionController.php index 7b3e42f4ed9c72e199487c471687b1f6fb6065a0..a0233529ab007f335f498858b0d8b18f34dc4af9 100644 --- a/module/VuFind/src/VuFind/Controller/CollectionController.php +++ b/module/VuFind/src/VuFind/Controller/CollectionController.php @@ -59,7 +59,7 @@ class CollectionController extends AbstractRecord * * @return array */ - protected function getTabConfiguration() + protected function getRecordTabConfig() { $cfg = $this->getServiceLocator()->get('Config'); return $cfg['vufind']['recorddriver_collection_tabs']; diff --git a/module/VuFind/src/VuFind/RecordTab/PluginManager.php b/module/VuFind/src/VuFind/RecordTab/PluginManager.php index 514710b40bba9cd41e3e5d64a8caaca1b6063488..28792dafdbfb55e994fe7a4ec3914ecbced62863 100644 --- a/module/VuFind/src/VuFind/RecordTab/PluginManager.php +++ b/module/VuFind/src/VuFind/RecordTab/PluginManager.php @@ -95,6 +95,21 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager return $this->getConfigByClass($driver, $config, 'tabs', []); } + /** + * Get an array of tabs names configured to load via AJAX in the background + * + * @param AbstractRecordDriver $driver Record driver + * @param array $config Tab configuration (associative array + * including 'tabs' array mapping driver class => tab service name) + * + * @return array + */ + public function getBackgroundTabNames(AbstractRecordDriver $driver, + array $config + ) { + return $this->getConfigByClass($driver, $config, 'backgroundLoadedTabs', []); + } + /** * Get a default tab by looking up the provided record driver in the tab * configuration array. diff --git a/themes/bootstrap3/js/embedded_record.js b/themes/bootstrap3/js/embedded_record.js index 51e7f0cb04bd783f9447df6509172d9535175a96..0d4eeb028ebe7cb7ec5e43508dadd1ce8a8346a9 100644 --- a/themes/bootstrap3/js/embedded_record.js +++ b/themes/bootstrap3/js/embedded_record.js @@ -157,6 +157,9 @@ VuFind.register('embedded', function embedded() { ); } ); + longNode.find('[data-background]').each(function setupEmbeddedBackgroundTabs(index, el) { + ajaxLoadTab(el.id, false); + }); // Add events to record toolbar VuFind.lightbox.bind(longNode); if (typeof checkSaveStatuses == 'function') { diff --git a/themes/bootstrap3/js/record.js b/themes/bootstrap3/js/record.js index 863968bc504eef6184135ee680cd6af5988c498e..5df87a2e8cd9e3d27ef53b0a5b7069d45bdf22e2 100644 --- a/themes/bootstrap3/js/record.js +++ b/themes/bootstrap3/js/record.js @@ -231,6 +231,19 @@ function ajaxTagUpdate(_link, tag, _remove) { }); } +function getNewRecordTab(tabid) { + return $('<div class="tab-pane ' + tabid + '-tab"><i class="fa fa-spinner fa-spin" aria-hidden="true"></i> ' + VuFind.translate('loading') + '...</div>'); +} + +function backgroundLoadTab(tabid) { + if ($('.' + tabid + '-tab').length > 0) { + return; + } + var newTab = getNewRecordTab(tabid); + $('.nav-tabs a.'+tabid).closest('.result,.record').find('.tab-content').append(newTab); + return ajaxLoadTab(newTab, tabid, false); +} + function applyRecordTabHash() { var activeTab = $('.record-tabs li.active a').attr('class'); var $initiallyActiveTab = $('.record-tabs li.initiallyActive a'); @@ -277,12 +290,16 @@ function recordDocReady() { window.location.hash = tabid; return false; } else { - var newTab = $('<div class="tab-pane active ' + tabid + '-tab"><i class="fa fa-spinner fa-spin" aria-hidden="true"></i> ' + VuFind.translate('loading') + '...</div>'); + var newTab = getNewRecordTab(tabid).addClass('active'); $top.find('.tab-content').append(newTab); return ajaxLoadTab(newTab, tabid, !$(this).parent().hasClass('initiallyActive')); } }); + $('[data-background]').each(function setupBackgroundTabs(index, el) { + backgroundLoadTab(el.className); + }); + registerTabEvents(); applyRecordTabHash(); } diff --git a/themes/bootstrap3/templates/collection/view.phtml b/themes/bootstrap3/templates/collection/view.phtml index 640a86b41269d297dc656fa57f002d54aa271d66..08b328f6ff679b60ca91fe9a6cdd901506b3c866 100644 --- a/themes/bootstrap3/templates/collection/view.phtml +++ b/themes/bootstrap3/templates/collection/view.phtml @@ -62,14 +62,12 @@ <?=$this->record($this->driver)->getToolbar()?> -<div class="row"> +<div class="record row"> <div class="<?=$tree ? 'col-sm-12' : $this->layoutClass('mainbody') ?>"> - <div class="record"> - <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>" class="hiddenId" id="record_id" /> - <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier())?>" class="hiddenSource" /> - <?=$this->flashmessages()?> - <?=$this->record($this->driver)->getCollectionMetadata()?> - </div> + <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>" class="hiddenId" id="record_id" /> + <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier())?>" class="hiddenSource" /> + <?=$this->flashmessages()?> + <?=$this->record($this->driver)->getCollectionMetadata()?> <? if (count($this->tabs) > 0): ?> <a name="tabnav"></a> @@ -91,7 +89,7 @@ if (!$obj->supportsAjax()) { $tab_classes[] = 'noajax'; } ?> <li<?=count($tab_classes) > 0 ? ' class="' . implode(' ', $tab_classes) . '"' : ''?>> - <a class="<?=strtolower($tab) ?>" href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav"><?=$this->transEsc($desc)?></a> + <a class="<?=strtolower($tab) ?>" href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav"<? if ($obj->supportsAjax() && in_array($tab, $this->backgroundTabs)):?> data-background<? endif ?>><?=$this->transEsc($desc)?></a> </li> <? endforeach; ?> </ul> diff --git a/themes/bootstrap3/templates/record/ajaxview-accordion.phtml b/themes/bootstrap3/templates/record/ajaxview-accordion.phtml index 71916a3a67661b4fa829a94e6b6d16e155b23787..150886392be963bd898b552655b03bcda093d236 100644 --- a/themes/bootstrap3/templates/record/ajaxview-accordion.phtml +++ b/themes/bootstrap3/templates/record/ajaxview-accordion.phtml @@ -75,7 +75,7 @@ if (!$obj->supportsAjax()) { $tab_classes[] = 'noajax'; } ?> <div class="panel panel-default <?=implode(' ', $tab_classes) ?>"> - <div id="<?=strtolower($tab)?>_<?=$idSuffix?>" class="list-tab-toggle panel-heading" data-toggle="collapse" data-parent="#accordion_<?=$idSuffix?>" data-target="#<?=strtolower($tab)?>_<?=$idSuffix?>-content"> + <div id="<?=strtolower($tab)?>_<?=$idSuffix?>" class="list-tab-toggle panel-heading" data-toggle="collapse" data-parent="#accordion_<?=$idSuffix?>" data-target="#<?=strtolower($tab)?>_<?=$idSuffix?>-content"<? if ($obj->supportsAjax() && in_array($tab, $this->backgroundTabs)):?> data-background<? endif ?>> <h4 class="panel-title"> <a class="accordion-toggle" data-href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav"><?=$desc ?></a> </h4> diff --git a/themes/bootstrap3/templates/record/ajaxview-tabs.phtml b/themes/bootstrap3/templates/record/ajaxview-tabs.phtml index 955095841b3a57b27915ae2c504a666d52724889..a995b43151542b2ef4e59c86ded443ba0405e5c0 100644 --- a/themes/bootstrap3/templates/record/ajaxview-tabs.phtml +++ b/themes/bootstrap3/templates/record/ajaxview-tabs.phtml @@ -43,7 +43,7 @@ if (!$obj->supportsAjax()) { $tab_classes[] = 'noajax'; } ?> <li<?=count($tab_classes) > 0 ? ' class="' . implode(' ', $tab_classes) . '"' : ''?>> - <a id="<?=strtolower($tab)?>_<?=$idSuffix?>" class="list-tab-toggle" href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav" data-toggle="tab" data-target="#<?=strtolower($tab)?>_<?=$idSuffix?>-content"><?=$this->transEsc($desc)?></a> + <a id="<?=strtolower($tab)?>_<?=$idSuffix?>" class="list-tab-toggle" href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav" data-toggle="tab" data-target="#<?=strtolower($tab)?>_<?=$idSuffix?>-content"<? if ($obj->supportsAjax() && in_array($tab, $this->backgroundTabs)):?> data-background<? endif ?>><?=$this->transEsc($desc)?></a> </li> <? endforeach; ?> </ul> diff --git a/themes/bootstrap3/templates/record/view.phtml b/themes/bootstrap3/templates/record/view.phtml index 180eaeee6a81f39381ad8f9546b88724e4af6710..d17786fd5b43a7ddcd00221c1b919edda019ba75 100644 --- a/themes/bootstrap3/templates/record/view.phtml +++ b/themes/bootstrap3/templates/record/view.phtml @@ -56,14 +56,12 @@ <?=$this->record($this->driver)->getToolbar()?> -<div class="row"> +<div class="record source<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier())?> row"> <div class="<?=$this->layoutClass('mainbody')?>"> - <div class="record source<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier())?>"> - <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>" class="hiddenId" /> - <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier()) ?>" class="hiddenSource" /> - <?=$this->flashmessages()?> - <?=$this->record($this->driver)->getCoreMetadata()?> - </div> + <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>" class="hiddenId" /> + <input type="hidden" value="<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier()) ?>" class="hiddenSource" /> + <?=$this->flashmessages()?> + <?=$this->record($this->driver)->getCoreMetadata()?> <? if (count($this->tabs) > 0): ?> <a name="tabnav"></a> @@ -85,7 +83,7 @@ if (!$obj->supportsAjax()) { $tab_classes[] = 'noajax'; } ?> <li<?=count($tab_classes) > 0 ? ' class="' . implode(' ', $tab_classes) . '"' : ''?>> - <a class="<?=strtolower($tab) ?>" href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav"><?=$this->transEsc($desc)?></a> + <a class="<?=strtolower($tab) ?>" href="<?=$this->recordLink()->getTabUrl($this->driver, $tab)?>#tabnav"<? if ($obj->supportsAjax() && in_array($tab, $this->backgroundTabs)):?> data-background<? endif ?>><?=$this->transEsc($desc)?></a> </li> <? endforeach; ?> </ul>