j1m_admin 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +37 -0
  4. data/lib/jekyll-admin.rb +47 -0
  5. data/lib/jekyll-admin/apiable.rb +153 -0
  6. data/lib/jekyll-admin/data_file.rb +91 -0
  7. data/lib/jekyll-admin/directory.rb +68 -0
  8. data/lib/jekyll-admin/file_helper.rb +64 -0
  9. data/lib/jekyll-admin/page_without_a_file.rb +7 -0
  10. data/lib/jekyll-admin/path_helper.rb +74 -0
  11. data/lib/jekyll-admin/public/03945ac4fc7fdefc44bc110bf1ba2393.svg +18 -0
  12. data/lib/jekyll-admin/public/059514c92565e4045da1a69525dd9ec0.ttf +0 -0
  13. data/lib/jekyll-admin/public/1dc35d25e61d819a9c357074014867ab.ttf +0 -0
  14. data/lib/jekyll-admin/public/25a32416abee198dd821b0b17a198a8f.eot +0 -0
  15. data/lib/jekyll-admin/public/33a752211d05af6684e26ec63c2ed965.gif +0 -0
  16. data/lib/jekyll-admin/public/55131026930a0cd4539d1e2fdb92722d.ttf +0 -0
  17. data/lib/jekyll-admin/public/847c038a8202754b465604459e16715d.png +0 -0
  18. data/lib/jekyll-admin/public/99adb54b0f30c0758bb4cb9ed5b80aa8.woff +0 -0
  19. data/lib/jekyll-admin/public/a770b6797b68e3f8920e473eb824bac0.gif +0 -0
  20. data/lib/jekyll-admin/public/bfc14ac982326f7d0b1340e20d3e0c37.ttf +0 -0
  21. data/lib/jekyll-admin/public/bundle.js +37 -0
  22. data/lib/jekyll-admin/public/bundle.js.map +1 -0
  23. data/lib/jekyll-admin/public/c4c172d28f17a61e4476715c58640841.png +0 -0
  24. data/lib/jekyll-admin/public/c8ddf1e5e5bf3682bc7bebf30f394148.woff +0 -0
  25. data/lib/jekyll-admin/public/d7c639084f684d66a1bc66855d193ed8.svg +685 -0
  26. data/lib/jekyll-admin/public/e44520ab9079ea7633bfa874bed5d21d.eot +0 -0
  27. data/lib/jekyll-admin/public/e6cf7c6ec7c2d6f670ae9d762604cb0b.woff2 +0 -0
  28. data/lib/jekyll-admin/public/favicon.ico +0 -0
  29. data/lib/jekyll-admin/public/iframeResizer.client.js +1104 -0
  30. data/lib/jekyll-admin/public/index.html +17 -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 +91 -0
  34. data/lib/jekyll-admin/server/collection.rb +82 -0
  35. data/lib/jekyll-admin/server/configuration.rb +42 -0
  36. data/lib/jekyll-admin/server/data.rb +45 -0
  37. data/lib/jekyll-admin/server/page.rb +90 -0
  38. data/lib/jekyll-admin/server/static_file.rb +61 -0
  39. data/lib/jekyll-admin/static_server.rb +24 -0
  40. data/lib/jekyll-admin/urlable.rb +65 -0
  41. data/lib/jekyll-admin/version.rb +3 -0
  42. data/lib/jekyll/commands/build.rb +14 -0
  43. data/lib/jekyll/commands/serve.rb +24 -0
  44. metadata +229 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af474043b98047a1a147a894905fec1893b52ef9
