Skip to content

Commit

Permalink
Merge pull request #1 from dartmouth-dltg/storybooth
Browse files Browse the repository at this point in the history
Storybooth
  • Loading branch information
jdshaw authored Aug 23, 2022
2 parents ef8a2aa + a11b5b2 commit 2ecbb5c
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 29 deletions.
141 changes: 141 additions & 0 deletions asset/js/random-items-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
'use strict';

class RandomItemsBlock {

constructor(itemIds, randIdx, totalImages, basePath, siteSlug, linkToItems = false, blockUuid, btnPlacement, headerLevel) {
this.API_PATH = "api/items";
this.itemIds = itemIds;
this.randIdx = randIdx;
this.basePath = basePath;
this.siteSlug = siteSlug;
this.totalImages = totalImages;
this.linkToItems = linkToItems;
this.btnPlacement = btnPlacement;
this.itemPath = this.basePath + "/s/" + this.siteSlug + "/item/";
this.media_api_path = this.basePath + '/api/media/';
this.headerLevel = headerLevel;
this.spinner = '<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>';
this.spinnerClass = '.lds-ellipsis';
}

getNewRandomItems(el, btn) {
const self = this
el.html(this.spinner);
setTimeout(function(){
for (let i = 1; i <= self.totalImages; i++) {
self.randIdx = (self.randIdx + i) % self.itemIds.length;
self.getRandomItem(el, btn)
}
}, 400, el, btn);

}

getRandomItem(el, btn) {
const self = this;
$.ajax({
url: self.basePath + "/" + self.API_PATH + "/" + self.itemIds[self.randIdx],
targetEl: el,
btnEl: btn,
success: function(data) {
self.parseApiData(data, this.targetEl, this.btnEl);
$(self.spinnerClass).remove()
}
}
);
}

// FIXME: Can we pass the description field in so we can look at something other than dcterms:description?
parseApiData(data, targetEl, btnEl) {
const itemId = data['o:id'];
const itemImageUrl = typeof(data['thumbnail_display_urls']['large']) != 'undefined' ? data['thumbnail_display_urls']['large'] : null;
const itemTitle = typeof(data['o:title']) != 'undefined' ? data['o:title'] : null;
const itemDescription = typeof(data['dcterms:description']) != 'undefined' ? data['dcterms:description'][0]['@value'] : null;
const imageMediaUrl = typeof(data['o:media']) != 'undefined' ? data['o:media'][0]['@id'] : null
const descriptionMediaUrl = typeof(data['o:media']) != 'undefined' && typeof(data['o:media'][1]) != 'undefined' ? data['o:media'][1]['@id'] : null

if (itemImageUrl != null && itemTitle != null) {
this.renderApiData(itemId, itemImageUrl, itemTitle, itemDescription, imageMediaUrl, descriptionMediaUrl, targetEl, btnEl);
}
else {
this.randIdx = (this.randIdx + 1) % this.itemIds.length;
this.getRandomItem(targetEl, btnEl);
}
}

renderApiData(itemId, itemImageUrl, itemTitle, itemDescription, imageMediaUrl, descriptionMediaUrl, targetEl, btnEl) {
const self = this;
let altText = '';
let descriptionHtml = null;

if (descriptionMediaUrl != null) {
$.when(
$.get(imageMediaUrl, function(data) {
altText = typeof(data['o:alt_text']) != 'undefined' && data['o:alt_text'] != null ? data['o:alt_text'] : '';
}),
$.get(descriptionMediaUrl, function(data) {
descriptionHtml = typeof(data['data']) != 'undefined' && data['data']['html'] != '' ? data['data']['html'] : null;
})
)
.done(function() {
self.assembleHtml(itemId, itemImageUrl, itemTitle, itemDescription, altText, descriptionHtml, targetEl, btnEl);
})
}
else {
$.when(
$.get(this.imageMediaUrl, function(data) {
altText = typeof(data['o:alt_text']) != 'undefined' && data['o:alt_text'] != null ? data['o:alt_text'] : '';
})
)
.done(function() {
self.assembleHtml(itemId, itemImageUrl, itemTitle, itemDescription, altText, descriptionHtml, targetEl, btnEl);
})
}
}

assembleHtml(itemId, itemImageUrl, itemTitle, itemDescription, altText, descriptionHtml, targetEl, btnEl) {
const self = this;
let html = '<div class="random-item">';
if (this.linkToItems == 1) {
html += '<' + this.headerLevel + '><a href="' + this.itemPath + itemId + '">' + itemTitle + '</a></' + this.headerLevel + '>';
html += '<div class="random-item-image">';
html += '<a href="' + this.itemPath + itemId + '"><img src="' + itemImageUrl + '" alt="' + altText + '"></a>';
html += '</div>';
html += '<div class="random-item-description">';
}
else {
html += '<' + this.headerLevel + '>' + itemTitle + '</' + this.headerLevel + '>';
html += '<div class="random-item-image">';
html += '<img src="' + itemImageUrl + '" alt="' + altText + '">';
html += '</div>';
html += '<div class="random-item-description">';
}

if (descriptionHtml != null) {
html += descriptionHtml;
}
else if (itemDescription != null) {
html += '<p>' + itemDescription + '</p>';
}

if (self.btnPlacement == 1) {
html += btnEl.outerHTML;
}

html += '</div>';
html += '</div>';

targetEl.append(html);
}
}

