jekyll-manager 0.1.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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +63 -0
  4. data/lib/jekyll-admin.rb +47 -0
  5. data/lib/jekyll-admin/apiable.rb +167 -0
  6. data/lib/jekyll-admin/data_file.rb +103 -0
  7. data/lib/jekyll-admin/directory.rb +73 -0
  8. data/lib/jekyll-admin/file_helper.rb +68 -0
  9. data/lib/jekyll-admin/page_without_a_file.rb +7 -0
  10. data/lib/jekyll-admin/path_helper.rb +78 -0
  11. data/lib/jekyll-admin/public/bundle.js +58 -0
  12. data/lib/jekyll-admin/public/bundle.js.map +1 -0
  13. data/lib/jekyll-admin/public/favicon.ico +0 -0
  14. data/lib/jekyll-admin/public/fonts/fontawesome-webfont.eot +0 -0
  15. data/lib/jekyll-admin/public/fonts/fontawesome-webfont.ttf +0 -0
  16. data/lib/jekyll-admin/public/fonts/fontawesome-webfont.woff +0 -0
  17. data/lib/jekyll-admin/public/fonts/fontawesome-webfont.woff2 +0 -0
  18. data/lib/jekyll-admin/public/fonts/lato-bold.ttf +0 -0
  19. data/lib/jekyll-admin/public/fonts/lato-regular.ttf +0 -0
  20. data/lib/jekyll-admin/public/fonts/rw-widgets.eot +0 -0
  21. data/lib/jekyll-admin/public/fonts/rw-widgets.ttf +0 -0
  22. data/lib/jekyll-admin/public/fonts/rw-widgets.woff +0 -0
  23. data/lib/jekyll-admin/public/images/fontawesome-webfont.svg +685 -0
  24. data/lib/jekyll-admin/public/images/loader-big.gif +0 -0
  25. data/lib/jekyll-admin/public/images/loading.gif +0 -0
  26. data/lib/jekyll-admin/public/images/logo-black-red.png +0 -0
  27. data/lib/jekyll-admin/public/images/logo.png +0 -0
  28. data/lib/jekyll-admin/public/images/no-image.svg +1 -0
  29. data/lib/jekyll-admin/public/images/rw-widgets.svg +18 -0
  30. data/lib/jekyll-admin/public/index.html +13 -0
  31. data/lib/jekyll-admin/public/styles.css +5 -0
  32. data/lib/jekyll-admin/public/styles.css.map +1 -0
  33. data/lib/jekyll-admin/server.rb +119 -0
  34. data/lib/jekyll-admin/server/collection.rb +88 -0
  35. data/lib/jekyll-admin/server/configuration.rb +57 -0
  36. data/lib/jekyll-admin/server/dashboard.rb +113 -0
  37. data/lib/jekyll-admin/server/data.rb +82 -0
  38. data/lib/jekyll-admin/server/draft.rb +110 -0
  39. data/lib/jekyll-admin/server/page.rb +90 -0
  40. data/lib/jekyll-admin/server/static_file.rb +82 -0
  41. data/lib/jekyll-admin/server/template.rb +196 -0
  42. data/lib/jekyll-admin/server/theme.rb +135 -0
  43. data/lib/jekyll-admin/static_server.rb +24 -0
  44. data/lib/jekyll-admin/urlable.rb +67 -0
  45. data/lib/jekyll-admin/version.rb +3 -0
  46. data/lib/jekyll-manager.rb +5 -0
  47. data/lib/jekyll/commands/build.rb +14 -0
  48. data/lib/jekyll/commands/serve.rb +26 -0
  49. metadata +253 -0
