Commit 0db0c8e9 authored by Chris Snijder's avatar Chris Snijder 🏅
Browse files

Initial commit.

parents
# Ignore bundler lock file
/Gemfile.lock
# Ignore pkg folder
/pkg
\ No newline at end of file
# If you do not have OpenSSL installed, update
# the following line to use "http://" instead
source 'https://rubygems.org'
# Specify your gem's dependencies in middleman-recursive-nav.gemspec
gemspec
group :development do
gem 'rake'
gem 'rdoc'
gem 'yard'
end
group :test do
gem 'cucumber'
gem 'aruba'
gem 'rspec'
end
require 'bundler'
Bundler::GemHelper.install_tasks
require 'cucumber/rake/task'
Cucumber::Rake::Task.new(:cucumber, 'Run features that should pass') do |t|
t.cucumber_opts = '--color --tags ~@wip --strict'
end
require 'rake/clean'
task test: ['cucumber']
task default: :test
PROJECT_ROOT_PATH = File.dirname(File.dirname(File.dirname(__FILE__)))
require 'middleman-core'
require 'middleman-core/step_definitions'
require File.join(PROJECT_ROOT_PATH, 'lib', 'middleman-recursive-nav')
require "middleman-core"
Middleman::Extensions.register :middleman_recursive_nav do
require "middleman-recursive-nav/extension"
RecursiveNav
end
# Require core library
require 'middleman-core'
# Extension namespace
class RecursiveNav < ::Middleman::Extension
# option :my_option, 'default', 'An example option'
def initialize(app, options_hash={}, &block)
# Call super to build options from the options_hash
super
end
#def after_configuration
#end
# A Sitemap Manipulator
# def manipulate_resource_list(resources)
# end
helpers do
# Return a list of links with translated versions of this page
#
#
def translation_links
links = {}
locales.select{|l| l != locale}.each do |loc|
# Blog seems to treat localisation way differently, so we have a different
# solutions for blog posts than for other pages.
if current_page.path.start_with? "blog"
# Check if same file exists in other language
if File.exists? current_page.source_file.sub("/#{locale}/", "/#{loc}/")
# Make a link to other language
links[loc] = link_to('this page',
'/' + current_page.path.sub("/#{locale}/", "/#{loc}/"))
end
else
path = current_page.target.sub("pages/", "").sub(/([\.\/])#{locale}([\.\/])/, "\\1#{loc}\\2")
link = extensions[:i18n].localized_path("/#{path}", loc)
if link
links[loc] = link_to('this page', link)
end
end
end
links
end
class NavNode
attr_reader :type
attr_accessor :children
attr_reader :data
attr_reader :weight
attr_reader :title
attr_reader :path
attr_reader :page_id
attr_reader :url
def initialize(path, page_id)
@type = :node
@children = nil
@data = Middleman::Util::EnhancedHash.new
if meta = _meta_file(path)
@data = meta
end
@weight = meta&.nav&.weight || 99999
@title = meta&.nav&.title || meta&.title || File.basename(path).capitalize
@path = path
@page_id = page_id
@url = nil
end
def is_index?
return @page_id == 'index' || @page_id.end_with?('/index')
end
private
def _meta_file(path)
meta_file = File.join path, "_meta.y{ml,aml}"
if (files = Dir.glob(meta_file)).length > 0
puts "== File(s) \"#{files.join(", ")}\" exist(s)."
else
puts "== File \"#{meta_file}\" does not exist."
return nil
end
files.each do |f|
begin
return Middleman::Util::EnhancedHash.new(YAML.load_file f)
rescue IOError => e
puts "== Can't read \"#{f}\", reason: #{e}"
end
end
return nil
end
end
class NavNodeResource < NavNode
attr_reader :type
attr_accessor :children
attr_reader :data
attr_reader :weight
attr_reader :title
attr_reader :path
attr_reader :page_id
attr_reader :url
attr_reader :locale
attr_reader :nav
attr_reader :nav_title
attr_reader :resource
attr_reader :page_id
def initialize(resource)
@type = resource.metadata[:resource_type]
@children = nil
@data = Middleman::Util::EnhancedHash.new
if meta = _meta_file(File.dirname(resource.source_file))
@data = meta
end
@data.deep_merge!(resource.data)
@weight = @data&.nav&.weight || 99999
@title = @data.title
@path = File.dirname(
resource.source_file.sub(/^#{__dir__}\/source\//, '')
)
@page_id = resource.page_id
@url = resource.url
@locale = resource.options[:locale]
@nav = resource.data&.nav || Middleman::Util::EnhancedHash.new
@nav_title = @data&.nav&.title || @data&.title || resource.title
@resource = resource
end
end
def _recurse_nav(resources, start, max_levels)
nodes = []
# Get all page_id's of index files
indexes = resources.select {|r| r.page_id.end_with? "index"}
indexes.map! {|r| File.dirname(r.page_id)}
# Intersect arrays to find paths with no index
no_index_res = resources.reject {|r| indexes.include? File.dirname(r.page_id) }
no_index_res.map! {|r| [File.dirname(r.source_file), r.page_id]}
# Recursively find directories without indexes
no_index_deep = []
no_index_res.uniq.each do |path, page_id|
page_id = File.dirname(page_id)
page_id_split = page_id.split('/')
# Check from deepest to shallowest level
(page_id_split.length-1).downto(0) do |i|
sub_id = page_id_split[0..i].join("/")
sub_path = path.split('/')
sub_path = sub_path[0..sub_path.length-i].join('/')
if not indexes.include? sub_id
no_index_deep << [sub_path, sub_id]
end
end
end
no_index_deep.uniq.each do |path, page_id|
# Directory only nodes, i.e. no [title.html] nor directory/index.html
nodes << NavNode.new(path, "#{page_id}/index")
end
# Normal resources that represent pages
resources.each do |r|
nodes << NavNodeResource.new(r)
end
# All resources and empty paths converted to NavNodes and NavNodeResource
# NavNodes are orphaned so we need to recreate parent child structure from
# paths
node_index = nodes.map { |n| [n.page_id, {:node => n}] }.to_h
# Limit node levels to max_levels
node_index.select! {|page_id, data|
if data[:node].is_index?
# Indexes are physically saved *under* the dir, so one more level is
# allowed here.
page_id.count('/') <= max_levels
else
page_id.count('/') <= max_levels - 1
end
}
node_index.each do |page_id, data|
parent = File.dirname(page_id)
if data[:node].is_index?
# Index pages belong one level higher..
parent = File.dirname(parent)
end
data[:parent] = parent == "." ? "index" : parent
end
def _recurse_children(node_index, parent)
# Select items with passed parent as a parent
level_nodes = node_index.select {|page_id, data| data[:parent] == parent}
nodes = []
# Add all nodes to the curren level.
nodes = level_nodes.map do |page_id, data|
# And also recurse over their children by their path
node = data[:node]
new_parent = File.dirname(page_id)
unless new_parent == parent
children = _recurse_children(node_index, new_parent)
if children.length > 0
node.children = children
end
end
node
end
nodes.sort_by! {|n| n.weight}
end
tree = _recurse_children node_index, start
def traverse_tree(tree, level)
for node in tree
puts "#{'##' * level} #{node.page_id}"
if node.children
traverse_tree node.children, level+1
end
end
end
traverse_tree(tree, 1)
tree
end
##
# Return part of the sitemap that can be used as navigation
# @param locale str Locale you want for your navigation by default whatever
# is mounted at root
# @param node str From where in the navigation tree you want to start
# @returns array sitemap.resources subset
def generate_nav locale, max_levels=10, start="index"
# We need only links to HTML pages
res = sitemap.resources.find_all {|r| r.ext == ".html"}
# Select only resources tagged with a resource type of :page
res.select! {|r| r.metadata[:resource_type]&.include? :page}
# Filter out what is in the currently selected locale
res.select! {|r| r.options[:locale] == locale}
# Only get resources that are within the `start` path,
# e.g. if `start`=="products" only return everything *under* products.
if start != "index"
res.select! do |r|
r.page_id.start_with?(start) &&
r.page_id.sub!(/^#{start}/, '').length > 0
end
end
_recurse_nav res, start, max_levels
end
end
end
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
Gem::Specification.new do |s|
s.name = "middleman-recursive-nav"
s.version = "0.0.1"
s.platform = Gem::Platform::RUBY
# s.authors = ["Your Name"]
# s.email = ["email@example.com"]
# s.homepage = "http://example.com"
# s.summary = %q{A short summary of your extension}
# s.description = %q{A longer description of your extension}
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
# The version of middleman-core your extension depends on
s.add_runtime_dependency("middleman-core", [">= 4.2.1"])
# Additional dependencies
# s.add_runtime_dependency("gem-name", "gem-version")
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment