Recent searches
No recent searches

Ashleigh Rentz
Joined Apr 16, 2021
·
Last activity Feb 24, 2022
Sr. Tech Writer at koresoftware.com
Following
0
Followers
0
Total activity
15
Votes
6
Subscriptions
4
ACTIVITY OVERVIEW
BADGES
ARTICLES
POSTS
COMMUNITY COMMENTS
ARTICLE COMMENTS
ACTIVITY OVERVIEW
Latest activity by Ashleigh Rentz
Ashleigh Rentz commented,
Hi Bruce - The line breaks are all intentional, JavaScript allows that and I wanted to keep it as human-readable as possible. But there's no reason not to change it, either. :)
I think you're right about this being a versioning issue—it looks like you're still on Templating API v1? I wrote this script based on Copenhagen 2.9.0 and Templating API v2, and I see that the 'pagination' helper was indeed updated between the two.
When inspecting my page, here's what the nav block looks like:
<nav class="pagination"> <ul class="pagination-list"> <li class="pagination-next"> <a href="/hc/en-us/sections/123456789012-Sample?page=2#articles" class="pagination-next-link" rel="next nofollow"> <span class="pagination-next-text">Nextspan> <span class="pagination-next-icon" aria-hidden="true">›span> a> li> <li class="pagination-last"> <a href="/hc/en-us/sections/123456789012-Sample?page=3#articles" class="pagination-last-link" rel="nofollow"> <span class="pagination-last-text">Lastspan> <span class="pagination-last-icon" aria-hidden="true">»span> a> li> ul> nav>
So my script failed on you because your 'pagination' helper doesn't assign a class to the link itself, only the list item. There might be other differences too, but it looks to me like you're on the right path for adapting this to the v1 API. Do you have it working?
View comment · Posted Dec 03, 2021 · Ashleigh Rentz
0
Followers
0
Votes
0
Comments
Ashleigh Rentz commented,
Hi Ifra Saqlain — This works with plain Copenhagen, no changes needed. :) I used a little CSS to put things on a single row just so the screenshot wouldn't be huge, but otherwise this is all from the JavaScript.
View comment · Posted Sep 16, 2021 · Ashleigh Rentz
0
Followers
0
Votes
0
Comments
Ashleigh Rentz created a post,
Hi again! I wanted to make some changes to our category pages.. there are several sections where Zendesk provides a "See all N articles" link when the full list is only 2 or 3 articles longer. I dislike getting shuffled off to another page just to see their titles. Even worse is when there's only 1 more article and it could have just been listed where the "See all..." link is! So let's change all that with some JavaScript. :-D
My help centre has one particularly enormous section, so there's also a size limit on this which you can change to suit your tastes. Depending on your CSS, it'll look something like this:
And here's the magic to add to your 'script.js' file:
// Zendesk Guide category pages with expandable listings
// author: Ashleigh Rentz, koresoftware.com
// license: https://mit-license.org/
window.onload = function() {
expandCategoryPage();
};
function expandCategoryPage() {
// Only execute this if we're on a category page.
if (document.getElementsByClassName("category-content")[0] == null) return;
const max_size_to_expand = 12; // Fall back to normal behaviour if larger.
const default_quantity = 6; // Zendesk default, unsure if it can be changed.
// Find the "See all N articles" links to (potentially) expand.
const see_all_array = document.getElementsByClassName("see-all-articles");
for (let i = 0; i < see_all_array.length; i++) {
var number_articles = see_all_array[i].innerText;
number_articles = parseInt(number_articles.match(/[0-9]+/));
if (number_articles <= max_size_to_expand) {
// Change text ASAP (\u25BC is unicode down-pointing triangle).
if ((number_articles - default_quantity) > 1) {
see_all_array[i].innerText = '\u25BC Show ' +
(number_articles - default_quantity) + ' more articles';
} else see_all_array[i].innerText = '';
expandThisSection(see_all_array[i]);
}
};
return;
async function expandThisSection(section_link_element) {
// Fetch the section page and create a list of
var section_page_response = await
fetch(section_link_element.getAttribute('href'));
var section_page_contents = new DOMParser().parseFromString(
await section_page_response.text(), 'text/html');
var article_list = section_page_contents.body.getElementsByClassName(
'article-list-item');
var articles_to_add = [];
for (let i = default_quantity; i < article_list.length; i++)
articles_to_add.push(article_list[i]);
// Get the
- for this section on the category page.
var list_element = section_link_element.previousElementSibling;
// Make sure it's the right thing, bail out if not.
if ((list_element.tagName !== 'UL') ||
(!(list_element.classList.contains('article-list')))) return;
// Insert the article(s).
if (articles_to_add.length == 1) {
// Insert the final article into the list, no expandable needed
list_element.append(articles_to_add[0]);
// Remove the 'see all' link.
section_link_element.remove();
} else {
// Insert more articles into the list as a hidden element in the DOM.
for (let i = 0; i < articles_to_add.length; i++) {
list_element.append(articles_to_add[i]);
list_element.lastElementChild.classList.add(
'collapsible-article-list-item');
list_element.lastElementChild.setAttribute('hidden', true);
};
// Change link action and assign a class for optional CSS styling.
section_link_element.classList.add('collapsible-article-list-control');
section_link_element.addEventListener('click',
function(){showMoreArticles(list_element, section_link_element)});
section_link_element.removeAttribute('href');
};
}; // end expandThisSection()
function showMoreArticles(list_element, section_link_element) {
for (let i = 0; i < list_element.children.length; i++) {
list_element.children[i].removeAttribute('hidden');
};
section_link_element.remove();
};
}; // end expandCategoryPage()
Again, I'm not a developer by trade, so there are probably ways to improve this. But it works great for me and I hope someone else out there finds it useful! :)
Posted Sep 15, 2021 · Ashleigh Rentz
1
Follower
5
Votes
9
Comments
Ashleigh Rentz commented,
My original post saved for posterity, but you're almost certainly better off using the revised version above.
---
If you haven't deviated from the base Copenhagen theme too much, the 'section_page.hbs' and 'category_page.hbs' files include SVG tags to draw the padlock and star icons. I didn't want to hard-code those into the script, so I removed them from the templates and uploaded them as separate files in the 'assets' folder. Now we can apply them via 'style.css'. I also display the non-paginated list in columns if the user's viewport is wide enough.
.article-promoted::after, .article-internal::after {
content: '';
background-size: 100% 100%;
display: inline-block;
height: 0.8em;
width: 0.8em;
padding-left: 1em;
}
.article-promoted::after {
background-image: url($assets-promoted-article-svg);
}
.article-internal::after {
background-image: url($assets-internal-article-svg);
}
@media (min-width: 768px) {
.long-article-list {
columns: 2;
}
}
@media (min-width: 1024px) {
.long-article-list {
columns: 3;
}
}
Next, we need a 'div' in 'section_page.hbs' that we can overwrite. Leave the pagination helper in place as a safe fallback.
{{! If more then 30 articles, JS should overwrite this div }}
{{#if section.articles}}
{{#each section.articles}}
{{title}}
{{/each}}
{{else}}
{{t 'empty'}}
{{/if}}
{{pagination "section.articles"}}
And finally, here's the Javascript:
// Zendesk Guide section pages without pagination.
// author: Ashleigh Rentz, koresoftware.com
// license: https://mit-license.org/
// Append to script.js
window.onload = function() {
unpaginatedSections();
};
function unpaginatedSections() {
// Only execute this if we're on a paginated section page.
if (document.getElementsByClassName("pagination")[0] == null) return;
const parsedUrlArray = parseSectionUrl(new URL(window.location.href));
if (parsedUrlArray == null) return;
// Define API URLs and parameters.
const hc_host = parsedUrlArray[0];
const hc_locale = parsedUrlArray[1];
const section_id = parsedUrlArray[2];
const per_page = 50; // Default 30. Higher means fewer XHRs but larger JSON
// objects; they contain the full body of each article.
const api_usersegs_url = 'https://' + hc_host + '/api/v2/help_center/user_segments';
const api_articles_url = 'https://' + hc_host + '/api/v2/help_center/' + hc_locale +
'/sections/' + section_id + '/articles?per_page=' + per_page;
// These vars need to be accessed from multiple function calls.
var long_list = '
- ';
var internalUserSegsArray = [];
// The 'articles' object doesn't tell us which ones are internal-only, so we
// need a list of 'staff' user segments to figure it out. Note that if you
// have over 100 user segments, this won't check all of them.
fetch(api_usersegs_url)
.then(function(response) {
if (response.status !== 200) throw new Error();
return response.json();
})
.then(
function(responseJson) {
for (let i=0; i < responseJson.count; i++) {
if (responseJson.user_segments[i].user_type == 'staff')
internalUserSegsArray.push(responseJson.user_segments[i].id);
};
}
)
.then(function() {
// Got the user segments list, now we can get the articles and
// create a new list.
var articles_json = new XMLHttpRequest();
articles_json.open("GET", api_articles_url);
articles_json.responseType = 'json';
articles_json.send();
articles_json.onload = function() {
// If request for articles failed, ignore and leave pagination in place.
if (articles_json.status !== 200) return;
// Add article titles and URLs to the new section page list.
long_list = long_list + addArticlesToList(articles_json.response['articles']);
if (articles_json.response.page < articles_json.response.page_count) {
// If those weren't all the articles, send another request which
// will call this same listener function again.
var next_url = articles_json.response.next_page;
articles_json.open("GET", next_url);
articles_json.send();
}
else {
// Close out the list and write it to the page.
long_list += '
document.getElementById("section-page-articles-list").innerHTML = long_list;
};
return;
};
})
.catch(function(e) { // API call for user segments failed;
}); // ignore and leave pagination in place.
function parseSectionUrl(sectionUrl) {
const urlArray = sectionUrl.pathname.toLowerCase().match(/\/hc\/.+?\/sections\/[0-9]+/);
if (urlArray !== null) {
// This is a section page.
const splitString = urlArray[0].split("/");
const locale = splitString[2];
const id = splitString[4].split("-")[0]; // Remove the text description
// after the ID, if present.
return [sectionUrl.hostname, locale, id];
} else return null; // This isn't a section page.
};
function addArticlesToList(articles_array) {
var list_markup = '';
for (let i=0; i < articles_array.length; i++) {
if (articles_array[i].draft) continue; // Don't add drafts to list.
list_markup += '
};
return list_markup;
};
};
I'm not a developer by trade so this could surely be improved, but hopefully it's useful to someone out there. Cheers!
View comment · Posted Sep 13, 2021 · Ashleigh Rentz
0
Followers
0
Votes
0
Comments
Ashleigh Rentz created a post,
Hi folks—I've benefited from various posts here, so let me try to pay it forward. :) By default, Zendesk Guide will only show 30 articles on a Section page and relies on pagination if you have more. I need to show all of a section's articles at once, so I put together some JS to do it.
Edited 2021-09-13:
Well don't I feel silly. I thought of a much simpler and efficient way to do this. :) Even better, now it works without modifying the basic Copenhagen 'section_page.hbs' template.
Additional 'style.css' rules recommended but not required:
@media (min-width: 768px) {
.long-article-list {
columns: 2;
}
}
@media (min-width: 1024px) {
.long-article-list {
columns: 3;
}
}
Append to 'script.js':
// Zendesk Guide section pages without pagination (v2).
// author: Ashleigh Rentz, koresoftware.com
// license: https://mit-license.org/
window.onload = function() {
unpaginatedSections();
};
function unpaginatedSections() {
// Only execute this if we're on a paginated section page.
if (document.getElementsByClassName("pagination")[0] == null) return;
// Does the URL specify a page number? If so, yield to the user.
if (document.URL.includes('?page=')) return;
// Start with the articles listed on the first page
var long_list = document.getElementsByClassName("article-list")[0].innerHTML;
var next_url = document.getElementsByClassName("pagination-next-link")[0]
.getAttribute('href');
var is_finished = false;
// Request the next page
var next_page = new XMLHttpRequest();
next_page.open("GET", next_url);
next_page.responseType = 'document';
next_page.send();
next_page.onload = function() {
// If something went wrong, leave pagination in place.
if (next_page.status !== 200) return;
// Add the articles from this page of results to our list.
long_list += next_page.response.getElementsByClassName("article-list")[0]
.innerHTML;
// Check for another page.
try {
next_url =
next_page.response.getElementsByClassName("pagination-next-link")[0]
.getAttribute('href');
next_page.open("GET", next_url);
next_page.send();
}
catch (e) {
// No more pages.
is_finished = true;
}
finally {
if (is_finished) {
// Write the new list to the current page.
document.getElementsByClassName("article-list")[0].innerHTML = long_list;
// Add a class to allow styling via CSS.
document.getElementsByClassName("article-list")[0].classList.add(
'long-article-list');
// Remove the pagination controls.
document.getElementsByClassName("pagination")[0].innerHTML = '';
};
};
};
};
I'll put the original (complicated and inefficient) version in a comment below for posterity, but you probably shouldn't use it. ;)
Posted Sep 09, 2021 · Ashleigh Rentz
0
Followers
4
Votes
6
Comments