(function($) {
$(document).ready(function() {
$('body').on('click', '.random-items-block-switch', function(e) {
e.preventDefault();
const btnHtml = $(this).parent()[0];
const targetId = $(this).data('random-block-target');
const targetEl = $('#' + targetId).children('.item.resource');
randomItemsBlock.getNewRandomItems(targetEl, btnHtml);
})
});
})(jQuery);
74 changes: 71 additions & 3 deletions src/Site/BlockLayout/RandomItems.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Omeka\Api\Representation\SitePageRepresentation;
use Omeka\Site\BlockLayout\AbstractBlockLayout;
use Laminas\Form\Element\Checkbox;
use Laminas\Form\Element\Number;
use Laminas\Form\Element\Select;
use Laminas\Form\Element\Text;
use Laminas\View\Renderer\PhpRenderer;

class RandomItems extends AbstractBlockLayout
Expand All @@ -19,18 +22,83 @@ public function getLabel()
public function form(PhpRenderer $view, SiteRepresentation $site, SitePageRepresentation $page = null, SitePageBlockRepresentation $block = null)
{
$count = new Number('o:block[__blockIndex__][o:data][count]');
$count->setLabel('Number of items'); // @translate
$count->setLabel('Number of items to display'); // @translate
$count->setAttributes([
'min' => '1',
'step' => '1',
]);
$count->setValue($block ? $block->dataValue('count', '3') : '3');

return $view->formRow($count);
$totalItems = new Number('o:block[__blockIndex__][o:data][totalItems]');
$totalItems->setLabel('Max number of random items to choose from)'); // @translate
$totalItems->setAttributes([
'min' => '1',
'step' => '1',
]);
$totalItems->setValue($block ? $block->dataValue('totalItems', '1000') : '1000');

// get the resource templates options
// we'll use this to narrow the SQL criteria
$data['sort_by'] = 'title';
$response = $view->api()->search('resource_templates', $data);
$resource_templates = $response->getContent();

$resource_templates_list = [];
$resource_templates_list['all'] = "All sites";
foreach($resource_templates as $res_template) {
$resource_templates_list[$res_template->id()] = $res_template->label();
}

$resTemplateSelectedOption = $block ? $block->dataValue('show_res_template_select_option', '') : '';
$resTemplateSelect = new Select('o:block[__blockIndex__][o:data][show_res_template_select_option]');
$resTemplateSelect->setValueOptions($resource_templates_list)->setValue($resTemplateSelectedOption);
$resTemplateSelect->setLabel('Choose a resource template to select random items from');

$resTemplateSelect->setValue($block ? $block->dataValue('show_res_template_select_option', '0') : '0');

$userRandom = new Checkbox('o:block[__blockIndex__][o:data][userRandom]');
$userRandom->setLabel('Check to allow users to see additional random items');
$userRandom->setValue($block ? $block->dataValue('userRandom', false) : false);

$userRandomLabel = new Text('o:block[__blockIndex__][o:data][userRandomLabel]');
$userRandomLabel->setLabel('If the above is checked, set a label for the button that users click to see a new random item');
$userRandomLabel->setValue($block && $block->dataValue('userRandomLabel') != '' ? $block->dataValue('userRandomLabel', 'View Another Item') : 'View Another item');

$userRandomPlacement = new Checkbox('o:block[__blockIndex__][o:data][userRandomPlacement]');
$userRandomPlacement->setLabel('If users are allowed to see additional random items AND the number of items to display is just one, then check to place the random button below the description.');
$userRandomPlacement->setValue($block ? $block->dataValue('userRandomPlacement', false) : false);

$linkItems = new Checkbox('o:block[__blockIndex__][o:data][linkItems]');
$linkItems->setLabel('Check to link random items to their display pages');
$linkItems->setValue($block ? $block->dataValue('linkItems', false) : false);

$header_levels_list = ['h2','h3','h4','h5'];
$headerLevelSelectedOption = $block ? $block->dataValue('show_header_level_select_option', '') : '';
$headerLevelSelect = new Select('o:block[__blockIndex__][o:data][show_header_level_select_option]');
$headerLevelSelect->setValueOptions($header_levels_list)->setValue($headerLevelSelectedOption);
$headerLevelSelect->setLabel('Choose a header level to use for the item display. Select a level that meets accessibility guidelines and ensures heading levels are not skipped.');

$headerLevelSelect->setValue($block ? $block->dataValue('show_header_level_select_option', '0') : '0');

$formReturn = $view->formRow($resTemplateSelect);
$formReturn .= $view->formRow($count);
$formReturn .= $view->formRow($totalItems);
$formReturn .= $view->formRow($userRandom);
$formReturn .= $view->formRow($userRandomLabel);
$formReturn .= $view->formRow($userRandomPlacement);
$formReturn .= $view->formRow($linkItems);
$formReturn .= $view->formRow($headerLevelSelect);

return $formReturn;
}

