block_editor 0.1.0
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 +147 -0
- data/Rakefile +18 -0
- data/app/assets/config/block_editor_manifest.js +1 -0
- data/app/assets/stylesheets/block_editor/backend.scss +4 -0
- data/app/assets/stylesheets/block_editor/backend/blocks.scss +0 -0
- data/app/assets/stylesheets/block_editor/frontend.scss +1 -0
- data/app/assets/stylesheets/block_editor/frontend/blocks.scss +0 -0
- data/app/controllers/block_editor/application_controller.rb +4 -0
- data/app/helpers/block_editor/application_helper.rb +11 -0
- data/app/javascript/block_editor/blocks/button/edit.js +240 -0
- data/app/javascript/block_editor/blocks/column/edit.js +93 -0
- data/app/javascript/block_editor/blocks/image/edit.js +656 -0
- data/app/javascript/block_editor/blocks/index.js +263 -0
- data/app/javascript/block_editor/components/block-editor/index.js +88 -0
- data/app/javascript/block_editor/components/block-editor/styles.scss +39 -0
- data/app/javascript/block_editor/components/header/index.js +45 -0
- data/app/javascript/block_editor/components/header/redo.js +36 -0
- data/app/javascript/block_editor/components/header/styles.scss +14 -0
- data/app/javascript/block_editor/components/header/undo.js +36 -0
- data/app/javascript/block_editor/components/media-upload/index.js +37 -0
- data/app/javascript/block_editor/components/notices/index.js +26 -0
- data/app/javascript/block_editor/components/notices/styles.scss +9 -0
- data/app/javascript/block_editor/components/sidebar/index.js +31 -0
- data/app/javascript/block_editor/components/sidebar/styles.scss +43 -0
- data/app/javascript/block_editor/stores/action-types.js +4 -0
- data/app/javascript/block_editor/stores/actions.js +41 -0
- data/app/javascript/block_editor/stores/controls.js +21 -0
- data/app/javascript/block_editor/stores/index.js +30 -0
- data/app/javascript/block_editor/stores/reducer.js +20 -0
- data/app/javascript/block_editor/stores/resolvers.js +10 -0
- data/app/javascript/block_editor/stores/selectors.js +13 -0
- data/app/javascript/controllers/block_editor_controller.jsx +42 -0
- data/app/javascript/controllers/index.js +6 -0
- data/app/javascript/packs/block_editor/application.js +2 -0
- data/app/javascript/packs/block_editor/application.scss +108 -0
- data/app/jobs/block_editor/application_job.rb +4 -0
- data/app/mailers/block_editor/application_mailer.rb +6 -0
- data/app/models/block_editor/application_record.rb +5 -0
- data/app/models/block_editor/block_list.rb +7 -0
- data/app/models/concerns/block_editor/listable.rb +24 -0
- data/app/views/layouts/block_editor/application.html.erb +15 -0
- data/config/initializers/webpacker_extension.rb +12 -0
- data/config/routes.rb +2 -0
- data/config/webpack/development.js +5 -0
- data/config/webpack/environment.js +3 -0
- data/config/webpack/production.js +5 -0
- data/config/webpack/test.js +5 -0
- data/config/webpacker.yml +92 -0
- data/db/migrate/20210312032114_create_block_lists.rb +11 -0
- data/lib/block_editor.rb +26 -0
- data/lib/block_editor/block_list_renderer.rb +43 -0
- data/lib/block_editor/blocks/base.rb +32 -0
- data/lib/block_editor/engine.rb +34 -0
- data/lib/block_editor/instance.rb +19 -0
- data/lib/block_editor/version.rb +3 -0
- data/lib/tasks/block_editor_tasks.rake +59 -0
- metadata +131 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module BlockEditor
|
2
|
+
module Listable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :block_lists, as: :listable, class_name: 'BlockEditor::BlockList'
|
7
|
+
has_one :active_block_list, -> { where active: true }, class_name: 'BlockEditor::BlockList', as: :listable
|
8
|
+
|
9
|
+
validates :active_block_list, presence: true
|
10
|
+
|
11
|
+
accepts_nested_attributes_for :active_block_list
|
12
|
+
|
13
|
+
after_initialize :set_block_list_defaults
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def set_block_list_defaults
|
19
|
+
return if self.persisted?
|
20
|
+
|
21
|
+
self.active_block_list ||= self.build_active_block_list(listable: self)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Webpacker::DynamicTag
|
2
|
+
def javascript_pack_tag(*names, **options)
|
3
|
+
return super unless options[:webpacker]
|
4
|
+
new_helper = self.dup
|
5
|
+
new_helper.define_singleton_method(:current_webpacker_instance) do
|
6
|
+
options[:webpacker].constantize.webpacker
|
7
|
+
end
|
8
|
+
new_helper.javascript_pack_tag(*names, **options.except(:webpacker))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Webpacker::Helper.prepend Webpacker::DynamicTag
|
data/config/routes.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Note: You must restart bin/webpack-dev-server for changes to take effect
|
2
|
+
|
3
|
+
default: &default
|
4
|
+
source_path: app/javascript
|
5
|
+
source_entry_path: packs
|
6
|
+
public_root_path: public
|
7
|
+
public_output_path: packs
|
8
|
+
cache_path: tmp/cache/webpacker
|
9
|
+
webpack_compile_output: true
|
10
|
+
|
11
|
+
# Additional paths webpack should lookup modules
|
12
|
+
# ['app/assets', 'engine/foo/app/assets']
|
13
|
+
additional_paths: []
|
14
|
+
|
15
|
+
# Reload manifest.json on all requests so we reload latest compiled packs
|
16
|
+
cache_manifest: false
|
17
|
+
|
18
|
+
# Extract and emit a css file
|
19
|
+
extract_css: false
|
20
|
+
|
21
|
+
static_assets_extensions:
|
22
|
+
- .jpg
|
23
|
+
- .jpeg
|
24
|
+
- .png
|
25
|
+
- .gif
|
26
|
+
- .tiff
|
27
|
+
- .ico
|
28
|
+
- .svg
|
29
|
+
- .eot
|
30
|
+
- .otf
|
31
|
+
- .ttf
|
32
|
+
- .woff
|
33
|
+
- .woff2
|
34
|
+
|
35
|
+
extensions:
|
36
|
+
- .mjs
|
37
|
+
- .js
|
38
|
+
- .sass
|
39
|
+
- .scss
|
40
|
+
- .css
|
41
|
+
- .module.sass
|
42
|
+
- .module.scss
|
43
|
+
- .module.css
|
44
|
+
- .png
|
45
|
+
- .svg
|
46
|
+
- .gif
|
47
|
+
- .jpeg
|
48
|
+
- .jpg
|
49
|
+
|
50
|
+
development:
|
51
|
+
<<: *default
|
52
|
+
compile: true
|
53
|
+
|
54
|
+
# Reference: https://webpack.js.org/configuration/dev-server/
|
55
|
+
dev_server:
|
56
|
+
https: false
|
57
|
+
host: localhost
|
58
|
+
port: 3035
|
59
|
+
public: localhost:3035
|
60
|
+
hmr: false
|
61
|
+
# Inline should be set to true if using HMR
|
62
|
+
inline: true
|
63
|
+
overlay: true
|
64
|
+
compress: true
|
65
|
+
disable_host_check: true
|
66
|
+
use_local_ip: false
|
67
|
+
quiet: false
|
68
|
+
pretty: false
|
69
|
+
headers:
|
70
|
+
'Access-Control-Allow-Origin': '*'
|
71
|
+
watch_options:
|
72
|
+
ignored: '**/node_modules/**'
|
73
|
+
|
74
|
+
|
75
|
+
test:
|
76
|
+
<<: *default
|
77
|
+
compile: true
|
78
|
+
|
79
|
+
# Compile test packs to a separate directory
|
80
|
+
public_output_path: packs-test
|
81
|
+
|
82
|
+
production:
|
83
|
+
<<: *default
|
84
|
+
|
85
|
+
# Production depends on precompilation of packs prior to booting for performance.
|
86
|
+
compile: false
|
87
|
+
|
88
|
+
# Extract and emit a css file
|
89
|
+
extract_css: true
|
90
|
+
|
91
|
+
# Cache manifest.json for performance
|
92
|
+
cache_manifest: true
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateBlockLists < ActiveRecord::Migration[6.1]
|
2
|
+
def change
|
3
|
+
create_table :block_editor_block_lists do |t|
|
4
|
+
t.string :name
|
5
|
+
t.text :content
|
6
|
+
t.boolean :active, default: false
|
7
|
+
t.references :listable, polymorphic: true
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/block_editor.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "block_editor/version"
|
2
|
+
require "block_editor/engine"
|
3
|
+
|
4
|
+
require "block_editor/instance"
|
5
|
+
require 'block_editor/blocks/base'
|
6
|
+
require 'block_editor/block_list_renderer'
|
7
|
+
|
8
|
+
module BlockEditor
|
9
|
+
ROOT_PATH = Pathname.new(File.join(__dir__, ".."))
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def webpacker
|
13
|
+
@webpacker ||= ::Webpacker::Instance.new(
|
14
|
+
root_path: ROOT_PATH,
|
15
|
+
config_path: ROOT_PATH.join("config/webpacker.yml")
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
mattr_accessor :dynamic_blocks
|
21
|
+
@@dynamic_blocks = []
|
22
|
+
|
23
|
+
mattr_accessor :frontend_parent_controller
|
24
|
+
@@frontend_parent_controller = 'ApplicationController'
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module BlockEditor
|
2
|
+
# Handles the rendering of a block list including dynamic blocks and removing HTML comments
|
3
|
+
class BlockListRenderer
|
4
|
+
# Renders dynamic blocks within the HTML snippet then strips all HTML comments (including Gutenberg markup)
|
5
|
+
#
|
6
|
+
# @param raw_html [String]
|
7
|
+
#
|
8
|
+
# @return [String] Parsed content
|
9
|
+
def self.render(raw_html)
|
10
|
+
html = Nokogiri::HTML(raw_html)
|
11
|
+
|
12
|
+
# # Find & render all instances of a dynamic block
|
13
|
+
BlockEditor.dynamic_blocks.each do |dynamic_block|
|
14
|
+
html.xpath('//comment()').select {|comment| comment.inner_text.starts_with?(" wp:#{dynamic_block.name}") }.each do |block_instance|
|
15
|
+
block_attributes = block_instance.inner_text.split(" wp:#{dynamic_block.name}")[1][0...-1]
|
16
|
+
block_attributes = block_attributes.blank? ? {} : JSON.parse(block_attributes)
|
17
|
+
block_instance.replace(render_block(dynamic_block, block_attributes))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
html.xpath('//comment()').remove
|
22
|
+
html.css('body').inner_html.html_safe
|
23
|
+
end
|
24
|
+
|
25
|
+
# Renders a specific block using the provided options
|
26
|
+
#
|
27
|
+
# @param block [String] name of block
|
28
|
+
# @param options [Hash] block options to use when rendering
|
29
|
+
#
|
30
|
+
# @return [String] block content (HTML)
|
31
|
+
def self.render_block(block, options)
|
32
|
+
block.render(options)
|
33
|
+
rescue StandardError => e
|
34
|
+
respond_with_block_error(e)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Handles block errors
|
38
|
+
def self.respond_with_block_error(error)
|
39
|
+
Rails.logger.error("Error rendering block - #{error.message}")
|
40
|
+
''
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module BlockEditor
|
2
|
+
# Blocks used to render dynamic content
|
3
|
+
module Blocks
|
4
|
+
# Base for dynamic blocks
|
5
|
+
class Base
|
6
|
+
def self.name
|
7
|
+
raise NotImplementedError, 'Must specify block name'
|
8
|
+
end
|
9
|
+
|
10
|
+
# Render the block
|
11
|
+
def self.render(options = {})
|
12
|
+
options = options.reverse_merge(default_options.with_indifferent_access)
|
13
|
+
|
14
|
+
controller.render(
|
15
|
+
partial: "block_editor/blocks/#{name}/block",
|
16
|
+
locals: { collection: options },
|
17
|
+
layout: false
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Frontend controller used to render views
|
22
|
+
def self.controller
|
23
|
+
BlockEditor.frontend_parent_controller.constantize
|
24
|
+
end
|
25
|
+
|
26
|
+
# Default widget options
|
27
|
+
def self.default_options
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module BlockEditor
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace BlockEditor
|
4
|
+
|
5
|
+
initializer "webpacker.proxy" do |app|
|
6
|
+
insert_middleware = begin
|
7
|
+
BlockEditor.webpacker.config.dev_server.present?
|
8
|
+
rescue
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
next unless insert_middleware
|
12
|
+
|
13
|
+
app.middleware.insert_before(
|
14
|
+
0, Webpacker::DevServerProxy,
|
15
|
+
ssl_verify_none: true,
|
16
|
+
webpacker: BlockEditor.webpacker
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Initializer to combine this engines static assets with the static assets of the host application
|
21
|
+
initializer 'static assets' do |app|
|
22
|
+
app.middleware.insert_before(::ActionDispatch::Static, ::ActionDispatch::Static, "#{root}/public")
|
23
|
+
end
|
24
|
+
|
25
|
+
initializer 'block_editor.assets.precompile' do |app|
|
26
|
+
assets_for_precompile = [
|
27
|
+
'block_editor/frontend.css',
|
28
|
+
'block_editor/backend.css'
|
29
|
+
]
|
30
|
+
|
31
|
+
app.config.assets.precompile.concat assets_for_precompile
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module BlockEditor
|
2
|
+
class Instance
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
include ActionView::Helpers::FormTagHelper
|
5
|
+
|
6
|
+
attr_accessor :output_buffer
|
7
|
+
|
8
|
+
def self.render(form_builder)
|
9
|
+
self.new.render(form_builder)
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(form_builder)
|
13
|
+
content_tag(:div, data: { controller: 'block-editor' }) do
|
14
|
+
form_builder.hidden_field(:content, data: { 'block-editor-target' => 'input' }) +
|
15
|
+
content_tag('div', nil, { class: 'block-editor', data: { 'block-editor-target' => 'output' } })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
def ensure_log_goes_to_stdout
|
2
|
+
old_logger = Webpacker.logger
|
3
|
+
Webpacker.logger = ActiveSupport::Logger.new(STDOUT)
|
4
|
+
yield
|
5
|
+
ensure
|
6
|
+
Webpacker.logger = old_logger
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
namespace :block_editor do
|
11
|
+
namespace :webpacker do
|
12
|
+
desc "Install deps with yarn"
|
13
|
+
task :yarn_install do
|
14
|
+
Dir.chdir(File.join(__dir__, "../..")) do
|
15
|
+
system "yarn install --no-progress --production"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Compile JavaScript packs using webpack for production with digests"
|
20
|
+
task compile: [:yarn_install, :environment] do
|
21
|
+
Webpacker.with_node_env("production") do
|
22
|
+
ensure_log_goes_to_stdout do
|
23
|
+
if BlockEditor.webpacker.commands.compile
|
24
|
+
# Successful compilation!
|
25
|
+
else
|
26
|
+
# Failed compilation
|
27
|
+
exit!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def yarn_install_available?
|
36
|
+
rails_major = Rails::VERSION::MAJOR
|
37
|
+
rails_minor = Rails::VERSION::MINOR
|
38
|
+
|
39
|
+
rails_major > 5 || (rails_major == 5 && rails_minor >= 1)
|
40
|
+
end
|
41
|
+
|
42
|
+
def enhance_assets_precompile
|
43
|
+
# yarn:install was added in Rails 5.1
|
44
|
+
deps = yarn_install_available? ? [] : ["block_editor:webpacker:yarn_install"]
|
45
|
+
Rake::Task["assets:precompile"].enhance(deps) do
|
46
|
+
Rake::Task["block_editor:webpacker:compile"].invoke
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Compile packs after we've compiled all other assets during precompilation
|
51
|
+
skip_webpacker_precompile = %w(no false n f).include?(ENV["WEBPACKER_PRECOMPILE"])
|
52
|
+
|
53
|
+
unless skip_webpacker_precompile
|
54
|
+
if Rake::Task.task_defined?("assets:precompile")
|
55
|
+
enhance_assets_precompile
|
56
|
+
else
|
57
|
+
Rake::Task.define_task("assets:precompile" => "block_editor:webpacker:compile")
|
58
|
+
end
|
59
|
+
end
|