Kookaburra Pages and Albums / Album Sets

Hi Matt,

thanks for the information.
I am very curious about the innovations :slight_smile:

At the moment I am looking for a solution to make my tabs linkable. I mean that each tab can be reached under an url. For example: for tab1 “www.mysite.com/test#tab1” etc.
This works with some templates from Codepen but I can’t add albums to individual tabs, at least not with:

<ul class="tabs">
<li data-album="588036">Sample Images</li>
</ul>

and the previous phplugins entry:

// Use the JavaScript JSON API to get album data;
		// logs the response to the browser's debug console.
		function scripts() {
			$siteURL = siteURL();
			$apiPath = "{$siteURL}backlight/" . (URLHelper::rewriteEnabled() ? "api" : "?m=publisher&c=jsonApi");
			$apiToken = AuthHelper::getJSONAPIToken();

			echo <<<HTML
			<script src="{$siteURL}backlight/modules/module-publisher/lib/js/api.js"></script>
			<script>
				// instantiate the api.
				const backlight = new Backlight("{$apiPath}");

				// create a placeholder for our images.
				const albums = {};

				// create an HTML template to be used for individual photos
				const renderTemplate = photo => (`
					<figure itemscope itemtype="http://schema.org/ImageObject">
						<div>
							<a
								data-caption="\${photo.title}"
								data-download-src="\${photo.path}photos2x/\${photo.filename}"
								data-fancybox="album-\${photo.album_id}"
								data-src="\${photo.path}photos/\${photo.filename}"
								data-srcset="\${photo.path}photos/\${photo.filename} 1x, \${photo.path}photos2x/\${photo.filename} 2x"
								data-thumb="\${photo.path}thumbnails/\${photo.filename}"
								data-width="\${photo.renditions.photos.width}"
								href="\${photo.url}"
							>
								<img
									alt="\${photo.filename}"
									class="lazyload"
									src="\${photo.path}thumbnails/\${photo.filename}"
									srcset="\${photo.path}thumbnails/\${photo.filename} 1x, \${photo.path}thumbnails2x/\${photo.filename} 2x"
									height="\${photo.renditions.thumbnails.height}"
									title="\${photo.filename}"
									width="\${photo.renditions.thumbnails.width}"
								>
							</a>
							<figcaption>
								<div class="photo-caption">
									<p>\${photo.title}</p>
									<p></p>
								</div>
							</figcaption>
						</div>
					</figure>
				`);

				// create a function to update the view.
				// * pumps photos into the template, above;
				// * appends the images to the page.
				const updateAlbumView = (listEl, albumId) => {
					listEl.nextSibling.remove();

					const view = document.createElement("div");
					view.dataset.columns = "4";
					view.dataset.presentation = "grid";

					let output = "";
					Object.values(albums[albumId]).forEach(photo => {
						output += renderTemplate(photo);
					})
					view.innerHTML = output;
					listEl.insertAdjacentElement("afterend", view);
				}

				// create a `get` function to fetch album data by albumId.
				const getAlbum = (listEl, albumId) => {
					if (albums[albumId]) {
						updateAlbumView(listEl, albumId);
					} else {
						backlight.getAlbum(albumId, {
							apiToken: "{$apiToken}",
							done: data => {
								const { id, photos } = data.album;
								albums[id] = {};
								photos.forEach(photo => {
									albums[id][photo.id] = photo;
								});

								updateAlbumView(listEl, id);
							},
						});
					}
				}

				// keeps the tab list up-to-date
				const setSelectedIdOnList = (listEl, albumId) => {
					listEl.dataset.selected = albumId;
					return albumId;
				}

				// on page load, get and set first album
				const listElements = document.querySelectorAll(".tabs");
				for (const listEl of listElements) {
					const firstAlbumId = listEl.querySelector("[data-album]").dataset.album;
					setSelectedIdOnList(listEl, firstAlbumId);
					getAlbum(listEl, firstAlbumId);
				}

				// listen for clicks;
				// if click event occurs within `tabs` and yields an album ID, fetch album data.
				document.addEventListener("click", (event) => {
					const listEl = event.target.closest("ul.tabs");

					if (!listEl) return; // not clicking a tab; eject!

					const selectedId = setSelectedIdOnList(
						listEl,
						event.target.dataset.album,
					);

					for (const tab of listEl.children) {
						if (tab.dataset.album === selectedId) {
							tab.classList.add("selected");
						} else {
							tab.classList.remove("selected");
						}
					}

					getAlbum(listEl, selectedId);
				});
			</script>
HTML; // do not indent this line
			return false;
		} // END /**/

But should not be your problem :smiley:

try giving each tab it’s own ID. e.g id=“tab1”

Hi Rod,

thank you for your response.
With the following example it is not possible to add an album:

https://codepen.io/kallmanation/pen/YzwQBbp

Edit the section labeled “// on page load, get and set first album”.

Put the albumId in the URL, e.g.