public function prepareRender(PhpRenderer $view)
{
$view->headScript()->appendFile($view->assetUrl('js/random-items-block.js', 'RandomItemsBlock'));
}

public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
{
return $view->partial('random-items-block/common/block-layouts/random-items', ['block' => $block]);
return $view->partial('random-items-block/common/block-layouts/random-items', ['block' => $block, 'view' => $view]);
}
}
44 changes: 29 additions & 15 deletions src/View/Helper/RandomItems.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,62 @@ public function __construct(EntityManager $entityManager, ApiAdapterManager $api
/**
* @return \Omeka\Api\Representation\ItemRepresentation[]
*/
public function __invoke(int $count): array
public function __invoke(int $count, int $totalItems, string $res_template_id = null): array
{
$em = $this->entityManager;

$itemAdapter = $this->apiAdapterManager->get('items');

$items = $em->getRepository(Item::class)->findBy(['id' => $this->getRandomItemIds($count)]);
$itemIds = $this->getRandomItemIds($totalItems, $res_template_id);
$randItemsIdx = rand(0, count($itemIds) - 1);
$itemRepresentations = [];
foreach ($items as $item) {
$itemRepresentations[] = $itemAdapter->getRepresentation($item);
$idxs = [];
for ($i = 0; $i < $count; $i++) {
array_push($idxs, $randItemsIdx);
$itemRepresentations[] = $itemAdapter->getRepresentation($em->getRepository(Item::class)->findBy(['id' => $itemIds[$randItemsIdx]])[0]);
$randItemsIdx = count($itemIds) > 1 ? ($randItemsIdx + 1) % (count($itemIds) - 1) : 1;
}

return $itemRepresentations;
return array($itemIds, $itemRepresentations, $idxs[$count - 1]);
}

protected function getRandomItemIds($count, $useCache = true)
protected function getRandomItemIds($totalItems, $res_template_id, $useCache = true)
{
$cacheKey = "omeka:RandomItems:randomItemIds:$count";
$itemIds = $useCache ? $this->getFromCache($cacheKey) : false;
if (false === $itemIds) {
$cacheKey = "omeka:RandomItems:randomItemIds:$totalItems";
$items = $useCache ? $this->getFromCache($cacheKey) : false;
if (false === $items) {
$em = $this->entityManager;
$conn = $em->getConnection();

$sql = 'SELECT id FROM resource';
$sql .= ' WHERE resource_type = :resourceType';

if (isset($res_template_id) && $res_template_id != 'all') {
$sql .= ' AND resource_template_id = :resourceTemplateId';
}

// Limit to public items so we don't have to check for user permissions
// (anyone can see public items even anonymous users)
$sql .= ' AND is_public = 1';

$sql .= ' ORDER BY RAND()';
$sql .= " LIMIT $count";
$sql .= ' ORDER BY id';
$sql .= " LIMIT $totalItems";

$stmt = $conn->prepare($sql);
$stmt->execute(['resourceType' => Item::class]);

if (isset($res_template_id) && $res_template_id != 'all') {
$stmt->execute(['resourceType' => Item::class, 'resourceTemplateId' => $res_template_id]);
}
else {
$stmt->execute(['resourceType' => Item::class]);
}
$result = $stmt->fetchAll();
$itemIds = array_column($result, 'id');
$items = array_column($result, 'id');

$this->storeInCache($cacheKey, $itemIds);
$this->storeInCache($cacheKey, $items);
}

return $itemIds;
return $items;
}

protected function getFromCache(string $key)
Expand Down
Loading

0 comments on commit 2ecbb5c

Please sign in to comment.