seiten 0.0.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. checksums.yaml +5 -5
  2. data/Rakefile +1 -0
  3. data/app/controllers/seiten/pages_controller.rb +2 -23
  4. data/config/initializers/seiten.rb +1 -1
  5. data/lib/seiten/errors/base_error.rb +4 -0
  6. data/lib/seiten/errors/page_error.rb +4 -0
  7. data/lib/seiten/errors/routing_error.rb +4 -0
  8. data/lib/seiten/helpers/backend.rb +23 -0
  9. data/lib/seiten/helpers/current.rb +33 -0
  10. data/lib/seiten/helpers/frontend.rb +19 -0
  11. data/lib/seiten/html/breadcrumb.rb +41 -0
  12. data/lib/seiten/html/helpers.rb +32 -0
  13. data/lib/seiten/html/navigation.rb +39 -0
  14. data/lib/seiten/navigation.rb +43 -0
  15. data/lib/seiten/page.rb +82 -40
  16. data/lib/seiten/page_collection.rb +54 -0
  17. data/lib/seiten/page_collection_builder.rb +63 -0
  18. data/lib/seiten/railtie.rb +7 -0
  19. data/lib/seiten/routes_helper.rb +16 -11
  20. data/lib/seiten/slug_builder.rb +32 -0
  21. data/lib/seiten/version.rb +1 -1
  22. data/lib/seiten.rb +63 -12
  23. data/test/controllers/helper_methods_test.rb +25 -0
  24. data/test/controllers/pages_controller_test.rb +9 -0
  25. data/test/controllers/posts_controller_test.rb +12 -0
  26. data/test/controllers/seiten/pages_controller_test.rb +39 -0
  27. data/test/dummy/app/controllers/application_controller.rb +10 -0
  28. data/test/dummy/app/controllers/pages_controller.rb +1 -1
  29. data/test/dummy/app/controllers/posts_controller.rb +10 -0
  30. data/test/dummy/app/helpers/application_helper.rb +1 -0
  31. data/test/dummy/app/pages/{de → application/de}/produkte.html.erb +0 -0
  32. data/test/dummy/app/pages/{en/about/our-team/switzerland.html.erb → application/en/about/our-team/italy.html.erb} +0 -0
  33. data/test/dummy/app/pages/{en/about/works.html.erb → application/en/about/our-team/switzerland.html.erb} +0 -0
  34. data/test/dummy/app/pages/application/en/about/our-team.html.erb +2 -0
  35. data/test/dummy/app/pages/application/en/about/partners.html.erb +1 -0
  36. data/test/dummy/app/pages/{en/contact.html.erb → application/en/about/works.html.erb} +0 -0
  37. data/test/dummy/app/pages/{en/about/our-team/italy.html.erb → application/en/about.html.erb} +0 -0
  38. data/test/dummy/app/pages/{en/products/logo-design.html.erb → application/en/contact.html.erb} +0 -0
  39. data/test/dummy/app/pages/{en → application/en}/home.html.erb +0 -0
  40. data/test/dummy/app/pages/{en/products/web-development.html.erb → application/en/products/hire-us.html.erb} +0 -0
  41. data/test/dummy/{db/test.sqlite3 → app/pages/application/en/products/logo-design.html.erb} +0 -0
  42. data/test/dummy/app/pages/application/en/products/web-development.html.erb +0 -0
  43. data/test/dummy/app/pages/{en → application/en}/products.html.erb +0 -0
  44. data/test/dummy/app/pages/{localization.html.erb → application/localization.html.erb} +0 -0
  45. data/test/dummy/app/pages/help/en/home.html.erb +0 -0
  46. data/test/dummy/app/pages/help/en/logging-in.html.erb +0 -0
  47. data/test/dummy/app/views/layouts/application.html.erb +1 -1
  48. data/test/dummy/app/views/layouts/home.html.erb +1 -1
  49. data/test/dummy/app/views/pages/secret.html.erb +1 -1
  50. data/test/dummy/app/views/posts/index.html.erb +1 -0
  51. data/test/dummy/config/application.rb +4 -41
  52. data/test/dummy/config/boot.rb +2 -9
  53. data/test/dummy/config/cable.yml +9 -0
  54. data/test/dummy/config/environments/development.rb +26 -21
  55. data/test/dummy/config/environments/production.rb +3 -0
  56. data/test/dummy/config/environments/test.rb +15 -19
  57. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  58. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  59. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  60. data/test/dummy/config/initializers/inflections.rb +6 -5
  61. data/test/dummy/config/initializers/mime_types.rb +0 -1
  62. data/test/dummy/config/initializers/new_framework_defaults.rb +20 -0
  63. data/test/dummy/config/initializers/session_store.rb +1 -6
  64. data/test/dummy/config/initializers/wrap_parameters.rb +5 -5
  65. data/test/dummy/config/{navigation/de.yml → navigations/application.de.yml} +5 -5
  66. data/test/dummy/config/{navigation.yml → navigations/application.en.yml} +21 -5
  67. data/test/dummy/config/navigations/help.en.yml +17 -0
  68. data/test/dummy/config/routes.rb +6 -3
  69. data/test/dummy/config/secrets.yml +22 -0
  70. data/test/dummy/log/development.log +1632 -8652
  71. data/test/dummy/log/test.log +43833 -13664
  72. data/test/fixtures/breadcrumb.html +1 -0
  73. data/test/fixtures/navigation.html +1 -0
  74. data/test/integration/layout_test.rb +10 -11
  75. data/test/integration/navigation_test.rb +50 -50
  76. data/test/lib/seiten/helpers/frontend_test.rb +37 -0
  77. data/test/lib/seiten/html/breadcrumb_test.rb +29 -0
  78. data/test/lib/seiten/html/helpers_test.rb +55 -0
  79. data/test/lib/seiten/html/navigation_test.rb +29 -0
  80. data/test/lib/seiten/navigation_test.rb +45 -0
  81. data/test/lib/seiten/page_collection_builder_test.rb +141 -0
  82. data/test/lib/seiten/page_collection_test.rb +59 -0
  83. data/test/lib/seiten/page_test.rb +188 -0
  84. data/test/lib/seiten/slug_builder_test.rb +47 -0
  85. data/test/lib/seiten_test.rb +16 -0
  86. data/test/test_helper.rb +2 -8
  87. metadata +136 -94
  88. data/app/helpers/seiten_helper.rb +0 -46
  89. data/lib/seiten/controllers/helpers.rb +0 -16
  90. data/lib/seiten/page_store.rb +0 -150
  91. data/test/dummy/app/assets/javascripts/application.js +0 -15
  92. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  93. data/test/dummy/app/pages/en/about/our-team.html.erb +0 -2
  94. data/test/dummy/app/pages/en/about/partners.html.erb +0 -1
  95. data/test/dummy/config/navigation/en.yml +0 -37
  96. data/test/dummy/db/development.sqlite3 +0 -0
  97. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  98. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  99. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  100. data/test/dummy/tmp/pids/server.pid +0 -1
  101. data/test/integration/i18n_test.rb +0 -37
  102. data/test/integration/redirect_test.rb +0 -15
  103. data/test/page_test.rb +0 -74
  104. data/test/seiten_test.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c07bb134e2faeb0ba5dd11af57a067fef28ceeb2
