comfortable_mexican_sofa 2.0.12 → 2.0.13
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 +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +5 -2
- data/Gemfile +5 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/comfy/admin/cms/application.js +40 -0
- data/app/assets/javascripts/comfy/admin/cms/base.js +46 -0
- data/app/assets/javascripts/comfy/admin/cms/categories.js +17 -0
- data/app/assets/javascripts/comfy/admin/cms/codemirror.js +31 -0
- data/app/assets/javascripts/comfy/admin/cms/custom.js +1 -0
- data/app/assets/javascripts/comfy/admin/cms/diff.js +10 -0
- data/app/assets/javascripts/comfy/admin/cms/file_link.js +67 -0
- data/app/assets/javascripts/comfy/admin/cms/file_upload.js +194 -0
- data/app/assets/javascripts/comfy/admin/cms/files_modal.js +40 -0
- data/app/assets/javascripts/comfy/admin/cms/page_fragments.js +22 -0
- data/app/assets/javascripts/comfy/admin/cms/slugify.js +34 -0
- data/app/assets/javascripts/comfy/admin/cms/sortable_list.js +40 -0
- data/app/assets/javascripts/comfy/admin/cms/timepicker.js +30 -0
- data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +65 -0
- data/app/assets/javascripts/comfy/vendor/redactor.js +12 -6
- data/app/assets/stylesheets/comfy/admin/cms/base.sass +32 -35
- data/app/controllers/application_controller.rb +2 -0
- data/app/controllers/comfy/admin/base_controller.rb +3 -1
- data/app/controllers/comfy/admin/cms/base_controller.rb +9 -1
- data/app/controllers/comfy/admin/cms/categories_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/files_controller.rb +3 -1
- data/app/controllers/comfy/admin/cms/layouts_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/pages_controller.rb +4 -1
- data/app/controllers/comfy/admin/cms/revisions/base_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/revisions/layout_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/revisions/page_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/revisions/snippet_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/revisions/translation_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/sites_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/snippets_controller.rb +2 -0
- data/app/controllers/comfy/admin/cms/translations_controller.rb +8 -0
- data/app/controllers/comfy/cms/assets_controller.rb +2 -0
- data/app/controllers/comfy/cms/base_controller.rb +4 -2
- data/app/controllers/comfy/cms/content_controller.rb +3 -1
- data/app/controllers/concerns/comfy/paginate.rb +2 -0
- data/app/controllers/concerns/comfy/reorder_action.rb +2 -0
- data/app/helpers/comfy/admin/cms_helper.rb +19 -0
- data/app/helpers/comfy/cms_helper.rb +4 -2
- data/app/models/comfy/cms/categorization.rb +2 -0
- data/app/models/comfy/cms/category.rb +2 -0
- data/app/models/comfy/cms/file.rb +2 -0
- data/app/models/comfy/cms/fragment.rb +3 -1
- data/app/models/comfy/cms/layout.rb +3 -1
- data/app/models/comfy/cms/page.rb +3 -1
- data/app/models/comfy/cms/revision.rb +2 -0
- data/app/models/comfy/cms/site.rb +5 -1
- data/app/models/comfy/cms/snippet.rb +2 -0
- data/app/models/comfy/cms/translation.rb +2 -0
- data/app/models/concerns/comfy/cms/with_categories.rb +2 -0
- data/app/models/concerns/comfy/cms/with_fragments.rb +2 -0
- data/app/views/comfy/admin/cms/categories/_index.html.haml +3 -3
- data/app/views/comfy/admin/cms/categories/create.js.erb +1 -1
- data/app/views/comfy/admin/cms/categories/destroy.js.erb +8 -3
- data/app/views/comfy/admin/cms/files/_file.html.haml +9 -10
- data/app/views/comfy/admin/cms/files/_modal.html.haml +1 -2
- data/app/views/comfy/admin/cms/files/destroy.js.erb +4 -0
- data/app/views/comfy/admin/cms/files/index.html.haml +10 -10
- data/app/views/comfy/admin/cms/fragments/_form_fragment_attachments.html.haml +15 -6
- data/app/views/comfy/admin/cms/fragments/_form_fragments.html.haml +17 -21
- data/app/views/comfy/admin/cms/pages/_form.html.haml +3 -2
- data/app/views/comfy/admin/cms/pages/toggle_branch.js.erb +3 -1
- data/app/views/comfy/admin/cms/translations/_form.html.haml +3 -2
- data/app/views/layouts/comfy/admin/cms.html.haml +0 -1
- data/app/views/layouts/comfy/admin/cms/_body.html.haml +1 -0
- data/app/views/layouts/comfy/admin/cms/_left.html.haml +1 -1
- data/comfortable_mexican_sofa.gemspec +3 -2
- data/config.ru +2 -0
- data/config/application.rb +2 -0
- data/config/boot.rb +2 -0
- data/config/cms_routes.rb +2 -0
- data/config/environment.rb +2 -0
- data/config/environments/development.rb +2 -0
- data/config/environments/test.rb +2 -0
- data/config/initializers/comfortable_mexican_sofa.rb +2 -0
- data/lib/comfortable_mexican_sofa.rb +2 -0
- data/lib/comfortable_mexican_sofa/access_control/admin_authentication.rb +2 -0
- data/lib/comfortable_mexican_sofa/access_control/admin_authorization.rb +2 -0
- data/lib/comfortable_mexican_sofa/access_control/public_authentication.rb +2 -0
- data/lib/comfortable_mexican_sofa/access_control/public_authorization.rb +2 -0
- data/lib/comfortable_mexican_sofa/configuration.rb +3 -0
- data/lib/comfortable_mexican_sofa/content.rb +3 -0
- data/lib/comfortable_mexican_sofa/content/block.rb +2 -0
- data/lib/comfortable_mexican_sofa/content/params_parser.rb +59 -41
- data/lib/comfortable_mexican_sofa/content/renderer.rb +18 -4
- data/lib/comfortable_mexican_sofa/content/tag.rb +20 -5
- data/lib/comfortable_mexican_sofa/content/tags/asset.rb +2 -0
- data/lib/comfortable_mexican_sofa/content/tags/checkbox.rb +10 -3
- data/lib/comfortable_mexican_sofa/content/tags/date.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/datetime.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/file.rb +21 -27
- data/lib/comfortable_mexican_sofa/content/tags/file_link.rb +23 -24
- data/lib/comfortable_mexican_sofa/content/tags/files.rb +11 -9
- data/lib/comfortable_mexican_sofa/content/tags/fragment.rb +11 -1
- data/lib/comfortable_mexican_sofa/content/tags/helper.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/markdown.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/mixins/file_content.rb +38 -0
- data/lib/comfortable_mexican_sofa/content/tags/number.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/page_file_link.rb +82 -0
- data/lib/comfortable_mexican_sofa/content/tags/partial.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/snippet.rb +2 -0
- data/lib/comfortable_mexican_sofa/content/tags/template.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/text.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/textarea.rb +3 -1
- data/lib/comfortable_mexican_sofa/content/tags/wysiwyg.rb +3 -1
- data/lib/comfortable_mexican_sofa/engine.rb +2 -1
- data/lib/comfortable_mexican_sofa/error.rb +2 -0
- data/lib/comfortable_mexican_sofa/extensions/acts_as_tree.rb +2 -0
- data/lib/comfortable_mexican_sofa/extensions/has_revisions.rb +2 -0
- data/lib/comfortable_mexican_sofa/form_builder.rb +24 -17
- data/lib/comfortable_mexican_sofa/render_methods.rb +2 -0
- data/lib/comfortable_mexican_sofa/routes/cms.rb +2 -0
- data/lib/comfortable_mexican_sofa/routes/cms_admin.rb +2 -0
- data/lib/comfortable_mexican_sofa/routing.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds.rb +3 -1
- data/lib/comfortable_mexican_sofa/seeds/file/exporter.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/file/importer.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/layout/exporter.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/layout/importer.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/page/exporter.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/page/importer.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/snippet/exporter.rb +2 -0
- data/lib/comfortable_mexican_sofa/seeds/snippet/importer.rb +2 -0
- data/lib/comfortable_mexican_sofa/version.rb +3 -1
- data/lib/comfortable_mexican_sofa/view_hooks.rb +2 -0
- data/lib/generators/comfy/cms/assets_generator.rb +2 -0
- data/lib/generators/comfy/cms/cms_generator.rb +6 -4
- data/lib/generators/comfy/cms/controllers_generator.rb +2 -0
- data/lib/generators/comfy/cms/models_generator.rb +2 -0
- data/lib/generators/comfy/cms/views_generator.rb +2 -0
- data/lib/generators/comfy/scaffold/scaffold_generator.rb +6 -2
- data/lib/tasks/cms_seeds.rake +2 -0
- metadata +20 -26
- data/app/assets/javascripts/comfy/admin/cms/application.js.coffee +0 -30
- data/app/assets/javascripts/comfy/admin/cms/base.js.coffee +0 -224
- data/app/assets/javascripts/comfy/admin/cms/custom.js.coffee +0 -1
- data/app/assets/javascripts/comfy/admin/cms/files.js.coffee +0 -29
- data/app/assets/javascripts/comfy/admin/cms/uploader.js.coffee +0 -140
- data/app/views/comfy/admin/cms/files/create.js.erb +0 -1
- data/app/views/comfy/admin/cms/files/destroy.js.coffee +0 -2
- data/app/views/comfy/admin/cms/pages/form_fragments.js.erb +0 -1
- data/app/views/comfy/admin/cms/translations/form_fragments.js.erb +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b4189f8584e5fbfcc3083d72b892dee0d17407e1893674eed30927e6e5c6d336
|
|
4
|
+
data.tar.gz: '02964679fbddf7a9f1c46dc35482d11a6a3736409a32daa4a137d0600a921d3d'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 47387e45ccebcad1bc3429c6b64633dfd9cc8f0810f7c28745dc578f391404e57a16fb8bd1ecd221acdd6701710aded9ee318eb2b110f7d7374e63063fc472b0
|
|
7
|
+
data.tar.gz: d16d2d2aaeb92e761c6b3559816f33e1339dd239f8691d6b8194bc5cf60d67ec0dbe34aae18ee2cc2a4f1bf24b15edc4105812bcd4427d04b048a850bc339819
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
language: ruby
|
|
2
2
|
rvm:
|
|
3
|
-
- 2.2.9
|
|
4
3
|
- 2.3.6
|
|
5
4
|
- 2.4.3
|
|
6
5
|
- 2.5.0
|
|
6
|
+
- ruby-head
|
|
7
7
|
gemfile:
|
|
8
8
|
- test/gemfiles/5.2.gemfile
|
|
9
9
|
branches:
|
|
@@ -19,7 +19,7 @@ before_install:
|
|
|
19
19
|
- gem update --system
|
|
20
20
|
- gem update bundler
|
|
21
21
|
before_script:
|
|
22
|
-
- wget http://chromedriver.storage.googleapis.com/2.
|
|
22
|
+
- wget http://chromedriver.storage.googleapis.com/2.36/chromedriver_linux64.zip
|
|
23
23
|
- unzip chromedriver_linux64.zip
|
|
24
24
|
- sudo apt-get install libnss3
|
|
25
25
|
- sudo apt-get --only-upgrade install google-chrome-stable
|
|
@@ -33,3 +33,6 @@ script:
|
|
|
33
33
|
- bundle exec rake test
|
|
34
34
|
- SKIP_COV=true bundle exec rake test:system
|
|
35
35
|
- bundle exec rubocop
|
|
36
|
+
matrix:
|
|
37
|
+
allow_failures:
|
|
38
|
+
- rvm: ruby-head
|
data/Gemfile
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
source "http://rubygems.org"
|
|
2
4
|
|
|
3
5
|
gemspec
|
|
4
6
|
|
|
5
7
|
group :development, :test do
|
|
8
|
+
gem "autoprefixer-rails", "~> 8.1.0"
|
|
6
9
|
gem "byebug", "~> 10.0.0", platforms: %i[mri mingw x64_mingw]
|
|
7
10
|
gem "capybara", "~> 2.17.0"
|
|
8
11
|
gem "kaminari", "~> 1.1.1"
|
|
@@ -19,6 +22,8 @@ end
|
|
|
19
22
|
|
|
20
23
|
group :test do
|
|
21
24
|
gem "coveralls", "~> 0.8.21", require: false
|
|
25
|
+
gem "diffy", "~> 3.2.0"
|
|
26
|
+
gem "equivalent-xml", "~> 0.6.0"
|
|
22
27
|
gem "mocha", "~> 1.3.0", require: false
|
|
23
28
|
gem "rails-controller-testing", "~> 1.0.2"
|
|
24
29
|
end
|
data/Rakefile
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//= require rails-ujs
|
|
2
|
+
//= require jquery3
|
|
3
|
+
|
|
4
|
+
//= require comfy/vendor/codemirror
|
|
5
|
+
//= require comfy/vendor/codemirror/mode/css/css
|
|
6
|
+
//= require comfy/vendor/codemirror/mode/htmlmixed/htmlmixed
|
|
7
|
+
//= require comfy/vendor/codemirror/mode/javascript/javascript
|
|
8
|
+
//= require comfy/vendor/codemirror/mode/markdown/markdown
|
|
9
|
+
//= require comfy/vendor/codemirror/mode/xml/xml
|
|
10
|
+
//= require comfy/vendor/codemirror/addon/edit/closetag
|
|
11
|
+
//= require comfy/vendor/sortable.min
|
|
12
|
+
//= require comfy/vendor/popper.min
|
|
13
|
+
//= require comfy/vendor/bootstrap.min
|
|
14
|
+
//= require comfy/vendor/diff/diff_match_patch.min
|
|
15
|
+
//= require comfy/vendor/diff/pretty_text_diff
|
|
16
|
+
//= require comfy/vendor/fontawesome
|
|
17
|
+
//= require comfy/vendor/redactor
|
|
18
|
+
//= require comfy/vendor/redactor/filemanager
|
|
19
|
+
//= require comfy/vendor/redactor/imagemanager
|
|
20
|
+
//= require comfy/vendor/redactor/definedlinks
|
|
21
|
+
//= require comfy/vendor/redactor/table
|
|
22
|
+
//= require comfy/vendor/redactor/video
|
|
23
|
+
//= require_directory ../../vendor/redactor/i18n/
|
|
24
|
+
//= require comfy/vendor/flatpickr.min
|
|
25
|
+
//= require_directory ../../vendor/flatpickr/i18n/
|
|
26
|
+
|
|
27
|
+
//= require comfy/admin/cms/base
|
|
28
|
+
//= require comfy/admin/cms/categories
|
|
29
|
+
//= require comfy/admin/cms/codemirror
|
|
30
|
+
//= require comfy/admin/cms/diff
|
|
31
|
+
//= require comfy/admin/cms/file_link
|
|
32
|
+
//= require comfy/admin/cms/file_upload
|
|
33
|
+
//= require comfy/admin/cms/files_modal
|
|
34
|
+
//= require comfy/admin/cms/page_fragments
|
|
35
|
+
//= require comfy/admin/cms/sortable_list
|
|
36
|
+
//= require comfy/admin/cms/slugify
|
|
37
|
+
//= require comfy/admin/cms/timepicker
|
|
38
|
+
//= require comfy/admin/cms/wysiwyg
|
|
39
|
+
|
|
40
|
+
//= require comfy/admin/cms/custom
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
if (!window.CMS) window.CMS = {};
|
|
3
|
+
const CMS = window.CMS;
|
|
4
|
+
|
|
5
|
+
// TODO(glebm): Use the battle-tested universal onPageLoad code and enable Turbolinks+async in the demo app.
|
|
6
|
+
// See: https://gist.github.com/glebm/2496daf445877055447a6fac46509d9a
|
|
7
|
+
const isTurbolinks = 'Turbolinks' in window && window.Turbolinks.supported;
|
|
8
|
+
if (isTurbolinks) {
|
|
9
|
+
document.addEventListener('turbolinks:load', () => {
|
|
10
|
+
window.CMS.init();
|
|
11
|
+
});
|
|
12
|
+
document.addEventListener('turbolinks:before-cache', () => {
|
|
13
|
+
window.CMS.dispose();
|
|
14
|
+
});
|
|
15
|
+
} else {
|
|
16
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
17
|
+
window.CMS.init();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
CMS.init = () => {
|
|
22
|
+
CMS.current_path = window.location.pathname;
|
|
23
|
+
CMS.slugify();
|
|
24
|
+
CMS.codemirror.init();
|
|
25
|
+
CMS.wysiwyg.init();
|
|
26
|
+
CMS.sortableList.init();
|
|
27
|
+
CMS.timepicker.init();
|
|
28
|
+
CMS.pageFragments();
|
|
29
|
+
CMS.categories();
|
|
30
|
+
CMS.files.init();
|
|
31
|
+
CMS.fileLinks();
|
|
32
|
+
CMS.fileUpload.init();
|
|
33
|
+
CMS.diff();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
CMS.dispose = () => {
|
|
37
|
+
CMS.codemirror.dispose();
|
|
38
|
+
CMS.wysiwyg.dispose();
|
|
39
|
+
CMS.files.dispose();
|
|
40
|
+
CMS.fileUpload.dispose();
|
|
41
|
+
CMS.sortableList.dispose();
|
|
42
|
+
CMS.timepicker.dispose();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
CMS.getLocale = () => document.querySelector('meta[name="cms-locale"]').content;
|
|
46
|
+
})();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
window.CMS.categories = (root = document) => {
|
|
3
|
+
const widget = root.querySelector('.categories-widget');
|
|
4
|
+
if (widget === null) return;
|
|
5
|
+
const readSection = widget.querySelector('.read');
|
|
6
|
+
const editSection = widget.querySelector('.editable');
|
|
7
|
+
widget.querySelector('.read button.toggle-cat-edit').addEventListener('click', () => {
|
|
8
|
+
readSection.style.display = 'none';
|
|
9
|
+
editSection.style.display = 'block';
|
|
10
|
+
});
|
|
11
|
+
widget.querySelector('.editable button.toggle-cat-edit').addEventListener('click', () => {
|
|
12
|
+
editSection.style.display = 'none';
|
|
13
|
+
readSection.style.display = 'block';
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
})();
|
|
17
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const codeMirrorInstances = [];
|
|
3
|
+
window.CMS.codemirror = {
|
|
4
|
+
init(root = document) {
|
|
5
|
+
for (const textarea of root.querySelectorAll('textarea[data-cms-cm-mode]')) {
|
|
6
|
+
const codemirror = CodeMirror.fromTextArea(textarea, {
|
|
7
|
+
mode: textarea.dataset.cmsCmMode,
|
|
8
|
+
tabSize: 2,
|
|
9
|
+
lineWrapping: true,
|
|
10
|
+
autoCloseTags: true,
|
|
11
|
+
lineNumbers: true,
|
|
12
|
+
viewportMargin: Infinity
|
|
13
|
+
});
|
|
14
|
+
codeMirrorInstances.push(codemirror);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const tabsRoot = root.id === 'form-fragments' ? root : root.querySelector('#form-fragments');
|
|
18
|
+
jQuery(tabsRoot).find('a[data-toggle="tab"]').on('shown.bs.tab', () => {
|
|
19
|
+
for (const codemirror of codeMirrorInstances) {
|
|
20
|
+
codemirror.refresh();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
dispose() {
|
|
25
|
+
for (const codemirror of codeMirrorInstances) {
|
|
26
|
+
codemirror.toTextArea();
|
|
27
|
+
}
|
|
28
|
+
codeMirrorInstances.length = 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Custom JS for the admin area
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const isFirefox = /\bFirefox\//.test(navigator.userAgent);
|
|
3
|
+
|
|
4
|
+
class FileLink {
|
|
5
|
+
constructor(link) {
|
|
6
|
+
this.link = link;
|
|
7
|
+
this.isImage = !!link.dataset.cmsFileThumbUrl;
|
|
8
|
+
|
|
9
|
+
link.addEventListener('dragstart', (evt) => {
|
|
10
|
+
evt.dataTransfer.setData('text/plain', this.link.dataset.cmsFileLinkTag);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (this.isImage) {
|
|
14
|
+
new bootstrap.Popover(link, {
|
|
15
|
+
container: link.parentElement,
|
|
16
|
+
trigger: 'hover',
|
|
17
|
+
placement: 'top',
|
|
18
|
+
content: this.buildFileThumbnail(),
|
|
19
|
+
html: true
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
link.addEventListener('dragstart', (evt) => {
|
|
23
|
+
evt.dataTransfer.setDragImage(this.buildFileThumbnail(), 4, 2);
|
|
24
|
+
this.getPopover().hide();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
this.workAroundFirefoxPopoverGlitch();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buildFileThumbnail() {
|
|
32
|
+
const img = new Image();
|
|
33
|
+
img.src = this.link.dataset.cmsFileThumbUrl;
|
|
34
|
+
return img;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// To work around a Firefox bug causing the popover to re-appear after the drop:
|
|
38
|
+
// https://github.com/comfy/comfortable-mexican-sofa/pull/799#issuecomment-369124161
|
|
39
|
+
//
|
|
40
|
+
// Possibly related to:
|
|
41
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=505521
|
|
42
|
+
workAroundFirefoxPopoverGlitch() {
|
|
43
|
+
if (!isFirefox) return;
|
|
44
|
+
this.link.addEventListener('dragstart', () => {
|
|
45
|
+
this.getPopover().disable();
|
|
46
|
+
});
|
|
47
|
+
this.link.addEventListener('dragend', () => {
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
const popover = this.getPopover();
|
|
50
|
+
popover.enable();
|
|
51
|
+
popover.hide();
|
|
52
|
+
}, 300);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// We can't keep a reference to the Popover object, because Bootstrap re-creates it internally.
|
|
57
|
+
getPopover() {
|
|
58
|
+
return jQuery(this.link).data(bootstrap.Popover.DATA_KEY);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
window.CMS.fileLinks = (root = document) => {
|
|
63
|
+
for (const link of root.querySelectorAll('[data-cms-file-link-tag]')) {
|
|
64
|
+
new FileLink(link);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
})();
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
//= require comfy/vendor/moxie.min
|
|
2
|
+
//= require comfy/vendor/plupload.dev
|
|
3
|
+
|
|
4
|
+
(() => {
|
|
5
|
+
const DROP_TARGET_ACTIVE_CLASS = 'cms-uploader-drag-drop-target-active';
|
|
6
|
+
|
|
7
|
+
class FileUpload {
|
|
8
|
+
constructor(container, settings) {
|
|
9
|
+
if (!container.id) container.id = plupload.guid();
|
|
10
|
+
settings = Object.assign(FileUpload.defaultUploaderSettings(container.id), settings);
|
|
11
|
+
this.ui = {
|
|
12
|
+
container,
|
|
13
|
+
list: container.querySelector('.cms-uploader-filelist'),
|
|
14
|
+
dropElement: container.querySelector(`#${settings.drop_element}`),
|
|
15
|
+
};
|
|
16
|
+
this.cleanupFns = [];
|
|
17
|
+
this.uploader = new plupload.Uploader(settings);
|
|
18
|
+
this.uploader.bind('PostInit', () => this.onUploaderPostInit());
|
|
19
|
+
this.uploader.bind('Error', (_uploader, error) => this.onUploaderError(error));
|
|
20
|
+
this.uploader.bind('FilesAdded', (_uploader, files) => this.onUploaderFilesAdded(files));
|
|
21
|
+
this.uploader.bind('UploadProgress', (_uploader, file) => this.onUploaderUploadProgress(file));
|
|
22
|
+
this.uploader.bind('FileUploaded', (_uploader, file, info) => this.onUploaderFileUploaded(file, info));
|
|
23
|
+
this.uploader.bind('FilesRemoved', (_uploader, files) => this.onUploaderFilesRemoved(files));
|
|
24
|
+
this.uploader.init();
|
|
25
|
+
if (settings.setup) {
|
|
26
|
+
settings.setup(this.uploader);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
destroy() {
|
|
31
|
+
this.uploader.destroy();
|
|
32
|
+
for (const cleanupFn of this.cleanupFns) {
|
|
33
|
+
cleanupFn();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
addCleanup(cleanupFn) {
|
|
38
|
+
this.cleanupFns.push(cleanupFn);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onUploaderPostInit() {
|
|
42
|
+
// Show drag and drop info and attach events only if drag and drop is enabled and supported.
|
|
43
|
+
if (!this.uploader.settings.dragdrop || !this.uploader.features.dragdrop) {
|
|
44
|
+
this.ui.container.querySelector('.cms-uploader-drag-drop-info').style.display = 'none';
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// When dragging over the document add a class to the drop target that puts it on top of every element and remove
|
|
48
|
+
// that class when dropping or leaving the drop target. Otherwise the dragleave event would fire whenever we drag
|
|
49
|
+
// over a child element inside the drop target such as text nodes.
|
|
50
|
+
const onDragEnter = (e) => {
|
|
51
|
+
// Only react to drag'n'drops that contain a file. See:
|
|
52
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
|
|
53
|
+
if (e.dataTransfer.types.includes('Files')) {
|
|
54
|
+
this.ui.dropElement.classList.add(DROP_TARGET_ACTIVE_CLASS);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
document.addEventListener('dragenter', onDragEnter);
|
|
58
|
+
this.addCleanup(() => {
|
|
59
|
+
document.removeEventListener('dragenter', onDragEnter);
|
|
60
|
+
});
|
|
61
|
+
for (const eventName of ['drop', 'dragleave']) {
|
|
62
|
+
this.ui.dropElement.addEventListener(eventName, () => {
|
|
63
|
+
this.ui.dropElement.classList.remove(DROP_TARGET_ACTIVE_CLASS);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onUploaderError(error) {
|
|
69
|
+
if (error.code === plupload.INIT_ERROR) {
|
|
70
|
+
window.alert('Error: Initialisation error. Reload to try again.');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const file = error.file;
|
|
74
|
+
if (!file) return;
|
|
75
|
+
// Get error message from the server response. Not all runtimes support this.
|
|
76
|
+
let message = error.response;
|
|
77
|
+
// If no error message is in the server response get standard plupload error messages.
|
|
78
|
+
// This will have descriptive error message for something like file size or file format errors but for
|
|
79
|
+
// server errors it will only display a general error message.
|
|
80
|
+
if (!message) {
|
|
81
|
+
message = error.message;
|
|
82
|
+
if (error.details) message += ` (${error.details})`;
|
|
83
|
+
}
|
|
84
|
+
file.status = plupload.FAILED;
|
|
85
|
+
file.error_message = message;
|
|
86
|
+
this.updateFileStatus(file);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
onUploaderFilesAdded(files) {
|
|
90
|
+
for (const file of files) {
|
|
91
|
+
this.addFile(file);
|
|
92
|
+
}
|
|
93
|
+
// Auto start upload when files are added.
|
|
94
|
+
this.uploader.start();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
onUploaderUploadProgress(file) {
|
|
98
|
+
this.updateFileStatus(file);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
onUploaderFileUploaded(file, info) {
|
|
102
|
+
// Replace the dummy file entry in the file list with the the entry from the server response.
|
|
103
|
+
const template = document.createElement('template');
|
|
104
|
+
template.innerHTML = info.response;
|
|
105
|
+
const newListItem = template.content.firstElementChild;
|
|
106
|
+
this.ui.list.replaceChild(newListItem, this.fileListItem(file));
|
|
107
|
+
window.CMS.fileLinks(newListItem);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onUploaderFilesRemoved(files) {
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
this.removeFile(file);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
addFile(file) {
|
|
117
|
+
this.ui.list.insertAdjacentHTML('afterbegin', FileUpload.buildListItemHTML(file));
|
|
118
|
+
this.fileListItem(file).querySelector('.cms-uploader-file-delete').addEventListener('click', (evt) => {
|
|
119
|
+
evt.preventDefault();
|
|
120
|
+
this.uploader.removeFile(file);
|
|
121
|
+
});
|
|
122
|
+
this.updateFileStatus(file);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
removeFile(file) {
|
|
126
|
+
this.fileListItem(file).remove();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
updateFileStatus(file) {
|
|
130
|
+
const progressBar = this.fileListItem(file).querySelector('.progress-bar');
|
|
131
|
+
switch (file.status) {
|
|
132
|
+
case plupload.UPLOADING:
|
|
133
|
+
progressBar.style.width = `${file.percent}%`;
|
|
134
|
+
break;
|
|
135
|
+
case plupload.FAILED:
|
|
136
|
+
progressBar.style.width = '100%';
|
|
137
|
+
progressBar.classList.add('progress-bar-danger');
|
|
138
|
+
progressBar.querySelector('span').innerHTML = file.error_message;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
fileListItem({id}) {
|
|
144
|
+
return this.ui.container.querySelector(`#${id}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static buildListItemHTML({id, name}) {
|
|
148
|
+
return `<li id='${id}' class='row temp'>
|
|
149
|
+
<div class='col-md-9 d-flex align-items-center'>
|
|
150
|
+
<div class='progress'>
|
|
151
|
+
<div class='progress-bar progress-bar-striped progress-bar-animated'>
|
|
152
|
+
<span>${name}</span>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
<div class='col-md-3 d-flex align-items-center justify-content-md-end'>
|
|
157
|
+
<a class='btn btn-sm btn-danger float-right cms-uploader-file-delete' href='#'>Delete</a>
|
|
158
|
+
</div>
|
|
159
|
+
</li>`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static defaultUploaderSettings(id) {
|
|
163
|
+
return {
|
|
164
|
+
runtimes: 'html5,browserplus,silverlight,flash,gears',
|
|
165
|
+
dragdrop: true,
|
|
166
|
+
drop_element: `${id}-drag-drop-target`,
|
|
167
|
+
browse_button: `${id}-browse`,
|
|
168
|
+
container: id,
|
|
169
|
+
file_data_name: 'file[file]',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const uploaders = [];
|
|
175
|
+
window.CMS.fileUpload = {
|
|
176
|
+
init(root = document) {
|
|
177
|
+
const el = root.querySelector('#cms-uploader');
|
|
178
|
+
if (el === null) return;
|
|
179
|
+
uploaders.push(new FileUpload(el, {
|
|
180
|
+
url: el.dataset.cmsUploaderUrl,
|
|
181
|
+
multipart_params: {
|
|
182
|
+
[el.dataset.cmsUploaderTokenName]: el.dataset.cmsUploaderTokenValue,
|
|
183
|
+
[el.dataset.cmsUploaderSessionName]: el.dataset.cmsUploaderSessionValue
|
|
184
|
+
}
|
|
185
|
+
}));
|
|
186
|
+
},
|
|
187
|
+
dispose() {
|
|
188
|
+
for (const uploader of uploader) {
|
|
189
|
+
uploader.dispose();
|
|
190
|
+
}
|
|
191
|
+
uploaders.length = 0;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
})();
|