scribo 1.0.38
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +93 -0
- data/Rakefile +40 -0
- data/app/assets/config/scribo_manifest.js +2 -0
- data/app/assets/javascripts/scribo/scribo.js +1 -0
- data/app/assets/stylesheets/scribo/scribo.css +1 -0
- data/app/controllers/concerns/maintenance_standards.rb +24 -0
- data/app/controllers/scribo/admin/sites/contents_controller.rb +86 -0
- data/app/controllers/scribo/admin/sites_controller.rb +61 -0
- data/app/controllers/scribo/api/sites_controller.rb +23 -0
- data/app/controllers/scribo/application_admin_controller.rb +11 -0
- data/app/controllers/scribo/application_controller.rb +6 -0
- data/app/controllers/scribo/contents_controller.rb +20 -0
- data/app/drops/scribo/action_dispatch/request_drop.rb +15 -0
- data/app/drops/scribo/active_model/errors_drop.rb +16 -0
- data/app/drops/scribo/application_drop.rb +9 -0
- data/app/drops/scribo/array_drop.rb +13 -0
- data/app/drops/scribo/content_drop.rb +73 -0
- data/app/drops/scribo/data_drop.rb +35 -0
- data/app/drops/scribo/form_drop.rb +26 -0
- data/app/drops/scribo/include_drop.rb +13 -0
- data/app/drops/scribo/paginator_drop.rb +73 -0
- data/app/drops/scribo/site_drop.rb +83 -0
- data/app/helpers/scribo/application_helper.rb +13 -0
- data/app/jobs/scribo/application_job.rb +6 -0
- data/app/models/scribo/application_record.rb +11 -0
- data/app/models/scribo/content.rb +378 -0
- data/app/models/scribo/site.rb +161 -0
- data/app/services/scribo/application_service.rb +9 -0
- data/app/services/scribo/content_find_service.rb +69 -0
- data/app/services/scribo/content_render_service.rb +127 -0
- data/app/services/scribo/site_export_service.rb +41 -0
- data/app/services/scribo/site_find_service.rb +26 -0
- data/app/services/scribo/site_import_service.rb +96 -0
- data/app/views/layouts/scribo.html.slim +1 -0
- data/app/views/scribo/admin/sites/_create_sites.html.slim +22 -0
- data/app/views/scribo/admin/sites/_sites.html.slim +18 -0
- data/app/views/scribo/admin/sites/contents/_form.html.slim +17 -0
- data/app/views/scribo/admin/sites/contents/create.json.jbuilder +11 -0
- data/app/views/scribo/admin/sites/contents/edit.html.slim +2 -0
- data/app/views/scribo/admin/sites/contents/edit.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/contents/index.html.slim +1 -0
- data/app/views/scribo/admin/sites/contents/move.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/contents/rename.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/contents/upload.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/import.json.jbuilder +4 -0
- data/app/views/scribo/admin/sites/index.html.slim +7 -0
- data/app/views/scribo/shared/_entry.html.slim +17 -0
- data/app/views/scribo/shared/_ide.html.slim +14 -0
- data/app/views/scribo/shared/_tree-view.html.slim +32 -0
- data/config/locales/en.yml +39 -0
- data/config/routes.rb +35 -0
- data/db/migrate/20200123095630_initial_scribo.rb +34 -0
- data/db/migrate/20220919124119_add_ancestry_to_scribo_contents.rb +13 -0
- data/db/migrate/20220919124749_remove_parent_id_from_scribo_contents.rb +8 -0
- data/lib/scribo/action_controller_helpers.rb +51 -0
- data/lib/scribo/action_controller_renderers.rb +71 -0
- data/lib/scribo/action_view_helpers.rb +17 -0
- data/lib/scribo/active_record_helpers.rb +11 -0
- data/lib/scribo/configuration.rb +97 -0
- data/lib/scribo/engine.rb +24 -0
- data/lib/scribo/i18n_store.rb +100 -0
- data/lib/scribo/liquid/filters/jekyll_filters.rb +94 -0
- data/lib/scribo/liquid/filters/markdownify.rb +11 -0
- data/lib/scribo/liquid/filters/url_filters.rb +76 -0
- data/lib/scribo/liquid/parser.rb +32 -0
- data/lib/scribo/liquid/tags/application_assets_tag.rb +14 -0
- data/lib/scribo/liquid/tags/application_js_tag.rb +16 -0
- data/lib/scribo/liquid/tags/asset_tag.rb +56 -0
- data/lib/scribo/liquid/tags/button_tag.rb +24 -0
- data/lib/scribo/liquid/tags/check_box_tag.rb +31 -0
- data/lib/scribo/liquid/tags/csrf_meta_tags_tag.rb +16 -0
- data/lib/scribo/liquid/tags/date_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/editable_url_tag.rb +19 -0
- data/lib/scribo/liquid/tags/email_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/feed_meta_tag.rb +22 -0
- data/lib/scribo/liquid/tags/field_error_tag.rb +26 -0
- data/lib/scribo/liquid/tags/fields_for_tag.rb +82 -0
- data/lib/scribo/liquid/tags/form_tag.rb +57 -0
- data/lib/scribo/liquid/tags/google_analytics_javascript_tag.rb +30 -0
- data/lib/scribo/liquid/tags/google_tag_manager_javascript_tag.rb +28 -0
- data/lib/scribo/liquid/tags/hidden_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/highlight_tag.rb +106 -0
- data/lib/scribo/liquid/tags/include_tag.rb +28 -0
- data/lib/scribo/liquid/tags/label_tag.rb +24 -0
- data/lib/scribo/liquid/tags/number_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/options_for_select.rb +36 -0
- data/lib/scribo/liquid/tags/password_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/search_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/search_tag.rb +29 -0
- data/lib/scribo/liquid/tags/select_tag.rb +22 -0
- data/lib/scribo/liquid/tags/seo_tag.rb +35 -0
- data/lib/scribo/liquid/tags/set_session.rb +19 -0
- data/lib/scribo/liquid/tags/telephone_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/text_field_tag.rb +35 -0
- data/lib/scribo/liquid/tags/textarea_tag.rb +28 -0
- data/lib/scribo/liquid/tags/time_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/url_field_tag.rb +23 -0
- data/lib/scribo/preamble.rb +89 -0
- data/lib/scribo/sassc/importer.rb +72 -0
- data/lib/scribo/utility.rb +94 -0
- data/lib/scribo/version.rb +5 -0
- data/lib/scribo.rb +59 -0
- data/lib/tasks/scribo_tasks.rake +28 -0
- metadata +498 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency 'scribo/application_drop'
|
4
|
+
|
5
|
+
module Scribo
|
6
|
+
# https://jekyllrb.com/docs/pagination/#liquid-attributes-available
|
7
|
+
class PaginatorDrop < ApplicationDrop
|
8
|
+
def initialize(site, content)
|
9
|
+
@site = site
|
10
|
+
@object = content
|
11
|
+
@per_page = site&.properties&.[]('paginate') ? site.properties['paginate'].to_i : 5
|
12
|
+
end
|
13
|
+
|
14
|
+
def posts
|
15
|
+
@site.contents.posts.order(created_at: :desc).page(page).per(@per_page).to_a
|
16
|
+
end
|
17
|
+
|
18
|
+
def page
|
19
|
+
page = 1
|
20
|
+
current_path = @context.registers['controller'].request.original_fullpath
|
21
|
+
page = current_path.match(%r[/(\d+)/$])[1].to_i if Scribo::Content.paginated?(current_path)
|
22
|
+
page
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :per_page
|
26
|
+
|
27
|
+
def total_posts
|
28
|
+
@site.contents.posts.page(page).per(@per_page).total_count
|
29
|
+
end
|
30
|
+
|
31
|
+
def total_pages
|
32
|
+
@site.contents.posts.page(page).per(@per_page).total_pages
|
33
|
+
end
|
34
|
+
|
35
|
+
def previous_page
|
36
|
+
page > 1 ? page - 1 : nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def previous_page_path
|
40
|
+
current_path = @context.registers['controller'].request.original_fullpath
|
41
|
+
previous_path = nil
|
42
|
+
if previous_page
|
43
|
+
if Scribo::Content.paginated?(current_path)
|
44
|
+
previous_path = current_path.gsub(%r[/(\d+)/$], "/#{previous_page}/")
|
45
|
+
else
|
46
|
+
previous_path = current_path
|
47
|
+
previous_path += '/' unless previous_path.ends_with?('/')
|
48
|
+
previous_path += "#{next_page}/"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
previous_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def next_page
|
55
|
+
page < total_pages ? page + 1 : nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def next_page_path
|
59
|
+
current_path = @context.registers['controller'].request.original_fullpath
|
60
|
+
next_path = nil
|
61
|
+
if next_page
|
62
|
+
if Scribo::Content.paginated?(current_path)
|
63
|
+
next_path = current_path.gsub(%r[/(\d+)/$], "/#{next_page}/")
|
64
|
+
else
|
65
|
+
next_path = current_path
|
66
|
+
next_path += '/' unless next_path.ends_with?('/')
|
67
|
+
next_path += "#{next_page}/"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
next_path
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency 'scribo/application_drop'
|
4
|
+
require 'pry'
|
5
|
+
module Scribo
|
6
|
+
# See https://jekyllrb.com/docs/variables/#site-variables
|
7
|
+
class SiteDrop < ApplicationDrop
|
8
|
+
delegate :collections, to: :@object
|
9
|
+
|
10
|
+
def initialize(object)
|
11
|
+
@object = object
|
12
|
+
@properties = object.properties
|
13
|
+
end
|
14
|
+
|
15
|
+
def time
|
16
|
+
Time.current
|
17
|
+
end
|
18
|
+
|
19
|
+
def pages
|
20
|
+
@object.contents.pages.to_a
|
21
|
+
end
|
22
|
+
|
23
|
+
def posts
|
24
|
+
@object.contents.posts.sort_by { |p| - p.date.to_i }.to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO
|
28
|
+
def related_posts
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def static_files
|
33
|
+
@object.contents.assets.to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
def html_pages
|
37
|
+
@object.contents.html_pages.to_a
|
38
|
+
end
|
39
|
+
|
40
|
+
def html_files
|
41
|
+
@object.contents.html_files.to_a
|
42
|
+
end
|
43
|
+
|
44
|
+
def data
|
45
|
+
Scribo::DataDrop.new(@object)
|
46
|
+
end
|
47
|
+
|
48
|
+
# TODO
|
49
|
+
def documents
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
|
53
|
+
# TODO
|
54
|
+
def categories
|
55
|
+
[]
|
56
|
+
end
|
57
|
+
|
58
|
+
# TODO
|
59
|
+
def tags
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
|
63
|
+
def url
|
64
|
+
@properties['url']
|
65
|
+
end
|
66
|
+
|
67
|
+
def current_locale
|
68
|
+
I18n.locale.to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
def locale
|
72
|
+
@properties['locale']
|
73
|
+
end
|
74
|
+
|
75
|
+
def liquid_method_missing(method)
|
76
|
+
if collections.include?(method)
|
77
|
+
@object.contents.in_folder("_#{method}").order(:created_at).to_a
|
78
|
+
else
|
79
|
+
@properties[method.to_s]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,378 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency 'scribo/application_record'
|
4
|
+
|
5
|
+
module Scribo
|
6
|
+
# Represents any content in the system
|
7
|
+
class Content < ApplicationRecord
|
8
|
+
has_ancestry(primary_key_format: /\A[\w\-]+(\/[\w\-]+)*\z/, counter_cache: true, cache_depth: true)
|
9
|
+
belongs_to :site, class_name: 'Site', foreign_key: 'scribo_site_id'
|
10
|
+
has_one_attached :asset
|
11
|
+
|
12
|
+
validate :post_path
|
13
|
+
validate :layout_cant_be_current_content
|
14
|
+
|
15
|
+
before_save :store_properties, if: :config?
|
16
|
+
before_save :upload_asset
|
17
|
+
|
18
|
+
after_save -> { store_full_path(true) }
|
19
|
+
after_update -> {store_full_path(true)}
|
20
|
+
|
21
|
+
scope :layouts, -> { in_folder('_layouts') }
|
22
|
+
scope :posts, -> { in_folder('_posts') }
|
23
|
+
scope :pages, -> { not_in_folder('_posts').restricted.where(kind: 'text') }
|
24
|
+
scope :assets, -> { where(kind: 'asset') }
|
25
|
+
scope :html_pages, -> { where("full_path LIKE '%.html' OR full_path LIKE '%.md' OR full_path LIKE '%.markdown'") }
|
26
|
+
# html files should be non-filtered html files
|
27
|
+
scope :html_files, -> { where("full_path LIKE '%.html'") }
|
28
|
+
scope :include, ->(name) { published.where(full_path: ["/_includes/#{name}"]) }
|
29
|
+
scope :layout, lambda { |name|
|
30
|
+
published.where(full_path: %W[/_layouts/#{name}.html /_layouts/#{name}.md /_layouts/#{name}.xml /_layouts/#{name}.css])
|
31
|
+
}
|
32
|
+
scope :data, lambda { |name|
|
33
|
+
published.where(full_path: %W[/_data/#{name}.yml /_data/#{name}.yaml /_data/#{name}.json /_data/#{name}.csv /_data/#{name}])
|
34
|
+
}
|
35
|
+
|
36
|
+
scope :locale, ->(name) { published.where(full_path: "/_locales/#{name}.yml") }
|
37
|
+
scope :locales, -> { published.in_folder('_locales') }
|
38
|
+
|
39
|
+
scope :published, lambda {
|
40
|
+
where("properties->>'published' = 'true' OR properties->>'published' IS NULL").where("properties->>'published_at' IS NULL OR properties->>'published_at' <= :now", now: Time.current.utc)
|
41
|
+
}
|
42
|
+
scope :restricted, -> { where("full_path NOT LIKE '/\\_%'") }
|
43
|
+
|
44
|
+
scope :not_in_folder, lambda { |folder_name|
|
45
|
+
where.not(id: in_folder(folder_name).pluck(:id))
|
46
|
+
}
|
47
|
+
scope :in_folder, lambda { |folder_name|
|
48
|
+
where(kind: 'folder').find_by(path: folder_name)&.descendants || none
|
49
|
+
}
|
50
|
+
|
51
|
+
scope :permalinked, ->(paths) { where("properties->>'permalink' IN (?)", paths) }
|
52
|
+
|
53
|
+
def self.located(path, restricted: true)
|
54
|
+
restricted = true if restricted.nil? # If blank it's still restricted
|
55
|
+
|
56
|
+
result = published.where(full_path: search_paths_for(path))
|
57
|
+
result = result.restricted if restricted
|
58
|
+
result.or(published.permalinked(search_paths_for(path)))
|
59
|
+
end
|
60
|
+
|
61
|
+
def path
|
62
|
+
self[:path]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Uses https://www.postgresql.org/docs/current/textsearch-controls.html
|
66
|
+
def self.search(search_string)
|
67
|
+
where(
|
68
|
+
"to_tsvector(scribo_contents.data || ' ' || COALESCE(scribo_contents.properties::text, '')) @@ to_tsquery(?)", search_string
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Name of the currently in use layout
|
73
|
+
def layout_name
|
74
|
+
properties&.key?('layout') ? properties&.[]('layout') : ''
|
75
|
+
end
|
76
|
+
|
77
|
+
# Layout as content
|
78
|
+
def layout
|
79
|
+
return nil unless layout_name.present?
|
80
|
+
|
81
|
+
site.contents.layout(layout_name).first
|
82
|
+
end
|
83
|
+
|
84
|
+
def identifier
|
85
|
+
File.basename(path, File.extname(path))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Data with frontmatter, used for maintenance and import/export
|
89
|
+
def data_with_frontmatter
|
90
|
+
return asset.attachment&.download || data if kind != 'text'
|
91
|
+
|
92
|
+
result = ''
|
93
|
+
# Use attributes['properties'] here, to always use content-local properties
|
94
|
+
result += (YAML.dump(attributes['properties']) + "---\n") if attributes['properties'].present?
|
95
|
+
|
96
|
+
result + data.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
# Data with frontmatter setter
|
100
|
+
def data_with_frontmatter=(text)
|
101
|
+
if kind == 'text'
|
102
|
+
data_with_metadata = Scribo::Preamble.parse(text)
|
103
|
+
self.properties = data_with_metadata.metadata
|
104
|
+
self.data = data_with_metadata.content
|
105
|
+
else
|
106
|
+
self.data = text
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Used for merging with defaults
|
111
|
+
def properties
|
112
|
+
attributes['properties']
|
113
|
+
# defaults.merge(attributes['properties'] || {})
|
114
|
+
end
|
115
|
+
|
116
|
+
def properties=(text)
|
117
|
+
props = text.is_a?(String) ? Scribo::Utility.yaml_safe_parse(text.gsub("\t", ' ')) : text
|
118
|
+
write_attribute :properties, props
|
119
|
+
end
|
120
|
+
|
121
|
+
def type
|
122
|
+
collection_name
|
123
|
+
end
|
124
|
+
|
125
|
+
def permalink
|
126
|
+
properties&.[]('permalink')
|
127
|
+
end
|
128
|
+
|
129
|
+
def url
|
130
|
+
result = permalink || Scribo::Utility.switch_extension(full_path)
|
131
|
+
result += '/' unless result.end_with?('/')
|
132
|
+
result
|
133
|
+
end
|
134
|
+
|
135
|
+
def date
|
136
|
+
# return nil unless post?
|
137
|
+
|
138
|
+
prop_date = begin
|
139
|
+
Time.zone.parse(properties['date'])
|
140
|
+
rescue StandardError
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
|
144
|
+
prop_date || post_date
|
145
|
+
end
|
146
|
+
|
147
|
+
def post_date
|
148
|
+
Time.zone.strptime(path[0, 10], '%Y-%m-%d')
|
149
|
+
rescue StandardError
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
|
153
|
+
def data
|
154
|
+
return attributes['data'] if kind == 'asset'
|
155
|
+
|
156
|
+
attributes['data']&.force_encoding('utf-8')
|
157
|
+
end
|
158
|
+
|
159
|
+
def excerpt
|
160
|
+
# FIXME: This is a terrible implementation
|
161
|
+
excerpt_part = data.gsub("\r\n", "\n\n").split("\n\n").reject(&:empty?).reject { |p| p.start_with?('#') }.first
|
162
|
+
Scribo::ContentRenderService.new(self, {}, data: excerpt_part, layout: false).call
|
163
|
+
end
|
164
|
+
|
165
|
+
def render(context = {}, options = {})
|
166
|
+
Scribo::ContentRenderService.new(self, context, options).call
|
167
|
+
end
|
168
|
+
|
169
|
+
def categories
|
170
|
+
if properties&.[]('categories').is_a? Array
|
171
|
+
properties&.[]('categories')
|
172
|
+
else
|
173
|
+
(properties&.[]('categories') || '').split
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def tags
|
178
|
+
if properties&.[]('tags').is_a? Array
|
179
|
+
properties&.[]('tags')
|
180
|
+
else
|
181
|
+
(properties&.[]('tags') || '').split
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def content_type
|
186
|
+
properties&.[]('content_type') || mime_type&.content_type || 'application/octet-stream'
|
187
|
+
end
|
188
|
+
|
189
|
+
def media_type
|
190
|
+
mime_type&.media_type
|
191
|
+
end
|
192
|
+
|
193
|
+
def extension
|
194
|
+
mime_type&.extensions&.first
|
195
|
+
end
|
196
|
+
|
197
|
+
def mime_type
|
198
|
+
MIME::Types.type_for(path).first
|
199
|
+
end
|
200
|
+
|
201
|
+
def dir
|
202
|
+
File.dirname(full_path)
|
203
|
+
end
|
204
|
+
|
205
|
+
def extname
|
206
|
+
File.extname(full_path).tr('.', '')
|
207
|
+
end
|
208
|
+
|
209
|
+
def translation_scope
|
210
|
+
scope = File.dirname(full_path).split('/')
|
211
|
+
scope << File.basename(full_path, File.extname(full_path))
|
212
|
+
scope.join('.')
|
213
|
+
end
|
214
|
+
|
215
|
+
def cache_key
|
216
|
+
"#{super}-#{updated_at}-#{I18n.locale}"
|
217
|
+
end
|
218
|
+
|
219
|
+
def collection_name
|
220
|
+
return nil unless part_of_collection?
|
221
|
+
|
222
|
+
ancestors.first.path[1..-1]
|
223
|
+
end
|
224
|
+
|
225
|
+
def part_of_collection?
|
226
|
+
return false unless ancestors.first&.path&.start_with?('_')
|
227
|
+
|
228
|
+
site.collections.include?(ancestors.first.path[1..-1])
|
229
|
+
end
|
230
|
+
|
231
|
+
def redirect?
|
232
|
+
extname == 'link'
|
233
|
+
end
|
234
|
+
|
235
|
+
def layout?
|
236
|
+
full_path.start_with?('/_layouts/')
|
237
|
+
end
|
238
|
+
|
239
|
+
def post?
|
240
|
+
ancestors.map(&:path).join('/').start_with?('_posts')
|
241
|
+
end
|
242
|
+
|
243
|
+
def page?
|
244
|
+
Scribo::Utility.output_content_type(self) == 'text/html'
|
245
|
+
end
|
246
|
+
|
247
|
+
def config?
|
248
|
+
path == '_config.yml' && parent.nil?
|
249
|
+
end
|
250
|
+
|
251
|
+
def asset?
|
252
|
+
kind == 'asset'
|
253
|
+
end
|
254
|
+
|
255
|
+
def folder?
|
256
|
+
kind == 'folder'
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.paginated?(path)
|
260
|
+
path.match(%r[/(\d+)/$])
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.search_paths_for(path)
|
264
|
+
search_paths = []
|
265
|
+
|
266
|
+
search_path = path
|
267
|
+
search_path = "/#{search_path}" unless search_path.start_with?('/')
|
268
|
+
search_path.gsub!(%r[/\d+/$], '/') if paginated?(search_path)
|
269
|
+
search_path = "#{search_path}index.html" if search_path.ends_with?('/')
|
270
|
+
|
271
|
+
search_paths.concat(alternative_paths_for(search_path))
|
272
|
+
|
273
|
+
secondary_search_path = path.sub(%r[/$], '')
|
274
|
+
secondary_search_path = "/#{secondary_search_path}" unless secondary_search_path.start_with?('/')
|
275
|
+
search_paths.concat(alternative_paths_for(secondary_search_path)) if secondary_search_path != '' && secondary_search_path != search_path
|
276
|
+
|
277
|
+
permalink_paths = [path]
|
278
|
+
|
279
|
+
normalized_path = path
|
280
|
+
normalized_path = "/#{normalized_path}" unless normalized_path.start_with?('/')
|
281
|
+
normalized_path = "#{normalized_path}/" unless normalized_path.ends_with?('/')
|
282
|
+
permalink_paths << normalized_path
|
283
|
+
search_paths.concat(permalink_paths) # deal with permalinks
|
284
|
+
|
285
|
+
search_paths.uniq
|
286
|
+
end
|
287
|
+
|
288
|
+
def self.alternative_paths_for(search_path)
|
289
|
+
search_paths = []
|
290
|
+
search_path = Scribo::Utility.switch_extension(search_path, 'html') unless File.extname(search_path).present?
|
291
|
+
search_paths.concat(Scribo::Utility.variations_for_path(search_path))
|
292
|
+
search_paths << Scribo::Utility.switch_extension(search_path, 'link')
|
293
|
+
end
|
294
|
+
|
295
|
+
def store_full_path(force = false)
|
296
|
+
if force || saved_changes.include?(:path) || saved_changes.include?(:ancestry)
|
297
|
+
if post?
|
298
|
+
result = categories.join('/') + '/'
|
299
|
+
result += date.strftime('%Y/%m/%d/') if date
|
300
|
+
result += path[11..-1]
|
301
|
+
elsif part_of_collection? && site.output_collection?(collection_name)
|
302
|
+
result = "#{collection_name}/#{path}"
|
303
|
+
else
|
304
|
+
result = (ancestors.map(&:path) << path).join('/')
|
305
|
+
end
|
306
|
+
result = '/' + result unless result.start_with?('/')
|
307
|
+
|
308
|
+
update_column(:full_path, result)
|
309
|
+
|
310
|
+
children.reload.each do |child|
|
311
|
+
child.store_full_path(true)
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def tree_path
|
318
|
+
result = (ancestors.map(&:path) << path).join('/')
|
319
|
+
result = '/' + result unless result.start_with?('/')
|
320
|
+
result
|
321
|
+
end
|
322
|
+
|
323
|
+
private
|
324
|
+
|
325
|
+
def upload_asset
|
326
|
+
return unless asset?
|
327
|
+
# return unless data.present? -> Breaks with utf8?
|
328
|
+
return unless data
|
329
|
+
return unless data.size.positive?
|
330
|
+
|
331
|
+
si = StringIO.new
|
332
|
+
si.write(data)
|
333
|
+
si.rewind
|
334
|
+
|
335
|
+
asset.attach(io: si, filename: path, content_type: content_type)
|
336
|
+
|
337
|
+
self.data = nil
|
338
|
+
end
|
339
|
+
|
340
|
+
def store_properties
|
341
|
+
return unless attributes['data'].present?
|
342
|
+
|
343
|
+
new_properties = Scribo::Utility.yaml_safe_parse(attributes['data'])
|
344
|
+
old_properties = site.properties
|
345
|
+
site.update(properties: new_properties)
|
346
|
+
|
347
|
+
# Only reshuffle if they need to
|
348
|
+
if old_properties['collections'] != new_properties['collections'] ||
|
349
|
+
old_properties['permalink'] != new_properties['permalink']
|
350
|
+
site.reshuffle!
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def post_path
|
355
|
+
return unless post?
|
356
|
+
|
357
|
+
errors.add(:path, 'path must be of format YYYY-MM-DD-title') unless path.match(/[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}-.*/)
|
358
|
+
end
|
359
|
+
|
360
|
+
def layout_cant_be_current_content
|
361
|
+
return unless layout
|
362
|
+
|
363
|
+
errors.add(:base, "layout can't be layout of itself") if layout.full_path == full_path
|
364
|
+
end
|
365
|
+
|
366
|
+
class << self
|
367
|
+
def redirect_options(redirect_data)
|
368
|
+
options = redirect_data.split
|
369
|
+
if options.length == 2
|
370
|
+
options[0] = options[0].to_i
|
371
|
+
else
|
372
|
+
options.unshift 302
|
373
|
+
end
|
374
|
+
options
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|