app/javascript/alchemy_admin/sitemap.js
// The admin sitemap Alchemy class
import PageSorter from "alchemy_admin/page_sorter"
import { on } from "alchemy_admin/utils/events"
import { get, patch } from "alchemy_admin/utils/ajax"
import { growl } from "alchemy_admin/growler"
import { createSortables, displayPageFolders } from "alchemy_admin/page_sorter"
export default class Sitemap {
// Storing some objects.
constructor(options) {
const list_template_html = document
.getElementById("sitemap-list")
.innerHTML.replace(/__ID__/g, "{{id}}")
this.search_field = document.querySelector(".search_input_field")
this.filter_field_clear = document.querySelector(".search_field_clear")
this.filter_field_clear.removeAttribute("href")
this.display = document.getElementById("page_filter_result")
this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
this.template = Handlebars.compile(
document.getElementById("sitemap-template").innerHTML
)
this.list_template = Handlebars.compile(list_template_html)
this.items = null
this.options = options
Handlebars.registerPartial("list", list_template_html)
this.load(options.page_root_id)
}
// Loads the sitemap
load(pageId) {
const spinner = new Alchemy.Spinner("medium")
const spinTarget = this.sitemap_wrapper
spinTarget.innerHTML = ""
spinner.spin(spinTarget)
get(this.options.url, { id: pageId })
.then(async (response) => {
this.render(await response.data)
this.handlePageFolders()
spinner.stop()
})
.catch(this.errorHandler)
}
// Reloads the sitemap
reload() {
this.load(this.options.page_root_id)
}
// Watch page folder clicks and re-render the page branch
handlePageFolders() {
on(
"click",
"#sitemap",
".page_folder",
function (evt) {
const spinner = new Alchemy.Spinner("small")
const pageFolder = evt.target.closest(".page_folder")
const pageId = pageFolder.dataset.pageId
pageFolder.innerHTML = ""
spinner.spin(pageFolder)
patch(Alchemy.routes.fold_admin_page_path(pageId))
.then(async (response) => {
this.reRender(pageId, await response.data)
spinner.stop()
})
.catch(this.errorHandler)
}.bind(this)
)
}
// Renders the sitemap
render(data) {
const renderTarget = this.sitemap_wrapper
const renderTemplate = this.template
renderTarget.innerHTML = renderTemplate({ children: data.pages })
this.items = document
.getElementById("sitemap")
.querySelectorAll(".sitemap_page")
this.sitemap_wrapper = document.getElementById("sitemap-wrapper")
this._observe()
PageSorter()
}
reRender(pageId, data) {
let pageEl = document.getElementById(`page_${pageId}`)
pageEl.outerHTML = this.list_template({ children: data.pages })
pageEl = document.getElementById(`page_${pageId}`)
const sortables = pageEl.querySelectorAll("ul.children")
createSortables(sortables)
displayPageFolders()
}
// Filters the sitemap
filter(term) {
const results = []
this.items.forEach(function (item) {
if (
term !== "" &&
item.getAttribute("name").toLowerCase().indexOf(term) !== -1
) {
item.classList.add("highlight")
item.classList.remove("no-match")
results.push(item)
} else {
item.classList.add("no-match")
item.classList.remove("highlight")
}
})
const { length } = results
if (length === 1) {
this.display.style.display = "block"
this.display.innerText = `1 ${Alchemy.t("page_found")}`
results[0].scrollIntoView({ behavior: "smooth", block: "center" })
} else if (length > 1) {
this.display.style.display = "block"
this.display.innerText = `${length} ${Alchemy.t("pages_found")}`
} else {
this.items.forEach((item) =>
item.classList.remove("no-match", "highlight")
)
this.display.style.display = "none"
window.scrollTo({
top: 0,
left: 0,
behavior: "smooth"
})
}
}
// Adds onkey up observer to search field
_observe() {
this.search_field.addEventListener("keyup", (evt) => {
const term = evt.target.value
this.filter_field_clear.style.visibility =
term == "" ? "hidden" : "visible"
this.filter(term.toLowerCase())
})
this.search_field.addEventListener("focus", () => key.setScope("search"))
this.filter_field_clear.addEventListener("click", () => {
this.search_field.value = ""
this.filter("")
return false
})
}
errorHandler(error) {
growl(error.message || error, "error")
console.error(error)
}
}