4
- data.tar.gz: 94f0e43ea9839d4bf1598ef7c63e0c8bb39a590a
2
+ SHA256:
3
+ metadata.gz: 3e17a2fa52d374492d7a6598c5e88c4d81935b091158a60bb14d298fd83469be
4
+ data.tar.gz: 4cb163a2fc0399bd5ab1267790907c6fb356f7d55996dd9b08c6a90c0a51166f
5
5
  SHA512:
6
- metadata.gz: 341550a0f7cdd4b7e6a9a01b685c70796b6ec8007b13256482c5a028c95e0ada6d42e164994926c5cf4307d819d085944c10874e3e91ca2c9de95e10ef8defb6
7
- data.tar.gz: 6657f6f1f45308fcab547c3dff423355c8ac887a154178a545230647829a824ace2361d921c3d94e6739288fe3a99a52a4b9f36d8ad586ebddd9f498b913bcbf
6
+ metadata.gz: 6d2e231683fa2bb4f8158211d8ab0b22f32093948792dce08e6dcff3011959deeaa61fc18d434a8dd73100b9e458dcb272a84c65fdd34d2c609b5442a03da8f9
7
+ data.tar.gz: a3f7f85d5196780920a259229c960d524176c127c102990c313ab161cdeb020f0f390e4a6130011528656562220f1ab5b34268507cf1ac9446c8602ade8bd281
data/Rakefile CHANGED
@@ -26,6 +26,7 @@ Rake::TestTask.new(:test) do |t|
26
26
  t.libs << 'test'