@@ -0,0 +1,110 @@
1
+ module JekyllAdmin
2
+ class Server < Sinatra::Base
3
+ namespace "/drafts" do
4
+ get "/*?/?:path.:ext" do
5
+ ensure_requested_file
6
+ json requested_file.to_api(:include_content => true)
7
+ end
8
+
9
+ get "/?*" do
10
+ ensure_directory
11
+ json entries.map(&:to_api)
12
+ end
13
+
14
+ put "/*?/?:path.:ext" do
15
+ ensure_html_content
16
+
17
+ if renamed?
18
+ ensure_requested_file
19
+ delete_file path
20
+ end
21
+
22
+ write_file write_path, document_body
23
+ json written_file.to_api(:include_content => true)
24
+ end
25
+
26
+ delete "/*?/?:path.:ext" do
27
+ ensure_requested_file
28
+ delete_file path
29
+ content_type :json
30
+ status 200
31
+ halt
32
+ end
33
+
34
+ private
35
+
36
+ # return all documents in the 'posts' collection that output to an html
37
+ # file but reside in a separate directory, `<source_dir>/_drafts/`
38
+ def drafts
39
+ posts = site.collections.find { |l, _c| l == "posts" }
40
+ if posts
41
+ posts[1].docs.find_all { |d| d.output_ext == ".html" && d.draft? }
42
+ end
43
+ end
44
+
45
+ # return drafts at the same level as directory
46
+ def directory_drafts
47
+ drafts.find_all { |d| File.dirname(d.path) == directory_path }
48
+ end
49
+
50
+ def reverse_sorted_drafts
51
+ directory_drafts.sort_by(&:date).reverse
52
+ end
53
+
54
+ # returns directories at the root of `/_drafts/` that contain drafts
55
+ def relevant_directory_paths
56
+ drafts.map { |doc| relative_draft_path(doc).split("/")[0] }.uniq
57
+ end
58
+
59
+ def relative_draft_path(document)
60
+ File.dirname(document.relative_path.sub("_drafts/", ""))
61
+ end
62
+
63
+ def ensure_directory
64
+ ensure_drafts
65
+ render_404 unless Dir.exist?(directory_path)
66
+ end
67
+
68
+ def ensure_drafts
69
+ render_404 if drafts.nil?
70
+ end
71
+
72
+ def ensure_html_content
73
+ return if html_content?
74
+ content_type :json
75
+ halt 422, json("error_message" => "Invalid file extension for drafts")
76
+ end
77
+
78
+ def entries
79
+ args = {
80
+ :base => site.source,
81
+ :content_type => "drafts",
82
+ :splat => params["splat"].first,
83
+ }
84
+ # get the directories inside the requested directory
85
+ directory = JekyllAdmin::Directory.new(directory_path, args)
86
+ directories = directory.directories
87
+
88
+ # exclude root level directories which do not have drafts
89
+ if params["splat"].first.empty?
90
+ directories = directories.select do |d|
91
+ relevant_directory_paths.include? d.name.to_s
92
+ end
93
+ end
94
+ # merge directories with the drafts at the same level
95
+ directories.concat(reverse_sorted_drafts)
96
+ end
97
+
98
+ def html_content?
99
+ draft = JekyllAdmin::PageWithoutAFile.new(
100
+ site,
101
+ site.source,
102
+ "_drafts",
103
+ request_payload["path"] || filename
104
+ )
105
+ draft.data = request_payload["front_matter"]
106
+ draft.html?
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,90 @@
1
+ module JekyllAdmin
2
+ class Server < Sinatra::Base
3
+ namespace "/pages" do
4
+ get "/*?/?:path.:ext" do
5
+ ensure_requested_file
6
+ json requested_file.to_api(:include_content => true)
7
+ end
8
+
9
+ get "/?*" do
10
+ ensure_directory
11
+ json entries.map(&:to_api)
12
+ end
13
+
14
+ put "/*?/?:path.:ext" do
15
+ ensure_html_content
16
+
17
+ if renamed?
18
+ ensure_requested_file
19
+ delete_file path
20
+ end
21
+
22
+ write_file write_path, page_body
23
+
24
+ json written_file.to_api(:include_content => true)
25
+ end
26
+
27
+ delete "/*?/?:path.:ext" do
28
+ ensure_requested_file
29
+ delete_file path
30
+ content_type :json
31
+ status 200
32
+ halt
33
+ end
34
+
35
+ private
36
+
37
+ def ensure_html_content
38
+ return if html_content?
39
+ content_type :json
40
+ halt 422, json("error_message" => "Invalid file extension for pages")
41
+ end
42
+
43
+ def html_content?
44
+ page = JekyllAdmin::PageWithoutAFile.new(
45
+ site,
46
+ site.source,
47
+ "",
48
+ request_payload["path"] || filename
49
+ )
50
+ page.data = request_payload["front_matter"]
51
+ page.html?
52
+ end
53
+
54
+ def pages
55
+ site.pages.select(&:html?)
56
+ end
57
+
58
+ def directory_pages
59
+ pages.find_all do |p|
60
+ sanitized_path(File.dirname(p.path)) == directory_path
61
+ end
62
+ end
63
+
64
+ # returns relative path of root level directories that contain pages
65
+ def directory_paths
66
+ pages.map { |p| File.dirname(p.path).split("/")[0] }.uniq
67
+ end
68
+
69
+ def entries
70
+ args = {
71
+ :base => site.source,
72
+ :content_type => "pages",
73
+ :splat => params["splat"].first,
74
+ }
75
+ # get all directories inside the requested directory
76
+ directory = JekyllAdmin::Directory.new(directory_path, args)
77
+ directories = directory.directories
78
+
79
+ # exclude root level directories which do not have pages
80
+ if params["splat"].first.empty?
81
+ directories = directories.select do |d|
82
+ directory_paths.include? d.name.to_s
83
+ end
84
+ end
85
+ # merge directories with the pages at the same level
86
+ directories.concat(directory_pages)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,82 @@
1
+ module JekyllAdmin
2
+ class Server < Sinatra::Base
3
+ namespace "/static_files" do
4
+ get "/index" do
5
+ json site.static_files.map(&:to_api)
6
+ end
7
+
8
+ get "/?*" do
9
+ render_404 unless File.exist?(path)
10
+ if requested_file
11
+ json requested_file.to_api(:include_content => true)
12
+ else
13
+ json entries.map(&:to_api)
14
+ end
15
+ end
16
+
17
+ put "/*" do
18
+ if renamed?
19
+ ensure_requested_file
20
+ delete_file path
21
+ end
22
+
23
+ write_file(write_path, static_file_body)
24
+ json written_file.to_api(:include_content => true)
25
+ end
26
+
27
+ delete "/*" do
28
+ ensure_requested_file
29
+ delete_file path
30
+ content_type :json
31
+ status 200
32
+ halt
33
+ end
34
+
35
+ private
36
+
37
+ # returns relative path of root level directories that contain static files
38
+ def directory_names
39
+ static_files.map do |f|
40
+ File.dirname(f.path.sub("#{site.source}/", "")).split("/")[0]
41
+ end.uniq
42
+ end
43
+
44
+ def directory_files
45
+ static_files.find_all do |p|
46
+ sanitized_path(File.dirname(p.path)) == directory_path
47
+ end
48
+ end
49
+
50
+ def entries
51
+ args = {
52
+ :base => site.source,
53
+ :content_type => "static_files",
54
+ :splat => params["splat"].first,
55
+ }
56
+ # get all directories inside the requested directory
57
+ directory = JekyllAdmin::Directory.new(directory_path, args)
58
+ directories = directory.directories
59
+
60
+ # exclude root level directories which do not have static files
61
+ if params["splat"].first.empty?
62
+ directories = directories.select do |d|
63
+ directory_names.include? d.name.to_s
64
+ end
65
+ end
66
+ directories.concat(directory_files)
67
+ end
68
+
69
+ def static_file_body
70
+ if !request_payload["raw_content"].to_s.empty?
71
+ request_payload["raw_content"].to_s
72
+ else
73
+ Base64.decode64 request_payload["encoded_content"].to_s
74
+ end
75
+ end
76
+
77
+ def static_files
78
+ site.static_files.select { |f| f.path.start_with? site.source }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,196 @@
1
+ module JekyllAdmin
2
+ class Server < Sinatra::Base
3
+ namespace "/templates" do
4
+ get "/?" do
5
+ json template_directories.map(&:to_api)
6
+ end
7
+
8
+ get "/*?/?:path.:ext" do
9
+ ensure_requested_file
10
+ api_hash = {
11
+ :name => filename,
12
+ :path => written_path,
13
+ :http_url => http_url,
14
+ :api_url => url,
15
+ :has_front_matter => front_matter?(written_path),
16
+ :front_matter => front_matter,
17
+ :raw_content => raw_content,
18
+ }
19
+ api_hash.merge!(front_matter) if front_matter
20
+ json api_hash
21
+ end
22
+
23
+ get "/?*" do
24
+ ensure_directory
25
+ json dirs.reject { |dir| page_entries_in(dir).empty? }
26
+ .map(&:to_api)
27
+ .concat(subdir_entries)
28
+ end
29
+
30
+ put "/*?/?:path.:ext" do
31
+ if renamed?
32
+ ensure_requested_file
33
+ delete_file path
34
+ end
35
+
36
+ write_file write_path, template_body
37
+ json({
38
+ :name => filename,
39
+ :path => written_path,
40
+ :raw_content => request_payload["raw_content"],
41
+ :http_url => http_url,
42
+ :api_url => url,
43
+ :has_front_matter => write_front_matter?,
44
+ }.merge!(payload_front_matter))
45
+ end
46
+
47
+ delete "/*?/?:path.:ext" do
48
+ ensure_requested_file
49
+ delete_file path
50
+ content_type :json
51
+ status 200
52
+ halt
53
+ end
54
+
55
+ private
56
+
57
+ def source_dir(dir = "")
58
+ site.in_source_dir(dir)
59
+ end
60
+
61
+ def requested_file
62
+ @requested_file = path
63
+ end
64
+
65
+ def dirs
66
+ args = {
67
+ :base => site.source,
68
+ :content_type => "templates",
69
+ :splat => splats.first,
70
+ }
71
+ Directory.new(directory_path, args).directories
72
+ end
73
+
74
+ def template_directories
75
+ regex = %r!(assets|_(includes|layouts|sass))!
76
+ dirs.find_all do |f|
77
+ f.name.to_s =~ regex
78
+ end.sort_by!(&:name)
79
+ end
80
+
81
+ def subdir_entries
82
+ Dir["#{directory_path}/*"]
83
+ .reject { |e| File.directory?(e) }
84
+ .reject { |f| site.static_files.map(&:path).include?(f) }
85
+ .map! do |e|
86
+ {
87
+ :name => File.basename(e),
88
+ :path => sanitized_relative_path(e).sub("/#{splats.first}/", ""),
89
+ :http_url => http_url(e),
90
+ :api_url => api_url(e),
91
+ }
92
+ end
93
+ end
94
+
95
+ def front_matter?(file)
96
+ file_path = sanitized_path(file)
97
+ if file_contents(file_path) =~ Jekyll::Document::YAML_FRONT_MATTER_REGEXP
98
+ true
99
+ else
100
+ false
101
+ end
102
+ end
103
+
104
+ def write_front_matter?
105
+ return false unless request_payload["front_matter"]
106
+ true
107
+ end
108
+
109
+ def front_matter
110
+ @front_matter ||= if file_contents =~ Jekyll::Document::YAML_FRONT_MATTER_REGEXP
111
+ SafeYAML.load(Regexp.last_match(1))
112
+ else
113
+ {}
114
+ end
115
+ end
116
+
117
+ def raw_content
118
+ @raw_content ||= if file_contents =~ Jekyll::Document::YAML_FRONT_MATTER_REGEXP
119
+ $POSTMATCH
120
+ else
121
+ file_contents
122
+ end
123
+ end
124
+
125
+ def payload_front_matter
126
+ request_payload["front_matter"] || {}
127
+ end
128
+
129
+ def written_path
130
+ renamed? ? request_payload["path"] : relative_write_path.sub("/", "")
131
+ end
132
+
133
+ def page_body
134
+ body = if payload_front_matter && !payload_front_matter.empty?
135
+ YAML.dump(payload_front_matter).strip
136
+ else
137
+ "---"
138
+ end
139
+ body << "\n---\n\n"
140
+ body << request_payload["raw_content"].to_s
141
+ body << "\n"
142
+ end
143
+
144
+ def template_body
145
+ if request_payload["front_matter"]
146
+ page_body
147
+ else
148
+ body = request_payload["raw_content"].to_s
149
+ body << "\n"
150
+ end
151
+ end
152
+
153
+ def directory_path
154
+ source_dir(splats.first)
155
+ end
156
+
157
+ def splats
158
+ params["splat"] || ["/"]
159
+ end
160
+
161
+ def api_url(entry)
162
+ File.join(base_url, "_api", "templates", sanitized_relative_path(entry))
163
+ end
164
+
165
+ def http_url(entry = requested_file)
166
+ if splats.first.include?("assets") && !Jekyll::Utils.has_yaml_header?(entry)
167
+ File.join(base_url, sanitized_relative_path(entry))
168
+ end
169
+ end
170
+
171
+ def ensure_requested_file
172
+ render_404 unless File.exist?(requested_file)
173
+ end
174
+
175
+ def file_contents(file = requested_file)
176
+ @file_contents ||= File.read(
177
+ file, Jekyll::Utils.merged_file_read_opts(site, {})
178
+ )
179
+ end
180
+
181
+ def page_entries_in(dir)
182
+ dir.path.children.select do |entry|
183
+ front_matter?(entry) || in_sass_dir?(entry)
184
+ end
185
+ end
186
+
187
+ # Jekyll does not consider files without front matter, within `_sass`
188
+ # to be 'static files' as of Jekyll 3.5.x, ergo they should be
189
+ # editable via the admin interface.
190
+ def in_sass_dir?(entry)
191
+ parent_dir = File.dirname(File.dirname(entry)).sub(source_dir, "")
192
+ parent_dir == "_sass"
193
+ end
194
+ end
195
+ end
196
+ end