local path = require 'pandoc.path' local utils = require 'pandoc.utils' local common = require 'scripts.lib.common' local sort = require 'scripts.lib.sort' function resolve_url(site_url, ref_file, target_file) local ref_base_dir = path.directory(ref_file) local abs = target_file:gsub("/index%.html$", "/") local rel = path.make_relative(abs, ref_base_dir, true) local full = (abs:sub(1, 1) == "/" and (site_url .. abs)) or abs return { abs = abs, rel = rel, full = full } end function prep_menu(namespace, main_menu) namespace = utils.stringify(namespace) local active_item = nil local items = pandoc.List() for i = 1, #main_menu do local item = main_menu[i] for j = 1, #item.match do if active_item then break end item.active = not not namespace:match(utils.stringify(item.match[j])) if item.active then active_item = item end end if not item.hidden or item.active then items:insert(item) end end return { items = items, active = active_item } end function d1_page_to_list_item(meta) return { title = meta.title, subtitle = meta.subtitle, date = meta.date, last_update = meta.last_update, show_date = meta.show_date, schema_type = meta.schema_type, draft = meta.draft, position = meta.position, url = meta.url, rel = meta.rel, slug = meta.slug, thumbnail = meta.thumbnail, icon = meta.icon, post_icon = meta.post_icon, indicator = meta.indicator, } end function d2_page_to_list_item(meta, unlisted, with_category) return { title = meta.title, subtitle = meta.subtitle, category = with_category and meta.category, date = meta.date, last_update = meta.last_update, show_date = meta.show_date, schema_type = meta.schema_type, draft = meta.draft, position = meta.position, url = meta.url, rel = meta.rel, slug = meta.slug, thumbnail = meta.thumbnail, icon = meta.icon, post_icon = meta.post_icon, indicator = meta.indicator, unlisted = unlisted } end function cat_to_list_cat(meta, allItems) local limit = meta.list_limit or 9999 local items = allItems:filter(function (item) return not item.unlisted end):take(limit) local omitted = #allItems - #items local description = nil if meta.description then description = pandoc.Para(meta.description) elseif not meta.no_description then description = meta.content end return { title = meta.title, description = description, last_update = meta.last_update, schema_type = meta.schema_type, url = meta.url, slug = meta.slug, layout = meta.list_layout, items = items, total = tostring(#allItems), omitted = omitted ~= 0 and tostring(omitted), } end function generate_list(meta) if meta.depth < 1 then return pandoc.List() end if meta.depth == 1 then return meta.pages.all:map(function (p) return d1_page_to_list_item(p) end) end if meta.depth == 2 then return meta.pages.all :map(function(cat) local allItems = cat.pages.all:map(function(p) return d2_page_to_list_item(p, false, false) end) return cat_to_list_cat(cat, allItems) end) :filter(function(cat) return #cat.items ~= 0 end) end if meta.depth == 3 then local list = meta.pages.all :map(function(cat) local allItems = cat.pages.all:flatMap(function(c) if cat.list_flatten and c.depth ~= 0 then return c.pages.all:map(function(p) return d2_page_to_list_item(p, c.list_no_propagate, true) end) else return pandoc.List({ d1_page_to_list_item(c) }) end end) allItems:sort(sort.page_sort(cat.list_order)) return cat_to_list_cat(cat, allItems) end) :filter(function(cat) return #cat.items ~= 0 end) return list end end function deref_page(pages) return function(ref) return pages[utils.stringify(ref)] end end function generate_related(meta) if not meta.parent then return nil end local deref = deref_page(meta.parent.pages.by_id) meta.prev = meta.prev and d1_page_to_list_item(deref(meta.prev)) meta.next = meta.next and d1_page_to_list_item(deref(meta.next)) if meta.prev then meta.prev.is_prev = true end if meta.next then meta.next.is_next = true end if not meta.prev and not meta.next then return nil end local layout local layout_id = utils.stringify(meta.parent.list_layout.id) if layout_id == "gallery-2" or layout_id == "gallery-3" then layout = common.prep_layout("gallery-2") else layout = common.prep_layout("grid-2") end return { url = meta.parent.url, layout = layout, prev = meta.prev, next = meta.next } end function process_pages(meta) local deref = deref_page(meta.pages.by_id) meta.pages.all = meta.pages.all:filterMap(deref) meta.pages.date_desc = meta.pages.date_desc:filterMap(deref) end function resolve_urls(global, build, meta) meta.url = resolve_url(global.site.url, build.file_out, meta.url) if meta.feed then if meta.file_out:match(".html$") then meta.feed = { url = resolve_url(global.site.url, build.file_out, meta.file_out:gsub(".html$", ".xml")), } else meta.page = { url = resolve_url(global.site.url, build.file_out, meta.file_out:gsub(".xml$", ".html")), } end end if meta.thumbnail then meta.thumbnail = resolve_url(global.site.url, build.file_out, meta.thumbnail) end end function process_base(meta) meta.id = utils.stringify(meta.id) meta.depth = tonumber(utils.stringify(meta.depth)) meta.file_out = utils.stringify(meta.file_out) meta.url = utils.stringify(meta.url) meta.title = utils.stringify(meta.title) meta.list_limit = meta.list_limit and tonumber(utils.stringify(meta.list_limit)) meta.list_order = meta.list_order and utils.stringify(meta.list_order) meta.position = meta.position and tonumber(utils.stringify(meta.position)) meta.thumbnail = meta.thumbnail and utils.stringify(meta.thumbnail) meta.prev = meta.prev and utils.stringify(meta.prev) meta.next = meta.next and utils.stringify(meta.next) meta.content = meta.content:filter(function (el) return el.tag ~= "LineBreak" end) end function process(global, build, meta, dir) process_base(meta) resolve_urls(global, build, meta) for _, p in pairs(meta.pages.by_id) do p.parent = meta process(global, build, p, 1) p.parent = nil end process_pages(meta) if dir <= 0 and meta.parent then process(global, build, meta.parent, -1) end end function prune_pages(meta, up, down) meta.pages.by_id = {} if down == 0 then meta.pages.all = pandoc.List() meta.pages.date_desc = pandoc.List() else for _, p in pairs(meta.pages.by_id) do prune(p, up, down - 1) end end end function prune(meta, up, down) prune_pages(meta, up, down) if up == 0 then meta.parent = nil elseif meta.parent then prune(meta.parent, up - 1, down) end end function Meta(meta) local build = {} for key, value in pairs(meta) do local suffix = key:match('^build.(.*)$') if suffix then build[suffix] = value meta[key] = nil end end local global = { assets = meta.assets, site = meta.site, menus = meta.menus } global.site.url = utils.stringify(global.site.url) meta = meta.tree local parts = build.namespace:split('/'):skip(1) for i = 1, #parts do local part = parts[i] local p = meta.pages.by_id[part] meta.pages.by_id[part] = nil p.parent = meta meta = p end process(global, build, meta, 0) meta.list = generate_list(meta) meta.related = generate_related(meta) if global.menus and global.menus.main then global.menus.main = prep_menu(meta.namespace.full, global.menus.main) end prune(meta, 0, 2) for key, value in pairs(global) do meta[key] = value end meta.build = build return meta end