27
27
  t.pattern = 'test/**/*_test.rb'
28
28
  t.verbose = false
29
+ t.warning = false
29
30
  end
30
31
 
31
32
 
@@ -1,30 +1,9 @@
1
1
  module Seiten
2
2
  class PagesController < ::ApplicationController
3
+ include Seiten::Helpers::Backend
3
4
 
4
5
  def show
5
- if current_page.nil?
6
- raise ActionController::RoutingError.new("Page /#{params[:page]} not found")
7
- else
8
- @title = current_page.title
9
-
10
- if params[:page]
11
- filename = params[:page]
12
- else
13
- filename = Seiten.config[:root_page_filename]
14
- end
15
-
16
- if File.exists? Seiten::PageStore.current.file_path(filename: "#{filename}.html.erb", locale: I18n.locale)
17
- file = Seiten::PageStore.current.file_path(filename: filename, locale: I18n.locale)
18
- else
19
- file = Seiten::PageStore.current.file_path(filename: filename)
20
- end
21
-
22
- if current_page.layout
23
- render file: file, layout: current_page.layout
24
- else
25
- render file: file
26
- end
27
- end
6
+ render_seiten_page
28
7
  end
29
8
  end
30
9
  end
@@ -1 +1 @@
1
- Seiten::PageStore.initialize_page_stores
1
+ Seiten.initialize_navigations
@@ -0,0 +1,4 @@
1
+ module Seiten::Errors
2
+ class BaseError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Seiten::Errors
2
+ class PageError < BaseError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Seiten::Errors
2
+ class RoutingError < BaseError
3
+ end
4
+ end
@@ -0,0 +1,23 @@
1
+ module Seiten
2
+ module Helpers
3
+ # Those helpers are convenience methods added to Seiten::PagesController or useful for building your own.
4
+ module Backend
5
+ extend ActiveSupport::Concern
6
+
7
+ def self.included(base)
8
+ base.prepend_view_path Seiten.config[:pages_dir]
9
+ base.before_action :raise_seiten_routing_error, unless: :current_page
10
+ end
11
+
12
+ private
13
+
14
+ def raise_seiten_routing_error
15
+ raise Seiten::Errors::RoutingError.new("Page /#{params[:slug]} not found")
16
+ end
17
+
18
+ def render_seiten_page
19
+ render current_page.template_path, layout: current_page.layout
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ module Seiten
2
+ module Helpers
3
+ # Those helpers are convenience methods added to ApplicationController.
4
+ module Current
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ if respond_to?(:helper_method)
9
+ helper_method :current_navigation
10
+ helper_method :current_page
11
+ end
12
+ end
13
+
14
+ def current_navigation
15
+ @current_navigation ||= set_current_navigation
16
+ end
17
+
18
+ def current_page
19
+ @current_page ||= set_current_page
20
+ end
21
+
22
+ private
23
+
24
+ def set_current_navigation
25
+ Seiten::Navigation.find_by(name: params[:navigation_id] || 'application', locale: params[:locale] || I18n.locale.to_s)
26
+ end
27
+
28
+ def set_current_page
29
+ current_navigation&.pages&.find_by(slug: params[:slug]) if params[:slug]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seiten
4
+ module Helpers
5
+ module Frontend
6
+ def link_to_seiten_page(page)
7
+ link_to page.title, page.path
8
+ end
9
+
10
+ def seiten_navigation(navigation = current_navigation, parent_id: nil, deep: 2, html: {})
11
+ Seiten::HTML::Navigation.new(self, navigation: navigation, parent_id: parent_id, current_page: current_page, deep: deep, html: html).body
12
+ end
13
+
14
+ def seiten_breadcrumb(separator: '>', html: {})
15
+ Seiten::HTML::Breadcrumb.new(self, page: current_page, separator: separator, html: html).body
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ module Seiten
2
+ module HTML
3
+ class Breadcrumb
4
+ attr_reader :body
5
+
6
+ def initialize(view_context, page:, separator: '>', html: {})
7
+ @view_context = view_context
8
+ @current_page = page
9
+ @separator = separator
10
+ @html_options = Seiten.config[:html].deep_merge(html || {})
11
+ @body = build_navigation if @current_page
12
+ end
13
+
14
+ private
15
+
16
+ def build_navigation
17
+ classes = Seiten::HTML::Helpers.build_classes(class_options: @html_options[:breadcrumb], modifier_options: @html_options[:modifier])
18
+ @view_context.content_tag(:ul, class: classes) do
19
+ pages = @current_page.breadcrumbs.each_with_index.map do |page, index|
20
+ build_page_element(page, index)
21
+ end
22
+ @view_context.safe_join(pages)
23
+ end
24
+ end
25
+
26
+ def build_page_element(page, index)
27
+ modifiers = page == @current_page ? [:current] : []
28
+ classes = Seiten::HTML::Helpers.build_classes(:item, modifiers: modifiers, class_options: @html_options[:breadcrumb], modifier_options: @html_options[:modifier])
29
+
30
+ @view_context.content_tag :li, class: classes do
31
+ if @separator && index.positive?
32
+ sep_class = Seiten::HTML::Helpers.build_classes(:separator, class_options: @html_options[:breadcrumb])
33
+ span = @view_context.content_tag(:span, @separator, class: sep_class)
34
+ end
35
+ link = @view_context.link_to_seiten_page(page)
36
+ @view_context.safe_join([span, link])
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ module Seiten
2
+ module HTML
3
+ module Helpers
4
+ def self.build_page_modifiers(page, current_page)
5
+ modifiers = []
6
+ modifiers << :parent if page.children?
7
+ if page.active?(current_page)
8
+ modifiers << :active
9
+ modifiers << (page == current_page ? :current : :expanded)
10
+ end
11
+ modifiers
12
+ end
13
+
14
+ def self.build_classes(element = nil, class_options:, modifier_options: [], modifiers: [], merge: nil)
15
+ classes = []
16
+
17
+ klass = class_options[element || :base]
18
+ classes << klass
19
+
20
+ if modifiers.any?
21
+ base = (modifier_options[:base].presence || klass)
22
+ modifiers.each do |modifier|
23
+ classes << "#{base}#{modifier_options[:separator]}#{modifier_options[modifier]}"
24
+ end
25
+ end
26
+
27
+ classes << merge if merge
28
+ classes.join(' ')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ module Seiten
2
+ module HTML
3
+ class Navigation
4
+ attr_reader :body
5
+
6
+ def initialize(view_context, navigation:, parent_id: nil, current_page: nil, deep: 2, html: {})
7
+ @view_context = view_context
8
+ @start_depth = deep
9
+ @html_options = Seiten.config[:html].deep_merge(html || {})
10
+ @current_page = current_page
11
+ @body = build_navigation(navigation, parent_id: parent_id, deep: deep)
12
+ end
13
+
14
+ private
15
+
16
+ def build_navigation(navigation, parent_id:, deep:)
17
+ wrapper_class = @start_depth != deep ? :nodes : nil
18
+
19
+ return unless deep.positive?
20
+
21
+ @view_context.content_tag(:ul, class: Seiten::HTML::Helpers.build_classes(wrapper_class, class_options: @html_options[:navigation], modifier_options: @html_options[:modifier])) do
22
+ pages = navigation.pages.where(parent_id: parent_id).map do |page|
23
+ children = build_navigation(navigation, parent_id: page.id, deep: deep - 1) if page.children?
24
+ build_page_element(page, children)
25
+ end
26
+ @view_context.safe_join(pages)
27
+ end
28
+ end
29
+
30
+ def build_page_element(page, children)
31
+ modifiers = Seiten::HTML::Helpers.build_page_modifiers(page, @current_page)
32
+ classes = Seiten::HTML::Helpers.build_classes(:item, modifiers: modifiers, merge: page.html_options[:class], class_options: @html_options[:navigation], modifier_options: @html_options[:modifier])
33
+ @view_context.content_tag(:li, page.html_options.merge(class: classes)) do
34
+ @view_context.safe_join([@view_context.link_to_seiten_page(page), children])
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ module Seiten
2
+ class Navigation
3
+ attr_accessor :name, :locale, :config, :dir, :page_collection
4
+
5
+ def initialize(options={})
6
+ @name = options[:name].to_s
7
+ @locale = options[:locale].to_s
8
+ @config = options[:config] || File.join(Rails.root, Seiten.config[:config_dir], "#{id}.yml")
9
+ @dir = options[:dir] || File.join(Rails.root, Seiten.config[:pages_dir], @name, @locale)
10
+ @page_collection = Seiten::PageCollection.new(navigation_id: id)
11
+ end
12
+
13
+ class << self
14
+ def find_by(params={})
15
+ where(params).first
16
+ end
17
+
18
+ def where(params={})
19
+ Seiten.navigations.select do |navigation|
20
+ params.all? do |param|
21
+ navigation.send(param[0]) == param[1]
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def id
28
+ "%s.%s" % [name, locale]
29
+ end
30
+
31
+ def pages
32
+ page_collection
33
+ end
34
+
35
+ def pages=(pages_array)
36
+ page_collection.pages = pages_array.map { |page| page.navigation_id = id; page }
37
+ # return page_collection
38
+ # NOTE: This doesn't work and just returns page_array.
39
+ # I think because page_collection#pages= attr_accessor is called first
40
+ # and thus why our return call is ignored.
41
+ end
42
+ end
43
+ end
data/lib/seiten/page.rb CHANGED
@@ -1,63 +1,83 @@
1
- module Seiten
1
+ # frozen_string_literal: true
2
2
 
