jekyll-manager 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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