embeddable_content 0.1.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +62 -0
- data/.ruby-version +1 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +49 -0
- data/Rakefile +22 -0
- data/app/assets/config/embeddable_content_manifest.js +0 -0
- data/app/assets/images/embeddable_content/.keep +0 -0
- data/app/assets/javascripts/desmos/support.js +12 -0
- data/app/assets/javascripts/geogebra/support.js +14 -0
- data/app/assets/stylesheets/embeddable_content/.keep +0 -0
- data/app/controllers/.keep +0 -0
- data/app/controllers/concerns/cms/embeddable_content_controller.rb +14 -0
- data/app/controllers/concerns/embeddable_content_controller.rb +85 -0
- data/app/helpers/.keep +0 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/models/concerns/provides_embeddable_content.rb +59 -0
- data/app/models/embeddable_model_config.rb +55 -0
- data/app/models/embedder_config.rb +45 -0
- data/app/models/embedding.rb +25 -0
- data/app/services/embeddable_content/desmos_files/doc_processor.rb +5 -0
- data/app/services/embeddable_content/desmos_files/node_processor.rb +7 -0
- data/app/services/embeddable_content/doc_processor.rb +63 -0
- data/app/services/embeddable_content/embedded_tag_info.rb +50 -0
- data/app/services/embeddable_content/embedded_tags.rb +30 -0
- data/app/services/embeddable_content/embedder.rb +89 -0
- data/app/services/embeddable_content/embedder_base.rb +68 -0
- data/app/services/embeddable_content/fragment_embedder.rb +30 -0
- data/app/services/embeddable_content/geogebra_files/doc_processor.rb +5 -0
- data/app/services/embeddable_content/geogebra_files/node_processor.rb +11 -0
- data/app/services/embeddable_content/html_tags/doc_processor.rb +11 -0
- data/app/services/embeddable_content/html_tags/node_processor.rb +26 -0
- data/app/services/embeddable_content/images/attributions_processor.rb +60 -0
- data/app/services/embeddable_content/images/doc_processor.rb +54 -0
- data/app/services/embeddable_content/images/image_downloader.rb +60 -0
- data/app/services/embeddable_content/images/img_tag_attributes.rb +125 -0
- data/app/services/embeddable_content/images/modal_dialog.rb +74 -0
- data/app/services/embeddable_content/images/node_processor.rb +91 -0
- data/app/services/embeddable_content/images/shared.rb +11 -0
- data/app/services/embeddable_content/node_processor.rb +75 -0
- data/app/services/embeddable_content/presentation_tags/doc_processor.rb +5 -0
- data/app/services/embeddable_content/presentation_tags/node_processor.rb +35 -0
- data/app/services/embeddable_content/record_node_processor.rb +90 -0
- data/app/services/embeddable_content/replacement_template_manager.rb +21 -0
- data/app/services/embeddable_content/sad_embedded_tags.rb +29 -0
- data/app/services/embeddable_content/scrubber.rb +32 -0
- data/app/services/embeddable_content/template_based.rb +19 -0
- data/app/services/embeddable_content/template_manager.rb +100 -0
- data/app/services/embeddable_content/tex/base_renderer.rb +33 -0
- data/app/services/embeddable_content/tex/canvas_renderer.rb +15 -0
- data/app/services/embeddable_content/tex/doc_processor.rb +55 -0
- data/app/services/embeddable_content/tex/mathjax_renderer.rb +11 -0
- data/app/services/embeddable_content/tex/mml_renderer.rb +11 -0
- data/app/services/embeddable_content/tex/schoology_string_renderer.rb +15 -0
- data/app/services/embeddable_content/tex/svg_renderer.rb +11 -0
- data/app/services/embeddable_content/token_replacement_map.rb +32 -0
- data/app/services/embeddable_content/tree_based_node_processor.rb +23 -0
- data/app/services/embeddable_content/video_links/doc_processor.rb +5 -0
- data/app/services/embeddable_content/video_links/node_processor.rb +46 -0
- data/app/services/embeddable_content/video_links/vimeo_player_settings.rb +19 -0
- data/app/services/embeddable_content/visual_element_node_processor.rb +13 -0
- data/app/services/embeddable_content/widget_files/doc_processor.rb +5 -0
- data/app/services/embeddable_content/widget_files/node_processor.rb +7 -0
- data/app/views/.keep +0 -0
- data/app/views/embeddable_content/replacements/desmos_files/_applet.html.slim +8 -0
- data/app/views/embeddable_content/replacements/desmos_files/_description.html.slim +6 -0
- data/app/views/embeddable_content/replacements/desmos_files/cc.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/cms.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/editable.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/exported.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/kiddom.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/print.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/qti.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/schoology.html.slim +1 -0
- data/app/views/embeddable_content/replacements/desmos_files/web.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/_applet.html.slim +11 -0
- data/app/views/embeddable_content/replacements/geogebra_files/_description.html.slim +9 -0
- data/app/views/embeddable_content/replacements/geogebra_files/cc.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/cms.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/editable.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/exported.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/kiddom.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/print.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/qti.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/schoology.html.slim +1 -0
- data/app/views/embeddable_content/replacements/geogebra_files/web.html.slim +1 -0
- data/app/views/embeddable_content/replacements/html_tags/editable.html.slim +16 -0
- data/app/views/embeddable_content/replacements/images/_button_close.html.slim +9 -0
- data/app/views/embeddable_content/replacements/images/_button_open.html.slim +9 -0
- data/app/views/embeddable_content/replacements/images/_image_embed.html.slim +14 -0
- data/app/views/embeddable_content/replacements/images/_modal_content.html.slim +30 -0
- data/app/views/embeddable_content/replacements/images/_modal_dialog.html.slim +17 -0
- data/app/views/embeddable_content/replacements/images/cc.html.slim +12 -0
- data/app/views/embeddable_content/replacements/images/cms.html.slim +1 -0
- data/app/views/embeddable_content/replacements/images/editable.html.slim +1 -0
- data/app/views/embeddable_content/replacements/images/exported.html.slim +1 -0
- data/app/views/embeddable_content/replacements/images/kiddom.html.slim +12 -0
- data/app/views/embeddable_content/replacements/images/print.html.slim +1 -0
- data/app/views/embeddable_content/replacements/images/qti.html.slim +6 -0
- data/app/views/embeddable_content/replacements/images/schoology.html.slim +12 -0
- data/app/views/embeddable_content/replacements/images/web.html.slim +1 -0
- data/app/views/embeddable_content/replacements/presentation_tags/_default.html.slim +6 -0
- data/app/views/embeddable_content/replacements/presentation_tags/print.html.slim +1 -0
- data/app/views/embeddable_content/replacements/status/warning.html.slim +12 -0
- data/app/views/embeddable_content/replacements/video_links/_caption.html.slim +13 -0
- data/app/views/embeddable_content/replacements/video_links/_description.html.slim +12 -0
- data/app/views/embeddable_content/replacements/video_links/_video_embed.html.slim +13 -0
- data/app/views/embeddable_content/replacements/video_links/_video_player.html.slim +6 -0
- data/app/views/embeddable_content/replacements/video_links/_vimeo_player.html.slim +6 -0
- data/app/views/embeddable_content/replacements/video_links/cc.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/cms.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/editable.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/exported.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/kiddom.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/print.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/qti.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/schoology.html.slim +1 -0
- data/app/views/embeddable_content/replacements/video_links/web.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/_widget_omitted.html.slim +8 -0
- data/app/views/embeddable_content/replacements/widget_files/_widget_script.html.slim +13 -0
- data/app/views/embeddable_content/replacements/widget_files/cc.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/cms.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/editable.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/exported.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/kiddom.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/print.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/qti.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/schoology.html.slim +1 -0
- data/app/views/embeddable_content/replacements/widget_files/web.html.slim +1 -0
- data/bin/rails +25 -0
- data/config/initializers/embeddable_content.rb +3 -0
- data/config/routes.rb +2 -0
- data/embeddable_content.gemspec +48 -0
- data/lib/embeddable_content/engine.rb +8 -0
- data/lib/embeddable_content/version.rb +3 -0
- data/lib/embeddable_content.rb +3 -0
- data/lib/tasks/embeddable_content_tasks.rake +4 -0
- metadata +309 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
module Images
|
3
|
+
class NodeProcessor < EmbeddableContent::VisualElementNodeProcessor
|
4
|
+
delegate :target, :image_catalog, to: :embedder
|
5
|
+
delegate :attribution, :long_description, :label, :alt_text,
|
6
|
+
to: :record
|
7
|
+
|
8
|
+
def modal_dialog
|
9
|
+
@modal_dialog = ModalDialog.new self
|
10
|
+
end
|
11
|
+
|
12
|
+
def img_tag_attrs
|
13
|
+
@img_tag_attrs ||= ImgTagAttributes.new(self).to_h
|
14
|
+
end
|
15
|
+
|
16
|
+
TARGETS_THAT_DISPLAY_A_MODAL_DIALOG = %i[web].freeze
|
17
|
+
def display_modal_dialog?
|
18
|
+
TARGETS_THAT_DISPLAY_A_MODAL_DIALOG.include? target.to_sym
|
19
|
+
end
|
20
|
+
|
21
|
+
TARGETS_THAT_USE_DIV_TAGS = %i[editable].freeze
|
22
|
+
TARGETS_THAT_USE_FIGURE_TAGS = %i[cms print web exported qti cc schoology]
|
23
|
+
.freeze
|
24
|
+
def figure_tag
|
25
|
+
case target
|
26
|
+
when *TARGETS_THAT_USE_DIV_TAGS then :div
|
27
|
+
when *TARGETS_THAT_USE_FIGURE_TAGS then :figure
|
28
|
+
else raise "Undefined tag for target: #{target}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def node_can_be_removed?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def node_selector_class
|
37
|
+
[super, 'embedded-content-image'].join ' '
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def catalog_image
|
43
|
+
image_catalog << record
|
44
|
+
end
|
45
|
+
|
46
|
+
def replace_node
|
47
|
+
record.render_svg if svg_should_be_rendered?
|
48
|
+
catalog_image if image_should_be_catalogued?
|
49
|
+
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def svg_should_be_rendered?
|
54
|
+
config.render_images? &&
|
55
|
+
record_model.requires_rendering? &&
|
56
|
+
attachment_status_matters? &&
|
57
|
+
attachment_unavailable?
|
58
|
+
end
|
59
|
+
|
60
|
+
def attachment_unavailable?
|
61
|
+
!attached_file.attached? ||
|
62
|
+
!attachment_url_response_status_ok?
|
63
|
+
end
|
64
|
+
|
65
|
+
def attachment_url_response_status_ok?
|
66
|
+
attachment_url_response.instance_of? Net::HTTPOK
|
67
|
+
end
|
68
|
+
|
69
|
+
def attachment_url_response
|
70
|
+
@attachment_url_response ||= Net::HTTP.get_response s3_ttl_service_uri
|
71
|
+
end
|
72
|
+
|
73
|
+
def s3_ttl_service_uri
|
74
|
+
@s3_ttl_service_uri ||= URI.parse s3_ttl_service_url
|
75
|
+
end
|
76
|
+
|
77
|
+
def attachment_status_matters?
|
78
|
+
Rails.env.production? &&
|
79
|
+
ENV['VERIFY_ATTACHMENT_STATUS'].eql?('true')
|
80
|
+
end
|
81
|
+
|
82
|
+
def image_should_be_catalogued?
|
83
|
+
record.present? && attribution.present?
|
84
|
+
end
|
85
|
+
|
86
|
+
def route_keys
|
87
|
+
%i[tikz_files image_files]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
class NodeProcessor < EmbedderBase
|
3
|
+
NODE_CAN_BE_REMOVED_BY_DEFAULT = true
|
4
|
+
SELECTOR_CLASS_BLANK_BY_DEFAULT = nil
|
5
|
+
RECORD_BLANK_BY_DEFAULT = nil
|
6
|
+
ALL_TARGETS_PROCESSED_BY_DEFAULT = EmbedderConfig::ALL_TARGETS
|
7
|
+
DEFAULT_TEMPLATE_MANAGER_CLASS = TemplateManager
|
8
|
+
ADDED_CLASSES_BLANK_BY_DEFAULT = [].freeze
|
9
|
+
|
10
|
+
attr_reader :node, :node_index, :doc_processor, :error
|
11
|
+
|
12
|
+
delegate :embedder, to: :doc_processor
|
13
|
+
delegate :warning_node, to: :template_manager
|
14
|
+
|
15
|
+
def initialize(doc_processor, node, node_index)
|
16
|
+
@doc_processor = doc_processor
|
17
|
+
@node = node
|
18
|
+
@node_index = node_index
|
19
|
+
super embedder.config, embedder.options
|
20
|
+
end
|
21
|
+
|
22
|
+
def process!
|
23
|
+
process_node || remove_node
|
24
|
+
rescue StandardError => e
|
25
|
+
@error = e
|
26
|
+
node.replace warning_node
|
27
|
+
end
|
28
|
+
|
29
|
+
def node_selector_class
|
30
|
+
SELECTOR_CLASS_BLANK_BY_DEFAULT
|
31
|
+
end
|
32
|
+
|
33
|
+
def node_added_classes
|
34
|
+
ADDED_CLASSES_BLANK_BY_DEFAULT
|
35
|
+
end
|
36
|
+
|
37
|
+
def record
|
38
|
+
RECORD_BLANK_BY_DEFAULT
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def process_node
|
44
|
+
replace_node if node_should_be_replaced?
|
45
|
+
end
|
46
|
+
|
47
|
+
def node_should_be_replaced?
|
48
|
+
targets_that_require_processing.include? target
|
49
|
+
end
|
50
|
+
|
51
|
+
def targets_that_require_processing
|
52
|
+
ALL_TARGETS_PROCESSED_BY_DEFAULT
|
53
|
+
end
|
54
|
+
|
55
|
+
def replace_node
|
56
|
+
raise 'implement in a subclass'
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_node
|
60
|
+
node.remove if node_can_be_removed?
|
61
|
+
end
|
62
|
+
|
63
|
+
def node_can_be_removed?
|
64
|
+
NODE_CAN_BE_REMOVED_BY_DEFAULT
|
65
|
+
end
|
66
|
+
|
67
|
+
def template_manager
|
68
|
+
@template_manager ||= template_manager_class.new self
|
69
|
+
end
|
70
|
+
|
71
|
+
def template_manager_class
|
72
|
+
DEFAULT_TEMPLATE_MANAGER_CLASS
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
module PresentationTags
|
3
|
+
class NodeProcessor < EmbeddableContent::TreeBasedNodeProcessor
|
4
|
+
include TemplateBased
|
5
|
+
|
6
|
+
alias presentation_tag record
|
7
|
+
|
8
|
+
def node_added_classes
|
9
|
+
['presentation-tag-classes-added',
|
10
|
+
presentation_tag.added_class].join ' '
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
delegate :template_based?, to: :presentation_tag
|
16
|
+
|
17
|
+
def replace_node
|
18
|
+
template_based? ? super : modify_parent
|
19
|
+
end
|
20
|
+
|
21
|
+
def modify_parent
|
22
|
+
parent_node.add_class node_added_classes
|
23
|
+
remove_node
|
24
|
+
end
|
25
|
+
|
26
|
+
def parent_node
|
27
|
+
@parent_node ||= node.parent
|
28
|
+
end
|
29
|
+
|
30
|
+
def targets_that_require_processing
|
31
|
+
%i[print]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
class RecordNodeProcessor < NodeProcessor
|
3
|
+
delegate :title, to: :record
|
4
|
+
|
5
|
+
def record_id
|
6
|
+
@record_id ||= tag_match_data[:id] if tag_references_record?
|
7
|
+
end
|
8
|
+
|
9
|
+
def record_model
|
10
|
+
@record_model ||= tag_match_data[:model].classify.constantize if
|
11
|
+
tag_references_record?
|
12
|
+
end
|
13
|
+
|
14
|
+
def record_css_id_for(type)
|
15
|
+
"#{type}-#{record_model}-#{record_id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def record
|
19
|
+
@record ||= target_scope.find record_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def s3_url(with_extension: false)
|
23
|
+
with_extension ? s3_url_with_extension : bare_s3_url
|
24
|
+
end
|
25
|
+
|
26
|
+
def cms_url
|
27
|
+
src_url
|
28
|
+
end
|
29
|
+
|
30
|
+
def s3_ttl_service_url
|
31
|
+
if Rails.env.test?
|
32
|
+
Pathname
|
33
|
+
.new(ActiveStorage::Blob.service.send(:path_for, blob.key))
|
34
|
+
.relative_path_from Rails.root
|
35
|
+
else
|
36
|
+
blob.service_url(content_type: content_type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def attached_file
|
41
|
+
record.file
|
42
|
+
end
|
43
|
+
|
44
|
+
def node_selector_class
|
45
|
+
"embedded-content-#{record_model.model_name.param_key.dasherize}"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
delegate :s3_bucket, to: :embedder
|
51
|
+
delegate :blob, to: :attached_file
|
52
|
+
delegate :content_type, to: :blob
|
53
|
+
|
54
|
+
def bare_s3_url
|
55
|
+
"https://s3.amazonaws.com/#{s3_bucket}/#{blob_key}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def s3_url_with_extension
|
59
|
+
"#{bare_s3_url}.#{blob.filename.extension}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def blob_key
|
63
|
+
blob.key
|
64
|
+
end
|
65
|
+
|
66
|
+
def src_url
|
67
|
+
@src_url ||= node.attr 'src'
|
68
|
+
end
|
69
|
+
|
70
|
+
def tag_match_data
|
71
|
+
@tag_match_data ||= regex_src_url.match src_url
|
72
|
+
end
|
73
|
+
|
74
|
+
def regex_src_url
|
75
|
+
%r{\/(?<model>#{route_keys.join('|')})\/(?<id>\d+)\.(?<ext>\w+)}
|
76
|
+
end
|
77
|
+
|
78
|
+
def target_scope
|
79
|
+
record_model
|
80
|
+
end
|
81
|
+
|
82
|
+
def tag_references_record?
|
83
|
+
tag_match_data.present?
|
84
|
+
end
|
85
|
+
|
86
|
+
def node_should_be_replaced?
|
87
|
+
super && tag_match_data.present?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
class ReplacementTemplateManager < TemplateManager
|
3
|
+
def replacement_node
|
4
|
+
render_target || warning_node
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def node_templates_subdir
|
10
|
+
@node_templates_subdir ||= node_type.underscore
|
11
|
+
end
|
12
|
+
|
13
|
+
def node_templates_path
|
14
|
+
@node_templates_path ||= templates_dir.join node_templates_subdir
|
15
|
+
end
|
16
|
+
|
17
|
+
def target_path
|
18
|
+
@target_path ||= node_templates_path.join target.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
class SadEmbeddedTags
|
3
|
+
attr_accessor :ed_node, :sad_related_records, :embedded_models
|
4
|
+
|
5
|
+
def initialize(ed_node, embedded_models)
|
6
|
+
@ed_node = ed_node
|
7
|
+
@sad_related_records = SadRelatedRecords.new ed_node
|
8
|
+
@embedded_models = embedded_models
|
9
|
+
end
|
10
|
+
|
11
|
+
def each
|
12
|
+
@ed_node.tags.each do |tag|
|
13
|
+
tag.html_attrs.each do |attr|
|
14
|
+
EmbeddedTags.new(tag, attr, embedded_models).each do |info|
|
15
|
+
yield nil, nil, info
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
sad_related_records.each do |node, node_address, related_record|
|
21
|
+
related_record.html_attrs.each do |attr|
|
22
|
+
EmbeddedTags.new(related_record, attr, embedded_models).each do |info|
|
23
|
+
yield node, node_address, info
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
class Scrubber < EmbedderBase
|
3
|
+
def scrub(document)
|
4
|
+
document.search(scrubbed_nodes_selector).remove
|
5
|
+
document
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def scrubbed_nodes_selector
|
11
|
+
all_selectors.join ','
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_selectors
|
15
|
+
selectors_for_other_targets <<
|
16
|
+
'.removed-for-all-embedder-targets' <<
|
17
|
+
selector_for_current_target
|
18
|
+
end
|
19
|
+
|
20
|
+
def selector_for_current_target
|
21
|
+
".removed-for-#{target}-embedder-target"
|
22
|
+
end
|
23
|
+
|
24
|
+
def selectors_for_other_targets
|
25
|
+
all_other_targets.map { |tgt| selector_for_other_target tgt }
|
26
|
+
end
|
27
|
+
|
28
|
+
def selector_for_other_target(tgt)
|
29
|
+
".removed-for-all-but-#{tgt}-embedder-target"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
module TemplateBased
|
3
|
+
delegate :replacement_node, to: :template_manager
|
4
|
+
|
5
|
+
def node_type
|
6
|
+
@node_type ||= embedding_module.underscore
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def replace_node
|
12
|
+
node.replace replacement_node
|
13
|
+
end
|
14
|
+
|
15
|
+
def template_manager_class
|
16
|
+
ReplacementTemplateManager
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
class TemplateManager < EmbedderBase
|
3
|
+
DEFAULT_NUM_BACKTRACE_LINES = 10
|
4
|
+
NUM_BACKTRACE_LINES =
|
5
|
+
ENV.fetch('NUM_BACKTRACE_LINES', DEFAULT_NUM_BACKTRACE_LINES).try :to_i
|
6
|
+
|
7
|
+
attr_reader :node_processor
|
8
|
+
|
9
|
+
delegate :record, :node, :node_type, :error, :node_selector_class,
|
10
|
+
:node_added_classes, :node_index,
|
11
|
+
to: :node_processor
|
12
|
+
|
13
|
+
def initialize(node_processor)
|
14
|
+
@node_processor = node_processor
|
15
|
+
super node_processor.config, node_processor.options
|
16
|
+
end
|
17
|
+
|
18
|
+
def warning_node
|
19
|
+
render_path warning_node_path
|
20
|
+
end
|
21
|
+
|
22
|
+
def selected_backtrace_lines
|
23
|
+
return if error.nil?
|
24
|
+
|
25
|
+
error.backtrace.first(NUM_BACKTRACE_LINES).join "\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def node_attrs
|
29
|
+
@node_attrs ||= { class: node_classes,
|
30
|
+
data: node_data }.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def target_attrs
|
34
|
+
@target_attrs ||= { id: node_id }.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def node_id
|
38
|
+
return if record.nil?
|
39
|
+
|
40
|
+
"#{record_model}-#{record.id}-#{node_index}"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def node_data
|
46
|
+
@node_data ||= { 'embedder-target': target }.merge record_node_data
|
47
|
+
end
|
48
|
+
|
49
|
+
def record_node_data
|
50
|
+
return {} if record.nil?
|
51
|
+
|
52
|
+
{ 'record-model': record_model,
|
53
|
+
'record-id': record.id }
|
54
|
+
end
|
55
|
+
|
56
|
+
def record_model
|
57
|
+
return if record.nil?
|
58
|
+
|
59
|
+
@record_model ||= record.model_name.name
|
60
|
+
end
|
61
|
+
|
62
|
+
def node_classes
|
63
|
+
['embedded-content',
|
64
|
+
node_selector_class,
|
65
|
+
node_added_classes].flatten.compact
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_target
|
69
|
+
I18n.with_locale(locale) { render_path target_path }
|
70
|
+
end
|
71
|
+
|
72
|
+
def render_path(path)
|
73
|
+
ApplicationController.render rendering_options_for path
|
74
|
+
end
|
75
|
+
|
76
|
+
def rendering_options_for(path)
|
77
|
+
{ assigns: assigns, template: path, layout: false }
|
78
|
+
end
|
79
|
+
|
80
|
+
def assigns
|
81
|
+
{ template_manager: self }
|
82
|
+
end
|
83
|
+
|
84
|
+
def warning_node_path
|
85
|
+
@warning_node_path ||= status_template_path 'warning'
|
86
|
+
end
|
87
|
+
|
88
|
+
def status_template_path(status)
|
89
|
+
status_dir.join status
|
90
|
+
end
|
91
|
+
|
92
|
+
def status_dir
|
93
|
+
@status_dir ||= templates_dir.join 'status'
|
94
|
+
end
|
95
|
+
|
96
|
+
def templates_dir
|
97
|
+
@templates_dir ||= Pathname.new('embeddable_content').join 'replacements'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module EmbeddableContent
|
4
|
+
module Tex
|
5
|
+
class BaseRenderer
|
6
|
+
RENDER_TEX_JS_PATH = Pathname.new('lib').join 'tasks/render_tex.js'
|
7
|
+
|
8
|
+
attr_reader :html
|
9
|
+
|
10
|
+
def initialize(html)
|
11
|
+
@html = html
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
html.replace render_format(target_format) if target_format.present?
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def render_format(format)
|
21
|
+
output, status = Open3.capture2(render_tex(format), stdin_data: html)
|
22
|
+
return output if status.success?
|
23
|
+
|
24
|
+
Rails.logger.warn "Error calling #{render_tex(format)}: #{status}"
|
25
|
+
html
|
26
|
+
end
|
27
|
+
|
28
|
+
def render_tex(format)
|
29
|
+
[RENDER_TEX_JS_PATH, '--output', format].join(' ')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module EmbeddableContent
|
2
|
+
module Tex
|
3
|
+
class DocProcessor < EmbeddableContent::DocProcessor
|
4
|
+
REPAIRED_MATH_CSS_CLASS = 'math-repaired'.freeze
|
5
|
+
REPAIRED_MATH_CSS_SELECTOR = ".#{REPAIRED_MATH_CSS_CLASS}".freeze
|
6
|
+
|
7
|
+
delegate :remove_repaired_math_spans?, to: :embedder
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def process_nodes?
|
12
|
+
remove_repaired_math_spans?
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_node(node, _node_index)
|
16
|
+
remove_repaired_math_span node
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove_repaired_math_span(node)
|
20
|
+
node.replace node.content
|
21
|
+
end
|
22
|
+
|
23
|
+
def post_process
|
24
|
+
refresh_html
|
25
|
+
render_tex
|
26
|
+
fix_mml_fragments if fix_mml_fragments?
|
27
|
+
rebuild_document
|
28
|
+
end
|
29
|
+
|
30
|
+
def node_selector
|
31
|
+
REPAIRED_MATH_CSS_SELECTOR
|
32
|
+
end
|
33
|
+
|
34
|
+
def repaired_math_nodes
|
35
|
+
@repaired_math_nodes ||= document.css(REPAIRED_MATH_CSS_SELECTOR)
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_tex
|
39
|
+
tex_renderer.new(html).render
|
40
|
+
end
|
41
|
+
|
42
|
+
def fix_mml_fragments?
|
43
|
+
embedder.fragment? && embedder.xml?
|
44
|
+
end
|
45
|
+
|
46
|
+
def fix_mml_fragments
|
47
|
+
html.replace Nokogiri::HTML(html).at('body').children.to_xml
|
48
|
+
end
|
49
|
+
|
50
|
+
def tex_renderer
|
51
|
+
"#{module_name}::#{tex_output_format.classify}Renderer".constantize
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module EmbeddableContent
|
4
|
+
module Tex
|
5
|
+
class SchoologyStringRenderer < BaseRenderer
|
6
|
+
def target_format
|
7
|
+
:schoology_string
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_format(_format)
|
11
|
+
Mathjax::SchoologyStringRenderer.new(html).render
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|