3
+ module Seiten
3
4
  class Page
4
-
5
- attr_accessor :id, :parent_id, :title, :children, :slug, :redirect, :layout
5
+ attr_accessor :navigation_id, :id, :parent_id, :title, :slug, :refer, :data, :html_options
6
+ attr_writer :layout
6
7
 
7
8
  # initialize Page object with attributes
8
9
  def initialize(options={})
9
- @id = options[:id]
10
- @parent_id = options[:parent_id]
11
- @title = options[:title]
12
- @slug = options[:slug]
13
- @redirect = options[:redirect]
14
- @layout = options[:layout]
10
+ @navigation_id = options[:navigation_id]
11
+ @id = options[:id]
12
+ @parent_id = options[:parent_id]
13
+ @title = options[:title]
14
+ @slug = options[:slug]
15
+ @refer = options[:refer]
16
+ @layout = options[:layout]
17
+ @data = options[:data].each_with_object({}){|(k,v), h| h[k.to_sym] = v} if options[:data]
18
+ @data ||= {}
19
+ @html_options = options[:html].each_with_object({}){|(k,v), h| h[k.to_sym] = v} if options[:html]
20
+ @html_options ||= {}
15
21
  end
16
22
 
17
- class << self
23
+ def navigation
24
+ Seiten::Navigation.find_by(id: navigation_id)
25
+ end
18
26
 
