embeddable_content 0.1.19
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.
- 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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d248938f6cfb46c41b491e75619538d518388329abe8970add6cb42188ee2247
|
|
4
|
+
data.tar.gz: 34843aabc66b6e11dcd4addb69e70c52b71bf8db70039ef111bc5f53a16bb8c5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3de97e6f33fad46331b1a9662db068b8ef81913675d224bf0e128b1a2ff1581414ffbbbaf07ad9c68af624c2c75e6c4a99544a6950c25e4ff602ec5c3cc90db0
|
|
7
|
+
data.tar.gz: 4dfcd81715bfa44e337f5ce8eb8a602f180ed3f3eb62d7569a2b236b87ea5ae030fc084c059d3cdce3f5f9310a2bab2283421d6b873459a8e6895077854d0da7
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop-rails
|
|
3
|
+
|
|
4
|
+
Style/Documentation:
|
|
5
|
+
Enabled: false
|
|
6
|
+
Layout/ArgumentAlignment:
|
|
7
|
+
Enabled: false
|
|
8
|
+
Layout/HashAlignment:
|
|
9
|
+
Enabled: false
|
|
10
|
+
Layout/ParameterAlignment:
|
|
11
|
+
Enabled: false
|
|
12
|
+
Layout/LeadingCommentSpace:
|
|
13
|
+
Enabled: false
|
|
14
|
+
Style/NumericLiterals:
|
|
15
|
+
Enabled: false
|
|
16
|
+
Style/FrozenStringLiteralComment:
|
|
17
|
+
Enabled: false
|
|
18
|
+
Rails/InverseOf:
|
|
19
|
+
Enabled: false
|
|
20
|
+
Metrics/MethodLength:
|
|
21
|
+
Exclude:
|
|
22
|
+
- config/routes//**/*.rb
|
|
23
|
+
Metrics/BlockLength:
|
|
24
|
+
ExcludedMethods:
|
|
25
|
+
[
|
|
26
|
+
"describe",
|
|
27
|
+
"described_class",
|
|
28
|
+
"context",
|
|
29
|
+
"scenario",
|
|
30
|
+
"feature",
|
|
31
|
+
"let",
|
|
32
|
+
"shared_examples",
|
|
33
|
+
"shared_examples_for",
|
|
34
|
+
"shared_context",
|
|
35
|
+
"before",
|
|
36
|
+
]
|
|
37
|
+
Exclude:
|
|
38
|
+
- "*.gemspec"
|
|
39
|
+
- db/schema.rb
|
|
40
|
+
- db/migrate/*.rb
|
|
41
|
+
- config/initializers/**/*.rb
|
|
42
|
+
- config/routes.rb
|
|
43
|
+
- config/routes/**/*.rb
|
|
44
|
+
- spec/factories/*.rb
|
|
45
|
+
- spec/policies/**/*.rb
|
|
46
|
+
- spec/system/**/*.rb
|
|
47
|
+
Security/YAMLLoad:
|
|
48
|
+
Exclude:
|
|
49
|
+
- spec/support/shared_examples/embeddable_content.rb
|
|
50
|
+
AllCops:
|
|
51
|
+
Exclude:
|
|
52
|
+
- db/schema.rb
|
|
53
|
+
- bin/*
|
|
54
|
+
- Rakefile
|
|
55
|
+
- config/environments/production.rb
|
|
56
|
+
- config/initializers/backtrace_silencers.rb
|
|
57
|
+
- config/initializers/devise.rb
|
|
58
|
+
- config/initializers/simple_form.rb
|
|
59
|
+
- config/initializers/wrap_parameters.rb
|
|
60
|
+
- config/puma.rb
|
|
61
|
+
- db/migrate/*.rb
|
|
62
|
+
- db/seeds.rb
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.6.6
|
data/Gemfile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
|
3
|
+
|
|
4
|
+
# Declare your gem's dependencies in embeddable_content.gemspec.
|
|
5
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
|
6
|
+
# development dependencies will be added by default to the :development group.
|
|
7
|
+
gemspec
|
|
8
|
+
|
|
9
|
+
# Declare any dependencies that are still in development here instead of in
|
|
10
|
+
# your gemspec. These might include edge Rails or gems from your path or
|
|
11
|
+
# Git. Remember to move these dependencies to your gemspec before releasing
|
|
12
|
+
# your gem to rubygems.org.
|
|
13
|
+
|
|
14
|
+
# To use a debugger
|
|
15
|
+
# gem 'byebug', group: [:development, :test]
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2020 Eric Connally
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# EmbeddableContent
|
|
2
|
+
|
|
3
|
+
Embedder functionality has been extracted to this gem to reduce client-app dependencies.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
For IM gems, add this to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
``` ruby
|
|
10
|
+
git_source(:im) do |repo_name|
|
|
11
|
+
"https://github.com/illustrativemathematics/#{repo_name}.git"
|
|
12
|
+
end
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then add this line to your application's Gemfile:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'embeddable_content', im: 'embeddable_content'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
And then execute:
|
|
22
|
+
|
|
23
|
+
$ bundle
|
|
24
|
+
|
|
25
|
+
Or install it yourself as:
|
|
26
|
+
|
|
27
|
+
$ gem install embeddable_content
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Ask Eric.
|
|
32
|
+
|
|
33
|
+
## Development
|
|
34
|
+
|
|
35
|
+
N.b. (EDC): This bit was auto-generated so it's unclear how relevant it is.
|
|
36
|
+
|
|
37
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
|
38
|
+
Then, run `rake spec` to run the tests.
|
|
39
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
40
|
+
|
|
41
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
42
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`,
|
|
43
|
+
which will create a git tag for the version, push git commits and tags,
|
|
44
|
+
and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
45
|
+
|
|
46
|
+
## Contributing
|
|
47
|
+
|
|
48
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
49
|
+
https://github.com/illustrativemathematics/embeddable_content.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'rdoc/task'
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
+
rdoc.title = 'EmbeddableContent'
|
|
12
|
+
rdoc.options << '--line-numbers'
|
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
|
18
|
+
load 'rails/tasks/engine.rake'
|
|
19
|
+
|
|
20
|
+
load 'rails/tasks/statistics.rake'
|
|
21
|
+
|
|
22
|
+
require 'bundler/gem_tasks'
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
2
|
+
document
|
|
3
|
+
.querySelectorAll('.embedded-content-desmos-file')
|
|
4
|
+
.forEach(loadDesmosCalculator);
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
function loadDesmosCalculator(elmt) {
|
|
8
|
+
var state = elmt.dataset['state'],
|
|
9
|
+
calculatorElmt = elmt.getElementsByClassName('desmos-calculator')[0],
|
|
10
|
+
calculator = Desmos.GraphingCalculator(calculatorElmt);
|
|
11
|
+
calculator.setState(state);
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
2
|
+
document
|
|
3
|
+
.querySelectorAll('.embedded-content-geogebra-file')
|
|
4
|
+
.forEach(loadGeogebraApplet);
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
function loadGeogebraApplet(elmt) {
|
|
8
|
+
var container = elmt.getElementsByClassName('ggb-applet-container')[0],
|
|
9
|
+
dataNode = elmt.getElementsByClassName('ggb-base-64-data')[0],
|
|
10
|
+
parameters = JSON.parse(dataNode.dataset['parameters']),
|
|
11
|
+
applet = new GGBApplet(parameters, '5.0');
|
|
12
|
+
applet.setHTML5Codebase('/GeoGebra/HTML5/5.0/web3d/');
|
|
13
|
+
applet.inject(container.id);
|
|
14
|
+
};
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module EmbeddableContentController
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
class_methods do
|
|
5
|
+
def embed_content_for(* actions)
|
|
6
|
+
whitelisted_embedder_actions.replace actions
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def do_not_embed_content_for(* actions)
|
|
10
|
+
blacklisted_embedder_actions.replace actions
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
class_attribute :whitelisted_embedder_actions, default: []
|
|
16
|
+
class_attribute :blacklisted_embedder_actions, default: []
|
|
17
|
+
|
|
18
|
+
after_action :embed_content
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def handle_unknown_format_error
|
|
24
|
+
embed_content
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def embed_content
|
|
28
|
+
render_embedded_content if embedder_required_for_action?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def render_embedded_content
|
|
32
|
+
render_html
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def render_html
|
|
36
|
+
response.body = embedded_html
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def embedder_required_for_action?
|
|
40
|
+
embedder_required_by_default? || embedder_action_whitelisted?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def embedder_required_by_default?
|
|
44
|
+
!embedder_action_blacklisted? && whitelisted_embedder_actions.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def embedder_action_whitelisted?
|
|
48
|
+
whitelisted_embedder_actions.map(&:to_s).include? action_name
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def embedder_action_blacklisted?
|
|
52
|
+
blacklisted_embedder_actions.map(&:to_s).include? action_name
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def embedded_html
|
|
56
|
+
@embedded_html ||= embedder.embed_content! raw_html
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def raw_html
|
|
60
|
+
@raw_html ||= response.body.presence || render_raw_html
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def requested_format
|
|
64
|
+
request.format.to_sym
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def render_raw_html
|
|
68
|
+
raise 'Define this method for blank response body (e.g., docx)'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def embedder
|
|
72
|
+
@embedder ||= create_embedder
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def create_embedder
|
|
76
|
+
raise_missing_target if embedder_target.blank?
|
|
77
|
+
|
|
78
|
+
EmbeddableContent::Embedder.new embedder_target
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def raise_missing_target
|
|
82
|
+
raise "No embedder target defined for action '#{action_name}'" \
|
|
83
|
+
" and format '#{requested_format}'"
|
|
84
|
+
end
|
|
85
|
+
end
|
data/app/helpers/.keep
ADDED
|
File without changes
|
data/app/mailers/.keep
ADDED
|
File without changes
|
data/app/models/.keep
ADDED
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module ProvidesEmbeddableContent
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
include ActionView::Helpers::TagHelper
|
|
4
|
+
|
|
5
|
+
class_methods do
|
|
6
|
+
def embeddable_model_config
|
|
7
|
+
@embeddable_model_config ||= EmbeddableModelConfig.for_model self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
delegate(*EmbeddableModelConfig.attributes, to: :embeddable_model_config)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
included do
|
|
14
|
+
validates :title, presence: true
|
|
15
|
+
delegate(*EmbeddableModelConfig.attributes, to: self)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def embeddable_tag_extension
|
|
19
|
+
try(:file).try(:filename).try(:extension) || embeddable_tag_ext
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def embeddable_tag(opts = {})
|
|
23
|
+
convert_safe_buffer_to_string tag(embeddable_tag_name, embeddable_tag_attrs(opts))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def template_based?
|
|
27
|
+
defined?(super) ? super : false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def convert_safe_buffer_to_string(safe_buffer)
|
|
33
|
+
safe_buffer.to_str
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def embeddable_tag_attrs(opts)
|
|
37
|
+
{ src: "/#{model_name.route_key}/#{id}.#{embeddable_tag_extension}",
|
|
38
|
+
data: data_attributes(opts) }.compact
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def data_attributes(opts)
|
|
42
|
+
return unless tree_based?
|
|
43
|
+
|
|
44
|
+
tree_based_data_attributes opts
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def tree_based_data_attributes(opts)
|
|
48
|
+
tree_node = opts[:tree_node]
|
|
49
|
+
tree_node_id = tree_node&.id ||
|
|
50
|
+
EmbeddableContent::TREE_EMBEDDER_ID_PLACEHOLDER
|
|
51
|
+
tree_ref_id = tree_node&.ref_id ||
|
|
52
|
+
EmbeddableContent::TREE_EMBEDDER_ID_PLACEHOLDER
|
|
53
|
+
tree_code = Tree.where(id: tree_ref_id)&.pluck(:code)&.first
|
|
54
|
+
{ tree_ref_id: tree_ref_id,
|
|
55
|
+
tree_node_id: tree_node_id,
|
|
56
|
+
tree_code: tree_code,
|
|
57
|
+
tag_title: title }.compact
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
class EmbeddableModelConfig < ApplicationRecord
|
|
2
|
+
IGNORED_ATTRIBUTES = %w[id created_at updated_at].freeze
|
|
3
|
+
BOOLEAN_ATTRIBUTES =
|
|
4
|
+
%w[tree_based?
|
|
5
|
+
always_display_tag_indicator?
|
|
6
|
+
embeddable_applet?
|
|
7
|
+
embeddable_image?
|
|
8
|
+
requires_rendering?].freeze
|
|
9
|
+
|
|
10
|
+
def self.ckeditor_config
|
|
11
|
+
pluck :embeddable_tag_selector, :ckeditor_allowed_content
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.ckeditor_allowed_content_rules
|
|
15
|
+
ckeditor_config.map do |selector, content|
|
|
16
|
+
[selector, content]
|
|
17
|
+
end.to_h
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.attributes
|
|
21
|
+
@attributes ||= (attribute_names -
|
|
22
|
+
IGNORED_ATTRIBUTES +
|
|
23
|
+
BOOLEAN_ATTRIBUTES).map(&:to_sym)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.all_embeddable_models
|
|
27
|
+
all.map(&:embeddable_model)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.embeddable_image_models
|
|
31
|
+
where(embeddable_image: true).map(&:embeddable_model)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.embeddable_applet_models
|
|
35
|
+
where(embeddable_applet: true).map(&:embeddable_model)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.embeddable_tree_based_models
|
|
39
|
+
where(tree_based: true).map(&:embeddable_model)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.for_model(embeddable_model)
|
|
43
|
+
find_by! embeddable_model_name: embeddable_model.model_name.name
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def embeddable_model
|
|
47
|
+
embeddable_model_name.constantize
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def styled_indicator_selector(tree_node: nil)
|
|
51
|
+
return embeddable_tag_name unless tree_based? && tree_node.present?
|
|
52
|
+
|
|
53
|
+
"#{embeddable_tag_name}[data-tree-ref-id=\"#{tree_node.ref_id}\"]".html_safe
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class EmbedderConfig < ApplicationRecord
|
|
2
|
+
TARGET_CATEGORY_ENUM_CONSULT_BEFORE_CHANGING =
|
|
3
|
+
{ cms: 0,
|
|
4
|
+
print: 1,
|
|
5
|
+
web: 2,
|
|
6
|
+
editable: 3,
|
|
7
|
+
exported: 4,
|
|
8
|
+
qti: 5,
|
|
9
|
+
cc: 6,
|
|
10
|
+
schoology: 7,
|
|
11
|
+
kiddom: 8 }.freeze
|
|
12
|
+
SCOPE_CATEGORY_ENUM_CONSULT_BEFORE_CHANGING =
|
|
13
|
+
{ document: 0,
|
|
14
|
+
fragment: 1 }.freeze
|
|
15
|
+
TEX_OUTPUT_FORMAT_CONSULT_BEFORE_CHANGING =
|
|
16
|
+
{ mathjax: 0,
|
|
17
|
+
svg: 1,
|
|
18
|
+
mml: 2,
|
|
19
|
+
canvas: 3,
|
|
20
|
+
schoology_string: 4}.freeze
|
|
21
|
+
OUTPUT_FORMAT_CONSULT_BEFORE_CHANGING =
|
|
22
|
+
{ html: 0,
|
|
23
|
+
xml: 1 }.freeze
|
|
24
|
+
DEFAULT_OUTPUT_FORMAT = OUTPUT_FORMAT_CONSULT_BEFORE_CHANGING[:html]
|
|
25
|
+
|
|
26
|
+
ALL_TARGETS = TARGET_CATEGORY_ENUM_CONSULT_BEFORE_CHANGING.keys.freeze
|
|
27
|
+
|
|
28
|
+
enum target: TARGET_CATEGORY_ENUM_CONSULT_BEFORE_CHANGING
|
|
29
|
+
enum scope: SCOPE_CATEGORY_ENUM_CONSULT_BEFORE_CHANGING
|
|
30
|
+
enum tex_output_format: TEX_OUTPUT_FORMAT_CONSULT_BEFORE_CHANGING
|
|
31
|
+
enum output_format: OUTPUT_FORMAT_CONSULT_BEFORE_CHANGING
|
|
32
|
+
|
|
33
|
+
def self.for_target(target)
|
|
34
|
+
find_by target: target
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def all_other_targets
|
|
38
|
+
@all_other_targets ||= ALL_TARGETS - [target.to_sym]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# EDC: this could be added to field on table
|
|
42
|
+
def aria_attrs?
|
|
43
|
+
!qti?
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class Embedding < ApplicationRecord
|
|
2
|
+
INDIFFERENT_RUN_ORDER = 0
|
|
3
|
+
MATH_TYPESETTING_RUN_ORDER = 1000
|
|
4
|
+
DEFAULT_RUN_ORDER = INDIFFERENT_RUN_ORDER
|
|
5
|
+
|
|
6
|
+
RUN_ORDER_ENUM_CONSULT_BEFORE_CHANGING = {
|
|
7
|
+
indifferent: INDIFFERENT_RUN_ORDER,
|
|
8
|
+
math_typesetting: MATH_TYPESETTING_RUN_ORDER
|
|
9
|
+
}.freeze
|
|
10
|
+
|
|
11
|
+
enum run_order: RUN_ORDER_ENUM_CONSULT_BEFORE_CHANGING
|
|
12
|
+
|
|
13
|
+
def self.in_run_order
|
|
14
|
+
order :run_order
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def doc_processor_for(embedder)
|
|
18
|
+
"EmbeddableContent::#{processor_module}::DocProcessor"
|
|
19
|
+
.constantize.new embedder
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def process_target?(target)
|
|
23
|
+
processor_targets.include? target.to_s
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module EmbeddableContent
|
|
2
|
+
class DocProcessor < EmbedderBase
|
|
3
|
+
PROCESS_NODES_BY_DEFAULT = true
|
|
4
|
+
|
|
5
|
+
attr_reader :embedder
|
|
6
|
+
|
|
7
|
+
delegate :document, :html, :rebuild_document, to: :embedder
|
|
8
|
+
delegate :selector, :process_target?, to: :embedding
|
|
9
|
+
|
|
10
|
+
def initialize(embedder)
|
|
11
|
+
@embedder = embedder
|
|
12
|
+
super embedder.config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def process!
|
|
16
|
+
return unless process_target?(target)
|
|
17
|
+
|
|
18
|
+
pre_process
|
|
19
|
+
process_matching_nodes if process_nodes?
|
|
20
|
+
post_process
|
|
21
|
+
refresh_html
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def embedding
|
|
25
|
+
@embedding ||= Embedding.find_by processor_module: embedding_module
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def refresh_html
|
|
31
|
+
html.replace document.to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def pre_process; end
|
|
35
|
+
|
|
36
|
+
def process_matching_nodes
|
|
37
|
+
matching_nodes.each.with_index(1) { |node, idx| process_node(node, idx) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def post_process; end
|
|
41
|
+
|
|
42
|
+
def process_nodes?
|
|
43
|
+
PROCESS_NODES_BY_DEFAULT
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def process_node(node, node_index)
|
|
47
|
+
node_processor_factory.new(self, node, node_index).process!
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def node_selector
|
|
51
|
+
@node_selector ||= embedding_module.underscore.dasherize.singularize
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def matching_nodes
|
|
55
|
+
@matching_nodes ||= document.css node_selector
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def node_processor_factory
|
|
59
|
+
@node_processor_factory ||=
|
|
60
|
+
"#{module_name}::NodeProcessor".constantize
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module EmbeddableContent
|
|
2
|
+
class EmbeddedTagInfo
|
|
3
|
+
attr_reader :record, :embedded_model, :attr, :dom_node
|
|
4
|
+
|
|
5
|
+
def initialize(record, embedded_model, attr, dom_node)
|
|
6
|
+
@record = record
|
|
7
|
+
@embedded_model = embedded_model
|
|
8
|
+
@attr = attr
|
|
9
|
+
@dom_node = dom_node
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def available?
|
|
13
|
+
match.present?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def embedded_record_id
|
|
17
|
+
match.try :first
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def embedded_record_ext
|
|
21
|
+
match.try :last
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def embedded_record
|
|
25
|
+
@embedded_record ||= embedded_model.find embedded_record_id
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def src
|
|
31
|
+
@src ||= dom_node.attributes['src'].to_html
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def embed_src_path
|
|
35
|
+
embedded_model.model_name.route_key
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def match
|
|
39
|
+
@match ||= src.match(%r{\/#{embed_src_path}\/(\d+)\.(\w+)}).try :captures
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def document
|
|
43
|
+
@document ||= Nokogiri::HTML.fragment searchable_text
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def searchable_text
|
|
47
|
+
record[attr].is_a?(Array) ? record[attr].join(' ') : record[attr]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|