4
+ data.tar.gz: edf51e9269eb195af0ac198066453dfc96f40642
5
+ SHA512:
6
+ metadata.gz: bf84f4b761b5b1a9b9a7b33d3fa2829aafb35e746b90a7cdf52f7ec1661e05241c6740f08a58f07104ab73ad890088ffd5a5130419be092cde0316c1d65b31b2
7
+ data.tar.gz: 452617bfb965923f42ae3b4e84ea356e13ee366a6b30e960ad9f9f3d28c38e20915f3efe0096f226fb1ab07b08ccb0333bb369e7d40f2af983a435b8645a57b3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright 2017 Mert Kahyaoğlu and the Jekyll Admin contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ [![Gem Version](https://img.shields.io/gem/v/jekyll-admin.svg)](https://rubygems.org/gems/jekyll-admin)
2
+ [![Build Status](https://travis-ci.org/jekyll/jekyll-admin.svg?branch=master)](https://travis-ci.org/jekyll/jekyll-admin)
3
+ [![Build status](https://ci.appveyor.com/api/projects/status/biop1r6ae524xlm2/branch/master?svg=true)](https://ci.appveyor.com/project/benbalter/jekyll-admin/branch/master)
4
+ [![NPM Dependencies](https://david-dm.org/jekyll/jekyll-admin.svg)](https://david-dm.org/jekyll/jekyll-admin)
5
+
6
+ A Jekyll plugin that provides users with a traditional CMS-style graphical interface to author content and administer Jekyll sites. The project is divided into two parts. A Ruby-based HTTP API that handles Jekyll and filesystem operations, and a Javascript-based front end, built on that API.
7
+
8
+ ![screenshot of Jekyll Admin](/screenshot.png)
9
+
10
+ ## Installation
11
+
12
+ Refer to the [installing plugins](https://jekyllrb.com/docs/plugins/#installing-a-plugin) section of Jekyll's documentation and install the `jekyll-admin` plugin as you would any other plugin. Here's the short version:
13
+
14
+ 1. Add the following to your site's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'jekyll-admin', group: :jekyll_plugins
18
+ ```
19
+
20
+ 2. Run `bundle install`
21
+
22
+ ## Usage
23
+
24
+ 1. Start Jekyll as you would normally (`bundle exec jekyll serve`)
25
+ 2. Navigate to `http://localhost:4000/admin` to access the administrative interface
26
+
27
+ ## Contributing
28
+
29
+ Interested in contributing to Jekyll Admin? We’d love your help. Jekyll Admin is an open source project, built one contribution at a time by users like you. See [the contributing instructions](.github/CONTRIBUTING.md), and [the development docs](http://jekyll.github.io/jekyll-admin/development/) for more information.
30
+
31
+ ## Looking for a hosted version?
32
+
33
+ Jekyll Admin is intended to be run on your computer alongside your local Jekyll installation. If you're looking for a hosted version, we'd recommend checking out [Siteleaf](https://www.siteleaf.com/) a hosted Jekyll editor with deep GitHub integration (whom we'd also like to thank for inspiring parts of Jekyll Admin itself!).
34
+
35
+ ## License
36
+
37
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,47 @@
1
+ # Default Sinatra to "production" mode (surpress errors) unless
2
+ # otherwise specified by the `RACK_ENV` environmental variable.
3
+ # Must be done prior to requiring Sinatra, or we'll get a LoadError
4
+ # as it looks for sinatra/cross-origin, which is development only
5
+ ENV["RACK_ENV"] = "production" if ENV["RACK_ENV"].to_s.empty?
6
+
7
+ require "json"
8
+ require "jekyll"
9
+ require "base64"
10
+ require "webrick"
11
+ require "sinatra"
12
+ require "fileutils"
13
+ require "sinatra/base"
14
+ require "sinatra/json"
15
+ require "addressable/uri"
16
+ require "sinatra/reloader"
17
+ require "sinatra/namespace"
18
+
19
+ module JekyllAdmin
20
+ autoload :APIable, "jekyll-admin/apiable"
21
+ autoload :DataFile, "jekyll-admin/data_file"
22
+ autoload :Directory, "jekyll-admin/directory"
23
+ autoload :FileHelper, "jekyll-admin/file_helper"
24
+ autoload :PageWithoutAFile, "jekyll-admin/page_without_a_file"
25
+ autoload :PathHelper, "jekyll-admin/path_helper"
26
+ autoload :Server, "jekyll-admin/server"
27
+ autoload :StaticServer, "jekyll-admin/static_server"
28
+ autoload :URLable, "jekyll-admin/urlable"
29
+ autoload :Version, "jekyll-admin/version"
30
+
31
+ def self.site
32
+ @site ||= begin
33
+ site = Jekyll.sites.first
34
+ site.future = true
35
+ site
36
+ end
37
+ end
38
+ end
39
+
40
+ # Monkey Patches
41
+ require_relative "./jekyll/commands/serve"
42
+ require_relative "./jekyll/commands/build"
43
+
44
+ [Jekyll::Page, Jekyll::Document, Jekyll::StaticFile, Jekyll::Collection].each do |klass|
45
+ klass.include JekyllAdmin::APIable
46
+ klass.include JekyllAdmin::URLable
47
+ end
@@ -0,0 +1,153 @@
1
+ module JekyllAdmin
2
+ # Abstract module to be included in Convertible and Document to provide
3
+ # additional, API-specific functionality without duplicating logic
4
+ module APIable
5
+
6
+ CONTENT_FIELDS = %w(next previous content excerpt).freeze
7
+
8
+ # Returns a hash suitable for use as an API response.
9
+ #
10
+ # For Documents and Pages:
11
+ #
12
+ # 1. Adds the file's raw content to the `raw_content` field
13
+ # 2. Adds the file's raw YAML front matter to the `front_matter` field
14
+ #
15
+ # For Static Files it addes the Base64 `encoded_content` field
16
+ #
17
+ # Options:
18
+ #
19
+ # include_content - if true, includes the content in the respond, false by default
20
+ # to support mapping on indexes where we only want metadata
21
+ #
22
+ #
23
+ # Returns a hash (which can then be to_json'd)
24
+ def to_api(include_content: false)
25
+ output = hash_for_api
26
+ output = output.merge(url_fields)
27
+
28
+ # Include content, if requested, otherwise remove it
29
+ if include_content
30
+ output = output.merge(content_fields)
31
+ else
32
+ CONTENT_FIELDS.each { |field| output.delete(field) }
33
+ end
34
+
35
+ # Documents have duplicate output and content fields, Pages do not
36
+ # Since it's an API, use `content` in both for consistency
37
+ output.delete("output")
38
+
39
+ # By default, calling to_liquid on a collection will return a docs
40
+ # array with each rendered document, which we don't want.
41
+ if is_a?(Jekyll::Collection)
42
+ output.delete("docs")
43
+ output["entries_url"] = entries_url
44
+ end
45
+
46
+ if is_a?(Jekyll::Document)
47
+ output["name"] = basename
48
+ end
49
+
50
+ output
51
+ end
52
+
53
+ private
54
+
55
+ # Pages don't have a hash method, but Documents do
56
+ def file_path
57
+ if is_a?(Jekyll::Document)
58
+ path
59
+ else
60
+ File.join(@base, @dir, name)
61
+ end
62
+ end
63
+
64
+ # StaticFiles don't have `attr_accesor` set for @site or @name
65
+ def site
66
+ @site
67
+ end
68
+
69
+ def name
70
+ @name
71
+ end
72
+
73
+ def file_contents
74
+ @file_contents ||= File.read(file_path, file_read_options) if file_exists?
75
+ end
76
+
77
+ def file_read_options
78
+ Jekyll::Utils.merged_file_read_opts(site, {})
79
+ end
80
+
81
+ def front_matter
82
+ return unless file_exists?
83
+ @front_matter ||= if file_contents =~ Jekyll::Document::YAML_FRONT_MATTER_REGEXP
84
+ SafeYAML.load(Regexp.last_match(1))
85
+ else
86
+ {}
87
+ end
88
+ end
89
+
90
+ def raw_content
91
+ return unless file_exists?
92
+ @raw_content ||= if file_contents =~ Jekyll::Document::YAML_FRONT_MATTER_REGEXP
93
+ $POSTMATCH
94
+ else
95
+ file_contents
96
+ end
97
+ end
98
+
99
+ def encoded_content
100
+ @encoded_content ||= Base64.encode64(file_contents) if file_exists?
101
+ end
102
+
103
+ def file_exists?
104
+ return @file_exists if defined? @file_exists
105
+ @file_exists = File.exist?(file_path)
106
+ end
107
+
108
+ # Base hash from which to generate the API output
109
+ def hash_for_api
110
+ output = to_liquid
111
+ if output.respond_to?(:hash_for_json)
112
+ output.hash_for_json
113
+ else
114
+ output.to_h
115
+ end
116
+ end
117
+
118
+ # Returns a hash of content fields for inclusion in the API output
119
+ def content_fields
120
+ output = {}
121
+
122
+ # Include file content-related fields
123
+ if is_a?(Jekyll::StaticFile)
124
+ output["encoded_content"] = encoded_content
125
+ elsif is_a?(JekyllAdmin::DataFile)
126
+ output["content"] = content
127
+ output["raw_content"] = raw_content
128
+ else
129
+ output["raw_content"] = raw_content
130
+ output["front_matter"] = front_matter
131
+ end
132
+
133
+ # Include next and previous documents non-recursively
134
+ if is_a?(Jekyll::Document)
135
+ %w(next previous).each do |direction|
136
+ method = "#{direction}_doc".to_sym
137
+ doc = public_send(method)
138
+ output[direction] = doc.to_api if doc
139
+ end
140
+ end
141
+
142
+ output
143
+ end
144
+
145
+ def url_fields
146
+ return {} unless respond_to?(:http_url) && respond_to?(:api_url)
147
+ {
148
+ "http_url" => http_url,
149
+ "api_url" => api_url,
150
+ }
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,91 @@
1
+ module JekyllAdmin
2
+ class DataFile
3
+ METHODS_FOR_LIQUID = %w(path relative_path slug ext title).freeze
4
+ EXTENSIONS = %w(yaml yml json csv).freeze
5
+
6
+ include APIable
7
+ include URLable
8
+ include PathHelper
9
+ extend PathHelper
10
+
11
+ alias_method :path, :relative_path
12
+
13
+ # Initialize a new DataFile object
14
+ #
15
+ # id - the file ID as passed from the API. This may or may not have an extension
16
+ def initialize(id)
17
+ @id ||= id
18
+ end
19
+
20
+ def exists?
21
+ @exists ||= File.exist?(absolute_path)
22
+ end
23
+
24
+ # Returns unparsed content as it exists on disk
25
+ def raw_content
26
+ @raw_content ||= File.open(absolute_path, "r:UTF-8", &:read)
27
+ end
28
+
29
+ # Returnes (re)parsed content using Jekyll's native parsing mechanism
30
+ def content
31
+ @content ||= data_reader.read_data_file(absolute_path)
32
+ end
33
+
34
+ # Returns the file's extension with preceeding `.`
35
+ def ext
36
+ @ext ||= if File.extname(@id).to_s.empty?
37
+ ".yml"
38
+ else
39
+ File.extname(@id)
40
+ end
41
+ end
42
+ alias_method :extension, :ext
43
+
44
+ # Returns the file's sanitized slug (as used in `site.data[slug]`)
45
+ def slug
46
+ @slug ||= data_reader.sanitize_filename(basename)
47
+ end
48
+
49
+ # Returns the human-readable title of the data file
50
+ def title
51
+ @title ||= Jekyll::Utils.titleize_slug(slug.tr("_", "-"))
52
+ end
53
+
54
+ # Mimics Jekyll's native to_liquid functionality by returning a hash
55
+ # of data file metadata
56
+ def to_liquid
57
+ @to_liquid ||= METHODS_FOR_LIQUID.map { |key| [key, public_send(key)] }.to_h
58
+ end
59
+
60
+ def self.all
61
+ data_dir = sanitized_path DataFile.data_dir
62
+ Dir["#{data_dir}/*.{#{EXTENSIONS.join(",")}}"].map do |path|
63
+ new path_without_site_source(path)
64
+ end
65
+ end
66
+
67
+ # Relative path to data directory within site source
68
+ def self.data_dir
69
+ JekyllAdmin.site.config["data_dir"]
70
+ end
71
+
72
+ private
73
+
74
+ def data_reader
75
+ @data_reader = Jekyll::DataReader.new(JekyllAdmin.site)
76
+ end
77
+
78
+ def basename
79
+ @basename ||= File.basename(@id, ".*")
80
+ end
81
+
82
+ def basename_with_extension
83
+ [basename, extension].join
84
+ end
85
+ alias_method :filename, :basename_with_extension
86
+
87
+ def namespace
88
+ "data"
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,68 @@
1
+ module JekyllAdmin
2
+ class Directory
3
+ extend Forwardable
4
+ def_delegator :@path, :basename, :name
5
+ def_delegator :@path, :mtime, :modified_time
6
+ attr_reader :path, :splat, :content_type, :base
7
+
8
+ include Enumerable
9
+ include JekyllAdmin::URLable
10
+ include JekyllAdmin::APIable
11
+
12
+ TYPE = :directory
13
+
14
+ # Arguments:
15
+ #
16
+ # path - full path of the directory which its entries will be listed
17
+ #
18
+ # base - passes site.source to generate `relative_path` needed for `to_api`
19
+ #
20
+ # content_type - type of the requested directory entries, this is used to generate
21
+ # API endpoint of the directory along with `splat`
22
+ #
23
+ # splat - the requested directory path relative to content namespace
24
+ def initialize(path, base: nil, content_type: nil, splat: nil)
25
+ @base = Pathname.new base
26
+ @content_type = content_type
27
+ @splat = Pathname.new splat
28
+ @path = Pathname.new path
29
+ end
30
+
31
+ def to_liquid
32
+ {
33
+ :name => name,
34
+ :modified_time => modified_time,
35
+ :path => relative_path,
36
+ :type => TYPE,
37
+ }
38
+ end
39
+
40
+ def relative_path
41
+ path.relative_path_from(base).to_s
42
+ end
43
+
44
+ def resource_path
45
+ if content_type == "pages"
46
+ "/pages/#{splat}/#{name}"
47
+ else
48
+ "/collections/#{content_type}/entries/#{splat}/#{name}"
49
+ end
50
+ end
51
+ alias_method :url, :resource_path
52
+
53
+ def http_url
54
+ nil
55
+ end
56
+
57
+ def directories
58
+ path.entries.map do |entry|
59
+ next if [".", ".."].include? entry.to_s
60
+ next unless path.join(entry).directory?
61
+ self.class.new(
62
+ path.join(entry),
63
+ :base => base, :content_type => content_type, :splat => splat
64
+ )
65
+ end.compact!
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,64 @@
1
+ module JekyllAdmin
2
+ module FileHelper
3
+
4
+ # The file the user requested in the URL
5
+ def requested_file
6
+ find_by_path(path)
7
+ end
8
+
9
+ # The file ultimately written to disk
10
+ # This may be the requested file, or in the case of a rename will be read
11
+ # from the new path that was actually written to disk
12
+ def written_file
13
+ find_by_path(write_path)
14
+ end
15
+
16
+ # Write a file to disk with the given content
17
+ def write_file(path, content)
18
+ Jekyll.logger.debug "WRITING:", path
19
+ path = sanitized_path(path)
20
+ FileUtils.mkdir_p File.dirname(path)
21
+ File.write(path, content)
22
+ site.process
23
+ end
24
+
25
+ # Delete the file at the given path
26
+ def delete_file(path)
27
+ Jekyll.logger.debug "DELETING:", path
28
+ FileUtils.rm_f sanitized_path(path)
29
+ site.process
30
+ end
31
+
32
+ private
33
+
34
+ def ensure_requested_file
35
+ ensure_file(requested_file)
36
+ end
37
+
38
+ def ensure_written_file
39
+ ensure_file(written_file)
40
+ end
41
+
42
+ def find_by_path(path)
43
+ files = case namespace
44
+ when "collections"
45
+ collection.docs
46
+ when "data"
47
+ DataFile.all
48
+ when "pages", "static_files"
49
+ site.public_send(namespace.to_sym)
50
+ else
51
+ []
52
+ end
53
+ files.find { |f| sanitized_path(f.path) == path }
54
+ end
55
+
56
+ def ensure_file(file)
57
+ render_404 if file.nil?
58
+ end
59
+
60
+ def ensure_directory
61
+ render_404 unless Dir.exist?(directory_path)
62
+ end
63
+ end
64
+ end