19
- def all
20
- Seiten::PageStore.current.pages
21
- end
27
+ # returns true if slug starts with http:// or https://
28
+ def external?
29
+ !!(slug.match(/^https?:\/\/.+/))
30
+ end
22
31
 
23
- # find page by id
24
- def find(id)
25
- all.select { |page| page.id == id }.first
26
- end
32
+ # get parent of page
33
+ def parent
34
+ navigation.pages.find(parent_id)
35
+ end
27
36
 
28
- # find all pages by parent_id
29
- def find_by_parent_id(parent_id)
30
- all.select { |page| page.parent_id == parent_id }
31
- end
37
+ def parent?
38
+ parent.present?
39
+ end
32
40
 
33
- # find a page by slug
34
- def find_by_slug(slug)
35
- if slug
36
- slug = slug[1..-1] if slug[0] == "/"
37
- end
38
- all.select { |page| page.slug == slug }.first
39
- end
41
+ def ancestors
42
+ return @ancestors unless @ancestors.nil?
40
43
 
41
- # get breadcrumb of given page (reversed)
42
- def get_breadcrumb(page)
43
- pages ||= []
44
- pages << page
45
- if page.parent
46
- pages << get_breadcrumb(page.parent)
47
- end
48
- pages.flatten
44
+ @ancestors = []
45
+ return @ancestors unless parent?
46
+
47
+ ancestor = parent
48
+ loop do
49
+ @ancestors << ancestor
50
+ ancestor = ancestor.parent
51
+ break if ancestor.nil?
49
52
  end
