comfortable_mexican_sofa 2.0.12 → 2.0.13
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
})();
|