https://volvoxturbo.com/page/?albumId=123456

Parse the ID using window.location. You’ll probably want to use your old friend the console log, and you may need to split the string to get the ID. Then update this value to use that ID:

const firstAlbumId = albumIdFromUrl || listEl.querySelector("[data-album]").dataset.album;

Thanks again Matthew!
I changed it like this:

	// on page load, get and set first album
				const listElements = document.querySelectorAll(".tabs");
				for (const listEl of listElements) {
					const firstAlbumId = albumIdFromUrl || listEl.querySelector("[data-album]").dataset.album;
					setSelectedIdOnList(listEl, firstAlbumId);
					getAlbum(listEl, firstAlbumId);
				}

then I searched for the albumID in Publisher and found: Shortcode: [album:698993]
I entered it to "https://oliver-blum.com/fototouren/?albumId=698993" and checked the console with window.location - no change. One thing, the above link shows the AlbumSet not the Album :thinking:

I entered "https://oliver-blum.com/fototouren/?albumId=698993" into:


<main>
  <section class="tab" id="third-tab">
    <nav>
      <a href="#first-tab">Linkable</a>
      <a href="#second-tab">Tabs</a>
      <a href="#third-tab" class="active">with only CSS</a>
    </nav>
    <p>text only 1.</p>
    <p>only text 2</p>

https://oliver-blum.com/fototouren/?albumId=698993

</section>
  <section class="tab" id="second-tab">
    <nav>
      <a href="#first-tab">Linkable</a>
      <a href="#second-tab" class="active">Tabs</a>
      <a href="#third-tab">with only CSS</a>
    </nav>
    <p>Maintains current tab through refreshes.</p>
  </section>
  <section class="tab" id="first-tab">
    <nav>
      <a href="#first-tab" class="active">Linkable</a>
      <a href="#second-tab">Tabs</a>
      <a href="#third-tab">with only CSS</a>
    </nav>
    <p>Built with only CSS.</p>
    <p>Using the :target selector.</p>
  </section>
</main>

but nothing happend. What did I wrong and what to do to make it work? :grimacing:

Best regards,
Oliver

Now that 5.3.0 is out, I need to revisit this.

With Kookaburra and the 5.3.0 update, this is should be easy:

<style>
   .tab-bar {
      background-color: black;
      color: white;
   }
   .tab {
      margin: 5px; 10px;
   }
   .tab:hover {
      color: orange;  
   }
</style>

<div class="tab-bar">
  <button class="tab" onclick="openCity('San Francisco')">San Francisco</button>
  <button class="tab" onclick="openCity('Paris')">Paris</button>
  <button class="tab" onclick="openCity('Venice')">Venice</button>
</div>

<div id="San Francisco" class="city">
  <h2>San Francisco</h2>
  <div data-albums="94160" data-presentation="grid" data-columns="4" data-images="94160_64087,94160_90854,94160_36499,94160_5959" data-group="san francisco"></div>
</div>

<div id="Paris" class="city" style="display:none">
  <h2>Paris</h2>
  <div data-albums="39218" data-presentation="grid" data-columns="4" data-images="39218_6646,39218_42549,39218_20853,39218_3136,39218_84033"></div>
</div>

<div id="Venice" class="city" style="display:none">
  <h2>Venice</h2>
  <div data-albums="99999" data-presentation="grid" data-columns="4" data-images="99999_91221,99999_61718,99999_82636,99999_67401"></div>
</div>

<script>
function openCity(cityName) {
  var i;
  var x = document.getElementsByClassName("city");
  for (i = 0; i < x.length; i++) {
    x[i].style.display = "none";
  }
  document.getElementById(cityName).style.display = "block";
}
</script>

I put the example up on Kookaburra Essay with tabbed galleries - Daniel Leu Photography

With the Kookaburra Essay builder (is this the name?), the embedded galleries are easy to create. Just select the album, presentation style etc and copy the code and paste it at the proper location.

1 Like

I’ve been calling it the Kookaburra essay presentation composer, but it’s a mouthful.

1 Like

Thank you Daniel,
it works good but I found out a tab solution where I can link to each tab.

Best regards,
Oliver

The objective was not the tab feature, but to show how you can add an album to the different tabs with the 5.3.0 release! Hope you noticed that!

This works with your code as well, but I didn’t had the CSS to have it fully functional.

Well, hopefully Pangolin won’t ever be superseded, because I have no desire to do coding, and I like being able to manage my albums and album sets from LR.

1 Like

@ttg-jim What’s happening in this thread is custom work. I assure you, you will never need to do any coding to utilize Backlight’s core features. We do offer a variety of options for folks to customize things under-the-hood, though – via custom CSS, PHPlugins, etc. – and that’s what this thread is about.

The goal is to eventually supersede Pangolin with Kookaburra, but you will always be able to work with it just as you are already accustomed to doing.

Oh good, thanks. Mild panic over!