50
53
 
54
+ @ancestors
51
55
  end
52
56
 
53
- # get parent of page
54
- def parent
55
- Page.find(parent_id)
57
+ def self_and_ancestors
58
+ @self_and_ancestors ||= ancestors.insert(0, self)
59
+ end
60
+
61
+ def breadcrumbs
62
+ @breadcrumbs ||= self_and_ancestors.reverse
63
+ end
64
+
65
+ # get root page of current page branch
66
+ def root
67
+ if self.parent?
68
+ self.parent.root
69
+ else
70
+ self
71
+ end
56
72
  end
57
73
 
58
74
  # get children of page
59
75
  def children
60
- Page.all.select { |page| page.parent_id == id }
76
+ navigation.pages.where(parent_id: id)
77
+ end
78
+
79
+ def children?
80
+ navigation.pages.find_by(parent_id: id).present?
61
81
  end
62
82
 
63
83
  # true if child is children of page
@@ -84,5 +104,27 @@ module Seiten
84
104
  end
85
105
  end
86
106
  end
107
+
108
+ def template_path
109
+ [
110
+ navigation_id.gsub(/\./, '/'),
111
+ slug.present? ? slug : Seiten.config[:root_page]
112
+ ].join('/')
113
+ end
114
+ alias_method :to_s, :template_path
115
+
116
+ def path
117
+ return refer if refer
118
+ return '#' if slug.nil?
119
+ return slug if external?
120
+
121
+ navigation_name = navigation.name == 'application' ? nil : navigation.name
122
+
123
+ [:seiten, navigation_name.try(:to_sym), :page, { slug: slug }]
124
+ end
125
+
126
+ def layout
127
+ @layout || Seiten.config[:default_layout]
128
+ end
87
129
  end
88
130
  end
@@ -0,0 +1,54 @@
1
+ module Seiten
2
+ class PageCollection
3
+ attr_accessor :navigation_id, :pages
4
+
5
+ def initialize(options = {})
6
+ @navigation_id = options[:navigation_id]
7
+ @pages = options[:pages] || []
8
+ end
9
+
10
+ def navigation
11
+ Seiten::Navigation.find_by(id: navigation_id)
12
+ end
13
+
14
+ def build(options = {})
15
+ Seiten::PageCollectionBuilder.call(self, options)
16
+ end
17
+
18
+ def all
19
+ pages.to_a
20
+ end
21
+
22
+ def find(id)
23
+ find_by(id: id)
24
+ end
25
+
26
+ def find_by(params)
27
+ @find_by ||= {}
28
+ return @find_by[params] if @find_by.key?(params)
29
+
30
+ @find_by[params] = pages.find do |page|
31
+ params.all? do |k, v|
32
+ page.send(k) == v
33
+ end
34
+ end
35
+ end
36
+
37
+ def where(params)
38
+ @where ||= {}
39
+ return @where[params] if @where.key?(params)
40
+
41
+ @where[params] = pages.select do |page|
42
+ params.all? do |k, v|
43
+ page.send(k) == v
44
+ end
45
+ end
46
+ end
47
+
48
+ def new(params = {})
49
+ page = Seiten::Page.new(params.merge(navigation_id: navigation_id))
50
+ pages << page
51
+ page
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,63 @@
1
+ module Seiten
2
+ class PageCollectionBuilder
3
+ def self.call(page_collection, options={})
4
+ pages = options[:pages]
5
+ parent_id = options[:parent_id] # || nil
6
+ layout = options[:layout]
7
+ prefix_url = options[:prefix_url] || ""
8
+
9
+ @id ||= 1
10
+ @parsed_pages ||= []
11
+
12
+ pages.each_index do |i|
13
+
14
+ # Load page and set parent_id and generated page id
15
+ page = pages[i]
16
+ page["id"] = @id
17
+ page["parent_id"] = parent_id
18
+ page["layout"] ||= layout
19
+
20
+ # Increment generated id
21
+ @id += 1
22
+
23
+ # Build slug
24
+ raise Errors::PageError, "The `url` option can not be an external path. Use the `refer` option to link to external resources." if page["url"] && !!(page["url"].match(/^https?:\/\/.+/))
25
+ slug = Seiten::SlugBuilder.call(page, prefix_url) unless page['url'].is_a?(FalseClass)
26
+
27
+ # Set refer
28
+ if page["refer"]
29
+ if page["refer"].is_a?(TrueClass)
30
+ page["refer"] = "/" + Seiten::SlugBuilder.call(page["nodes"].first, page["slug"])
31
+ end
32
+ raise Errors::PageError, "The `refer` option must be `true` or an absolute or external path" if page["refer"] != true && page["refer"][0] != "/" && !(page["refer"].match(/^https?:\/\/.+/))
33
+ else
34
+ page["slug"] = slug
35
+ end
36
+
37
+ # Set layout
38
+ if page["layout"]
39
+ if page["layout"].is_a?(String)
40
+ inherited_layout = page["layout"]
41
+ elsif page["layout"].is_a?(Hash)
42
+ if page["layout"]["inherit"]
43
+ inherited_layout = page["layout"]
44
+ else
45
+ inherited_layout = nil
46
+ end
47
+ page["layout"] = page["layout"]["name"]
48
+ end
49
+ end
50
+
51
+ # Load children
52
+ if page["nodes"]
53
+ self.call(page_collection, pages: page["nodes"], parent_id: page["id"], prefix_url: slug, layout: inherited_layout, external: page["external"])
54
+ end
55
+
56
+ page_params = page.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
57
+ @parsed_pages << page_collection.new(page_params)
58
+ end
59
+
60
+ @parsed_pages
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,7 @@
1
+ module Seiten
2
+ class Railtie < Rails::Railtie
3
+ config.action_dispatch.rescue_responses.merge!(
4
+ 'Seiten::Errors::RoutingError' => :not_found
5
+ )
6
+ end
7
+ end
@@ -1,16 +1,21 @@
1
1
  class ActionDispatch::Routing::Mapper
2
+ def seiten(*resources)
3
+ options = resources.extract_options!
4
+ options[:to] ||= 'seiten/pages#show'
2
5
 
3
- def seiten_resources
4
- Seiten::PageStore.storages.each do |page_store|
5
- page_store.pages.each do |page|
6
- if page.redirect
7
- get page.slug, to: redirect { |p, req|
8
- Rails.application.routes.url_helpers.seiten_page_path(page: page.redirect, locale: p[:locale])
9
- }
10
- end
11
- end
12
- end
6
+ resources.each do |resource|
7
+ resource_options = options.dup
8
+
9
+ resource_options[:as] ||= resource == :application ? :seiten_page : "seiten_#{resource}_page"
10
+
11
+ resource_options[:defaults] ||= {}
12
+ resource_options[:defaults][:navigation_id] = resource.to_s unless resource == :application
13
+ resource_options[:defaults][:slug] = ''
13
14
 
14
- get "(*page)" => "seiten/pages#show", as: :seiten_page
15
+ # NOTE: See https://github.com/rails/rails/issues/31228
16
+ resource_options[:constraints] ||= ->(req) { req.path.exclude? 'rails/active_storage' }
17
+
18
+ get '(*slug)', resource_options
19
+ end
15
20
  end
16
21
  end
@@ -0,0 +1,32 @@
1
+ module Seiten
2
+ class SlugBuilder
3
+
4
+ def self.call(page_options, prefix_url='')
5
+ page_options = page_options.with_indifferent_access
6
+ title = page_options['title']
7
+ url = page_options['url']
8
+ root = page_options['root']
9
+
10
+ # if url is nil parameterize title otherwise just use url
11
+ slug = url.nil? ? title.parameterize : url
12
+
13
+ # prepend prefix_url if slug is not root or external url
14
+ unless slug[0] == "/" || !!(slug.match(/^https?:\/\/.+/)) || !prefix_url.present?
15
+ slug = "#{prefix_url}/#{slug}"
16
+ end
17
+
18
+ # return empty string if page slug is /
19
+ if slug == "/" || root == true
20
+ slug = ""
21
+ end
22
+
23
+ # remove leading slash if present
24
+ if slug
25
+ slug = slug[1..-1] if slug[0] == "/"
26
+ end
27
+
28
+ slug
29
+ end
30
+
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  module Seiten
2
- VERSION = "0.0.6"
2
+ VERSION = "1.0.0"
3
3
  end