decidim-core 0.25.2 → 0.26.0.rc1

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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/activity_cell.rb +2 -1
  3. data/app/cells/decidim/author/flag_user.erb +1 -1
  4. data/app/cells/decidim/author/profile_inline.erb +1 -1
  5. data/app/cells/decidim/author/withdraw.erb +2 -2
  6. data/app/cells/decidim/author_cell.rb +32 -0
  7. data/app/cells/decidim/card_m_cell.rb +1 -1
  8. data/app/cells/decidim/content_blocks/cta_cell.rb +1 -1
  9. data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
  10. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  11. data/app/cells/decidim/content_blocks/last_activity_cell.rb +1 -1
  12. data/app/cells/decidim/content_blocks/stats_cell.rb +12 -0
  13. data/app/cells/decidim/endorsers_list_cell.rb +3 -1
  14. data/app/cells/decidim/flag_modal/flag_user.erb +2 -2
  15. data/app/cells/decidim/flag_modal/show.erb +2 -2
  16. data/app/cells/decidim/flag_modal_cell.rb +10 -0
  17. data/app/cells/decidim/notification/show.erb +31 -0
  18. data/app/cells/decidim/notification_cell.rb +20 -0
  19. data/app/cells/decidim/notifications/show.erb +1 -24
  20. data/app/cells/decidim/notifications_cell.rb +0 -1
  21. data/app/cells/decidim/user_conversation/conversation_header.erb +1 -1
  22. data/app/cells/decidim/user_conversation/show.erb +4 -2
  23. data/app/cells/decidim/user_conversations/conversation_item.erb +1 -1
  24. data/app/commands/decidim/create_editor_image.rb +41 -0
  25. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  26. data/app/controllers/decidim/editor_images_controller.rb +47 -0
  27. data/app/controllers/decidim/user_activities_controller.rb +2 -1
  28. data/app/forms/decidim/editor_image_form.rb +16 -0
  29. data/app/helpers/decidim/amendments_helper.rb +1 -1
  30. data/app/helpers/decidim/application_helper.rb +2 -2
  31. data/app/helpers/decidim/messaging/conversation_helper.rb +32 -3
  32. data/app/helpers/decidim/resource_versions_helper.rb +1 -1
  33. data/app/helpers/decidim/sanitize_helper.rb +65 -0
  34. data/app/models/decidim/editor_image.rb +14 -0
  35. data/app/models/decidim/messaging/conversation.rb +9 -0
  36. data/app/models/decidim/participatory_space_private_user.rb +16 -0
  37. data/app/models/decidim/user.rb +3 -3
  38. data/app/models/decidim/user_group.rb +40 -0
  39. data/app/packs/entrypoints/decidim_core.js +1 -0
  40. data/app/packs/src/decidim/dialog_mode.js +143 -0
  41. data/app/packs/src/decidim/dialog_mode.test.js +168 -0
  42. data/app/packs/src/decidim/editor.js +56 -14
  43. data/app/packs/src/decidim/form_attachments.js +5 -0
  44. data/app/packs/src/decidim/index.js +4 -0
  45. data/app/packs/src/decidim/vendor/image-resize.min.js +3 -0
  46. data/app/packs/src/decidim/vendor/image-upload.min.js +8 -0
  47. data/app/packs/stylesheets/decidim/extras/_extras.scss +0 -1
  48. data/app/packs/stylesheets/decidim/extras/_quill.scss +7 -0
  49. data/app/packs/stylesheets/decidim/modules/_buttons.scss +11 -4
  50. data/app/packs/stylesheets/decidim/modules/_cards.scss +4 -0
  51. data/app/packs/stylesheets/decidim/modules/_layout.scss +1 -1
  52. data/app/presenters/decidim/nil_presenter.rb +2 -2
  53. data/app/presenters/decidim/notification_presenter.rb +25 -0
  54. data/app/presenters/decidim/official_author_presenter.rb +1 -1
  55. data/app/presenters/decidim/validation_errors_presenter.rb +27 -0
  56. data/app/queries/decidim/similar_emendations.rb +1 -1
  57. data/app/resolvers/decidim/core/metric_resolver.rb +1 -1
  58. data/app/services/decidim/activity_search.rb +2 -2
  59. data/app/services/decidim/email_notification_generator.rb +4 -1
  60. data/app/services/decidim/html_truncation.rb +130 -0
  61. data/app/services/decidim/open_data_exporter.rb +29 -5
  62. data/app/services/decidim/resource_search.rb +1 -1
  63. data/app/uploaders/decidim/editor_image_uploader.rb +6 -0
  64. data/app/validators/password_validator.rb +123 -0
  65. data/app/views/decidim/account/_password_fields.html.erb +1 -1
  66. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  67. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  68. data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +6 -4
  69. data/app/views/decidim/messaging/conversations/_conversation.html.erb +3 -3
  70. data/app/views/decidim/messaging/conversations/_messages.html.erb +8 -2
  71. data/app/views/decidim/messaging/conversations/_show.html.erb +10 -12
  72. data/app/views/decidim/messaging/conversations/show.html.erb +4 -2
  73. data/app/views/decidim/newsletters/show.html.erb +1 -1
  74. data/app/views/decidim/notification_mailer/event_received.html.erb +17 -0
  75. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  76. data/app/views/decidim/searches/_filters_small_view.html.erb +3 -3
  77. data/app/views/decidim/shared/_login_modal.html.erb +5 -5
  78. data/app/views/decidim/shared/_orders.html.erb +1 -1
  79. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  80. data/app/views/decidim/shared/participatory_space_filters/_filters_small_view.html.erb +3 -3
  81. data/app/views/layouts/decidim/_application.html.erb +1 -12
  82. data/app/views/layouts/decidim/_head.html.erb +4 -0
  83. data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
  84. data/app/views/layouts/decidim/_meta_tags_config.html.erb +11 -0
  85. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  86. data/config/brakeman.ignore +149 -0
  87. data/config/initializers/devise.rb +1 -1
  88. data/config/initializers/rack_attack.rb +23 -21
  89. data/config/locales/ca.yml +2 -0
  90. data/config/locales/cs.yml +60 -0
  91. data/config/locales/en.yml +45 -0
  92. data/config/locales/es.yml +45 -0
  93. data/config/locales/eu.yml +5 -0
  94. data/config/locales/fi-plain.yml +6 -0
  95. data/config/locales/fi.yml +45 -0
  96. data/config/locales/fr-CA.yml +38 -0
  97. data/config/locales/fr.yml +44 -6
  98. data/config/locales/gl.yml +5 -0
  99. data/config/locales/it.yml +11 -0
  100. data/config/locales/ja.yml +72 -36
  101. data/config/locales/lb-LU.yml +1354 -0
  102. data/config/locales/lb.yml +1 -1
  103. data/config/locales/nl.yml +54 -0
  104. data/config/locales/pl.yml +5 -5
  105. data/config/locales/pt-BR.yml +1 -1
  106. data/config/locales/ro-RO.yml +8 -0
  107. data/config/locales/sv.yml +5 -0
  108. data/config/locales/val-ES.yml +1 -0
  109. data/config/routes.rb +2 -0
  110. data/db/migrate/20210730112319_create_decidim_editor_images.rb +12 -0
  111. data/db/migrate/20211126183540_add_timestamps_to_content_blocks.rb +14 -0
  112. data/db/seeds.rb +16 -14
  113. data/lib/decidim/api/functions/user_entity_list.rb +1 -0
  114. data/lib/decidim/api/input_sorts/component_input_sort.rb +1 -1
  115. data/lib/decidim/common_passwords.rb +56 -0
  116. data/lib/decidim/content_parsers/inline_images_parser.rb +68 -0
  117. data/lib/decidim/content_parsers.rb +1 -0
  118. data/lib/decidim/content_renderers/link_renderer.rb +85 -1
  119. data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
  120. data/lib/decidim/content_renderers/user_renderer.rb +1 -1
  121. data/lib/decidim/core/engine.rb +3 -12
  122. data/lib/decidim/core/test/factories.rb +7 -1
  123. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +131 -0
  124. data/lib/decidim/core/test.rb +1 -0
  125. data/lib/decidim/core/version.rb +1 -1
  126. data/lib/decidim/core.rb +22 -5
  127. data/lib/decidim/db/common-passwords.txt +128420 -0
  128. data/lib/decidim/etherpad/pad.rb +48 -0
  129. data/lib/decidim/etherpad.rb +7 -0
  130. data/lib/decidim/events/base_event.rb +18 -0
  131. data/lib/decidim/events/machine_translated_event.rb +36 -0
  132. data/lib/decidim/events/user_group_event.rb +1 -3
  133. data/lib/decidim/events.rb +1 -0
  134. data/lib/decidim/exporters/csv.rb +7 -7
  135. data/lib/decidim/faker/localized.rb +15 -6
  136. data/lib/decidim/form_builder.rb +14 -4
  137. data/lib/decidim/has_attachments.rb +11 -4
  138. data/lib/decidim/importers/import_manifest.rb +103 -3
  139. data/lib/decidim/paddable.rb +1 -9
  140. data/lib/decidim/searchable.rb +2 -2
  141. data/lib/decidim/settings_manifest.rb +2 -0
  142. data/lib/decidim/translatable_attributes.rb +6 -6
  143. data/lib/decidim/view_model.rb +10 -0
  144. data/lib/tasks/decidim_active_storage_migration_tasks.rake +68 -0
  145. metadata +56 -65
  146. data/app/packs/stylesheets/decidim/extras/_social_icons_mini.scss +0 -11
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Images attached to editors.
5
+ class EditorImage < ApplicationRecord
6
+ include Decidim::HasUploadValidations
7
+
8
+ belongs_to :author, foreign_key: :decidim_author_id, class_name: "Decidim::User"
9
+ belongs_to :organization, foreign_key: :decidim_organization_id, class_name: "Decidim::Organization"
10
+
11
+ has_one_attached :file
12
+ validates_upload :file, uploader: Decidim::EditorImageUploader
13
+ end
14
+ end
@@ -131,6 +131,15 @@ module Decidim
131
131
  blocked.blank?
132
132
  end
133
133
 
134
+ #
135
+ # Given a user, returns if ALL the interlocutors have their accounts deleted
136
+ #
137
+ # @return Boolean
138
+ #
139
+ def with_deleted_users?(user)
140
+ interlocutors(user).all?(&:deleted?)
141
+ end
142
+
134
143
  #
135
144
  # Given a user, returns if the user is participating in the conversation
136
145
  # for groups being part of a conversation all their admin member are accepted
@@ -22,6 +22,22 @@ module Decidim
22
22
  Decidim::AdminLog::ParticipatorySpacePrivateUserPresenter
23
23
  end
24
24
 
25
+ ransacker :name do
26
+ Arel.sql(%{("decidim_users"."name")::text})
27
+ end
28
+
29
+ ransacker :email do
30
+ Arel.sql(%{("decidim_users"."email")::text})
31
+ end
32
+
33
+ ransacker :invitation_sent_at do
34
+ Arel.sql(%{("invitation_sent_at")::text})
35
+ end
36
+
37
+ ransacker :invitation_accepted_at do
38
+ Arel.sql(%{("invitation_accepted_at")::text})
39
+ end
40
+
25
41
  private
26
42
 
27
43
  # Private: check if the participatory space and the user have the same organization
@@ -73,7 +73,7 @@ module Decidim
73
73
  actual_ids = scope_ids.select(&:presence)
74
74
  if actual_ids.count.positive?
75
75
  ids = actual_ids.map(&:to_i).join(",")
76
- where("extended_data->'interested_scopes' @> ANY('{#{ids}}')")
76
+ where(Arel.sql("extended_data->'interested_scopes' @> ANY('{#{ids}}')").to_s)
77
77
  else
78
78
  # Do not apply the scope filter when there are scope ids available. Note
79
79
  # that the active record scope must always return an active record
@@ -92,8 +92,8 @@ module Decidim
92
92
  A: :name,
93
93
  datetime: :created_at
94
94
  },
95
- index_on_create: ->(user) { !user.deleted? },
96
- index_on_update: ->(user) { !user.deleted? })
95
+ index_on_create: ->(user) { !(user.deleted? || user.blocked?) },
96
+ index_on_update: ->(user) { !(user.deleted? || user.blocked?) })
97
97
 
98
98
  before_save :ensure_encrypted_password
99
99
 
@@ -144,6 +144,46 @@ module Decidim
144
144
  @unread_messages_count_for[user.id] ||= Decidim::Messaging::Conversation.user_collection(self).unread_messages_by(user).count
145
145
  end
146
146
 
147
+ def self.state_eq(value)
148
+ send(value.to_sym) if %w(all pending rejected verified).include?(value)
149
+ end
150
+
151
+ def self.ransackable_scopes(_auth = nil)
152
+ [:state_eq]
153
+ end
154
+
155
+ scope :sort_by_users_count_asc, lambda {
156
+ order("users_count ASC NULLS FIRST")
157
+ }
158
+
159
+ scope :sort_by_users_count_desc, lambda {
160
+ order("users_count DESC NULLS LAST")
161
+ }
162
+
163
+ def self.sort_by_document_number_asc
164
+ order(Arel.sql("extended_data->>'document_number' ASC"))
165
+ end
166
+
167
+ def self.sort_by_document_number_desc
168
+ order(Arel.sql("extended_data->>'document_number' DESC"))
169
+ end
170
+
171
+ def self.sort_by_phone_asc
172
+ order(Arel.sql("extended_data->>'phone' ASC"))
173
+ end
174
+
175
+ def self.sort_by_phone_desc
176
+ order(Arel.sql("extended_data->>'phone' DESC"))
177
+ end
178
+
179
+ def self.sort_by_state_asc
180
+ order(Arel.sql("extended_data->>'rejected_at' ASC, extended_data->>'verified_at' ASC, deleted_at ASC"))
181
+ end
182
+
183
+ def self.sort_by_state_desc
184
+ order(Arel.sql("extended_data->>'rejected_at' DESC, extended_data->>'verified_at' DESC, deleted_at DESC"))
185
+ end
186
+
147
187
  private
148
188
 
149
189
  # Private: Checks if the state user group is correct.
@@ -31,6 +31,7 @@ import "src/decidim/account_form"
31
31
  import "src/decidim/data_picker"
32
32
  import "src/decidim/dropdowns_menus"
33
33
  import "src/decidim/append_redirect_url_to_modals"
34
+ import "src/decidim/form_attachments"
34
35
  import "src/decidim/form_validator"
35
36
  import "src/decidim/ajax_modals"
36
37
  import "src/decidim/conferences"
@@ -0,0 +1,143 @@
1
+ const focusGuardClass = "focusguard";
2
+ const focusableNodes = ["A", "IFRAME", "OBJECT", "EMBED"];
3
+ const focusableDisableableNodes = ["BUTTON", "INPUT", "TEXTAREA", "SELECT"];
4
+
5
+ const isFocusGuard = (element) => {
6
+ return element.classList.contains(focusGuardClass);
7
+ }
8
+
9
+ const isFocusable = (element) => {
10
+ if (focusableNodes.indexOf(element.nodeName) > -1) {
11
+ return true;
12
+ }
13
+ if (focusableDisableableNodes.indexOf(element.nodeName) > -1 || element.getAttribute("contenteditable")) {
14
+ if (element.getAttribute("disabled")) {
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+
20
+ const tabindex = parseInt(element.getAttribute("tabindex"), 10);
21
+ if (!isNaN(tabindex) && tabindex >= 0) {
22
+ return true;
23
+ }
24
+
25
+ return false;
26
+ }
27
+
28
+ const createFocusGuard = (position) => {
29
+ return $(`<div class="${focusGuardClass}" data-position="${position}" tabindex="0" aria-hidden="true"></div>`);
30
+ };
31
+
32
+ const handleContainerFocus = ($container, $guard) => {
33
+ const $reveal = $(".reveal:visible:last", $container);
34
+ if ($reveal.length > 0) {
35
+ handleContainerFocus($reveal, $guard);
36
+ return;
37
+ }
38
+
39
+ const $nodes = $("*:visible", $container);
40
+ let $target = null;
41
+
42
+ if ($guard.data("position") === "start") {
43
+ // Focus at the start guard, so focus the first focusable element after that
44
+ for (let ind = 0; ind < $nodes.length; ind += 1) {
45
+ if (!isFocusGuard($nodes[ind]) && isFocusable($nodes[ind])) {
46
+ $target = $($nodes[ind]);
47
+ break;
48
+ }
49
+ }
50
+ } else {
51
+ // Focus at the end guard, so focus the first focusable element after that
52
+ for (let ind = $nodes.length - 1; ind >= 0; ind -= 1) {
53
+ if (!isFocusGuard($nodes[ind]) && isFocusable($nodes[ind])) {
54
+ $target = $($nodes[ind]);
55
+ break;
56
+ }
57
+ }
58
+ }
59
+
60
+ if ($target) {
61
+ $target.trigger("focus");
62
+ } else {
63
+ // If no focusable element was found, blur the guard focus
64
+ $guard.blur();
65
+ }
66
+ };
67
+
68
+ /**
69
+ * A method to enable the dialog mode for the given dialog(s).
70
+ *
71
+ * This should be called when the dialog is opened. It implements two things for
72
+ * the dialog:
73
+ * 1. It places the focus to the title element making sure the screen reader
74
+ * focuses in the correct position of the document. Otherwise some screen
75
+ * readers continue reading outside of the document.
76
+ * 2. Document "tab guards" that force the keyboard focus within the modal when
77
+ * the user is using keyboard or keyboard emulating devices for browsing the
78
+ * document.
79
+ *
80
+ * The "tab guards" are added at the top and bottom of the document to keep the
81
+ * user's focus within the dialog if they accidentally or intentionally place
82
+ * the focus outside of the document, e.g. in different window or in the browser
83
+ * address bar. They guard the focus on both sides of the document returning
84
+ * focus back to the first or last focusable element within the dialog.
85
+ *
86
+ * @param {jQuery} $dialogs The jQuery element(s) to apply the mode for.
87
+ * @return {Void} Nothing
88
+ */
89
+ export default ($dialogs) => {
90
+ $dialogs.each((_i, dialog) => {
91
+ const $dialog = $(dialog);
92
+
93
+ const $container = $("body");
94
+ const $title = $(".reveal__title:first", $dialog);
95
+
96
+ if ($title.length > 0) {
97
+ // Focus on the title to make the screen reader to start reading the
98
+ // content within the modal.
99
+ $title.attr("tabindex", $title.attr("tabindex") || -1);
100
+ $title.trigger("focus");
101
+ }
102
+
103
+ // Once the final modal closes, remove the focus guards from the container
104
+ $dialog.off("closed.zf.reveal.focusguard").on("closed.zf.reveal.focusguard", () => {
105
+ $dialog.off("closed.zf.reveal.focusguard");
106
+
107
+ // After the last dialog is closed, the tab guards should be removed.
108
+ // Note that there may be multiple dialogs open on top of each other at
109
+ // the same time.
110
+ if ($(".reveal:visible", $container).length < 1) {
111
+ $(`> .${focusGuardClass}`, $container).remove();
112
+ }
113
+ });
114
+
115
+ // Check if the guards already exists due to some other dialog
116
+ const $guards = $(`> .${focusGuardClass}`, $container);
117
+ if ($guards.length > 0) {
118
+ // Make sure the guards are the first and last element as there have
119
+ // been changes in the DOM.
120
+ $guards.each((_j, guard) => {
121
+ const $guard = $(guard);
122
+ if ($guard.data("position") === "start") {
123
+ $container.prepend($guard);
124
+ } else {
125
+ $container.append($guard);
126
+ }
127
+ });
128
+
129
+ return;
130
+ }
131
+
132
+ // Add guards at the start and end of the document and attach their focus
133
+ // listeners
134
+ const $startGuard = createFocusGuard("start");
135
+ const $endGuard = createFocusGuard("end");
136
+
137
+ $container.prepend($startGuard);
138
+ $container.append($endGuard);
139
+
140
+ $startGuard.on("focus", () => handleContainerFocus($container, $startGuard));
141
+ $endGuard.on("focus", () => handleContainerFocus($container, $endGuard));
142
+ });
143
+ };
@@ -0,0 +1,168 @@
1
+ /* global jest, global */
2
+
3
+ // Mock jQuery because the visibility indicator works differently within jest.
4
+ // This fixes jQuery reporting $(".element").is(":visible") correctly during the
5
+ // tests and within foundation, too.
6
+ jest.mock("jquery", () => {
7
+ const jq = jest.requireActual("jquery");
8
+
9
+ jq.expr.pseudos.visible = (elem) => {
10
+ const display = global.window.getComputedStyle(elem).display;
11
+ return ["inline", "block", "inline-block"].includes(display);
12
+ };
13
+
14
+ return jq;
15
+ });
16
+
17
+ import $ from "jquery"; // eslint-disable-line id-length
18
+ import "foundation-sites";
19
+
20
+ import dialogMode from "./dialog_mode.js";
21
+
22
+ describe("dialogMode", () => {
23
+ const content = `
24
+ <div class="reveal" id="test-modal" data-reveal aria-modal="true" aria-labelledby="test-modal-label">
25
+ <div class="reveal__header">
26
+ <h3 id="test-modal-label" class="reveal__title">Testing modal</h3>
27
+ <button class="close-button" data-close aria-label="Close window"
28
+ type="button">
29
+ <span aria-hidden="true">&times;</span>
30
+ </button>
31
+ </div>
32
+ <div class="row">
33
+ <div class="columns medium-4 medium-centered">
34
+ <p>Here is some content within the modal.</p>
35
+ <button type="button" id="test-modal-button">Button at the bottom</button>
36
+ </div>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="reveal" id="test-modal-2" data-reveal aria-modal="true" aria-labelledby="test-modal-2-label">
41
+ <div class="reveal__header">
42
+ <h3 id="test-modal-2-label" class="reveal__title">Other testing modal</h3>
43
+ <button class="close-button" data-close aria-label="Close window"
44
+ type="button">
45
+ <span aria-hidden="true">&times;</span>
46
+ </button>
47
+ </div>
48
+ <div class="row">
49
+ <div class="columns medium-4 medium-centered">
50
+ <p>Here is some content within the other modal.</p>
51
+ <button type="button" id="test-modal-2-button">Button at the bottom</button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ `;
56
+
57
+ beforeEach(() => {
58
+ $("body").html(content);
59
+
60
+ $(document).foundation();
61
+
62
+ // Make sure all reveals are hidden by default so that their visibility is
63
+ // correctly reported always.
64
+ $(".reveal").css("display", "none");
65
+
66
+ $(document).on("open.zf.reveal", (ev) => {
67
+ dialogMode($(ev.target));
68
+ });
69
+ });
70
+
71
+ it("focuses the title", () => {
72
+ $("#test-modal").foundation("open");
73
+
74
+ const $focused = $(document.activeElement);
75
+ expect($focused.is($("#test-modal-label"))).toBe(true);
76
+ });
77
+
78
+ it("adds the tab guads on both sides of the document", () => {
79
+ $("#test-modal").foundation("open");
80
+
81
+ const $first = $("body *:first");
82
+ const $last = $("body *:last");
83
+
84
+ expect($first[0].outerHTML).toEqual(
85
+ '<div class="focusguard" data-position="start" tabindex="0" aria-hidden="true"></div>'
86
+ );
87
+ expect($last[0].outerHTML).toEqual(
88
+ '<div class="focusguard" data-position="end" tabindex="0" aria-hidden="true"></div>'
89
+ );
90
+ });
91
+
92
+ it("removes the tab guards when the modal is closed", () => {
93
+ const $modal = $("#test-modal");
94
+ $modal.foundation("open");
95
+ $modal.foundation("close");
96
+
97
+ expect($(".focusguard").length).toEqual(0);
98
+ });
99
+
100
+ it("focuses the first focusable element when the start tab guard gets focus", () => {
101
+ const $modal = $("#test-modal");
102
+ $modal.foundation("open");
103
+
104
+ $(".focusguard[data-position='start']").trigger("focus");
105
+
106
+ const $focused = $(document.activeElement);
107
+ expect($focused.is($("#test-modal .close-button"))).toBe(true);
108
+ });
109
+
110
+ it("focuses the last focusable element when the end tab guard gets focus", () => {
111
+ const $modal = $("#test-modal");
112
+ $modal.foundation("open");
113
+
114
+ $(".focusguard[data-position='end']").trigger("focus");
115
+
116
+ const $focused = $(document.activeElement);
117
+ expect($focused.is($("#test-modal-button"))).toBe(true);
118
+ });
119
+
120
+ describe("when multiple modals are opened", () => {
121
+ it("adds the tab guads only once", () => {
122
+ $("#test-modal").foundation("open");
123
+ $("#test-modal-2").foundation("open");
124
+
125
+ expect($(".focusguard[data-position='start']").length).toEqual(1);
126
+ expect($(".focusguard[data-position='end']").length).toEqual(1);
127
+ });
128
+
129
+ it("does not remove the tab guards when modal is closed but there is still another modal open", () => {
130
+ $("#test-modal").foundation("open");
131
+ $("#test-modal-2").foundation("open");
132
+ $("#test-modal-2").foundation("close");
133
+
134
+ expect($(".focusguard[data-position='start']").length).toEqual(1);
135
+ expect($(".focusguard[data-position='end']").length).toEqual(1);
136
+ });
137
+
138
+ it("removes the tab guards when the last modal is closed", () => {
139
+ $("#test-modal").foundation("open");
140
+ $("#test-modal-2").foundation("open");
141
+ $("#test-modal-2").foundation("close");
142
+ $("#test-modal").foundation("close");
143
+
144
+ expect($(".focusguard").length).toEqual(0);
145
+ });
146
+
147
+ describe("within the active modal", () => {
148
+ beforeEach(() => {
149
+ $("#test-modal").foundation("open");
150
+ $("#test-modal-2").foundation("open");
151
+ });
152
+
153
+ it("focuses the first focusable element when the start tab guard gets focus", () => {
154
+ $(".focusguard[data-position='start']").trigger("focus");
155
+
156
+ const $focused = $(document.activeElement);
157
+ expect($focused.is($("#test-modal-2 .close-button"))).toBe(true);
158
+ });
159
+
160
+ it("focuses the last focusable element when the end tab guard gets focus", () => {
161
+ $(".focusguard[data-position='end']").trigger("focus");
162
+
163
+ const $focused = $(document.activeElement);
164
+ expect($focused.is($("#test-modal-2-button"))).toBe(true);
165
+ });
166
+ });
167
+ });
168
+ });
@@ -1,8 +1,10 @@
1
1
  /* eslint-disable require-jsdoc */
2
2
 
3
3
  import lineBreakButtonHandler from "src/decidim/editor/linebreak_module"
4
+ import "src/decidim/vendor/image-resize.min"
5
+ import "src/decidim/vendor/image-upload.min"
4
6
 
5
- const quillFormats = ["bold", "italic", "link", "underline", "header", "list", "video", "image", "alt", "break"];
7
+ const quillFormats = ["bold", "italic", "link", "underline", "header", "list", "video", "image", "alt", "break", "width", "style", "code", "blockquote", "indent"];
6
8
 
7
9
  export default function createQuillEditor(container) {
8
10
  const toolbar = $(container).data("toolbar");
@@ -11,12 +13,16 @@ export default function createQuillEditor(container) {
11
13
  let quillToolbar = [
12
14
  ["bold", "italic", "underline", "linebreak"],
13
15
  [{ list: "ordered" }, { list: "bullet" }],
14
- ["link", "clean"]
16
+ ["link", "clean"],
17
+ ["code", "blockquote"],
18
+ [{ "indent": "-1"}, { "indent": "+1" }]
15
19
  ];
16
20
 
21
+ let addImage = $(container).data("editorImages");
22
+
17
23
  if (toolbar === "full") {
18
24
  quillToolbar = [
19
- [{ header: [1, 2, 3, 4, 5, 6, false] }],
25
+ [{ header: [2, 3, 4, 5, 6, false] }],
20
26
  ...quillToolbar,
21
27
  ["video"]
22
28
  ];
@@ -27,19 +33,48 @@ export default function createQuillEditor(container) {
27
33
  ];
28
34
  }
29
35
 
36
+ if (addImage) {
37
+ quillToolbar.push(["image"]);
38
+ }
39
+
40
+ let modules = {
41
+ linebreak: {},
42
+ toolbar: {
43
+ container: quillToolbar,
44
+ handlers: {
45
+ "linebreak": lineBreakButtonHandler
46
+ }
47
+ }
48
+ };
30
49
  const $input = $(container).siblings('input[type="hidden"]');
31
50
  container.innerHTML = $input.val() || "";
32
-
33
- const quill = new Quill(container, {
34
- modules: {
35
- linebreak: {},
36
- toolbar: {
37
- container: quillToolbar,
38
- handlers: {
39
- "linebreak": lineBreakButtonHandler
40
- }
51
+ const token = $('meta[name="csrf-token"]').attr("content");
52
+ if (addImage) {
53
+ modules.imageResize = {
54
+ modules: ["Resize", "DisplaySize"]
55
+ }
56
+ modules.imageUpload = {
57
+ url: $(container).data("uploadImagesPath"),
58
+ method: "POST",
59
+ name: "image",
60
+ withCredentials: false,
61
+ headers: { "X-CSRF-Token": token },
62
+ callbackOK: (serverResponse, next) => {
63
+ $("div.ql-toolbar").last().removeClass("editor-loading")
64
+ next(serverResponse.url);
65
+ },
66
+ callbackKO: (serverError) => {
67
+ $("div.ql-toolbar").last().removeClass("editor-loading")
68
+ console.log(`Image upload error: ${serverError.message}`);
69
+ },
70
+ checkBeforeSend: (file, next) => {
71
+ $("div.ql-toolbar").last().addClass("editor-loading")
72
+ next(file);
41
73
  }
42
- },
74
+ }
75
+ }
76
+ const quill = new Quill(container, {
77
+ modules: modules,
43
78
  formats: quillFormats,
44
79
  theme: "snow"
45
80
  });
@@ -67,6 +102,13 @@ export default function createQuillEditor(container) {
67
102
  // After editor is ready, linebreak_module deletes two extraneous new lines
68
103
  quill.emitter.emit("editor-ready");
69
104
 
105
+ if (addImage) {
106
+ const text = $(container).data("dragAndDropHelpText");
107
+ $(container).after(`<p class="help-text" style="margin-top:-1.5rem;">${text}</p>`);
108
+ }
109
+
110
+ // After editor is ready, linebreak_module deletes two extraneous new lines
111
+ quill.emitter.emit("editor-ready");
112
+
70
113
  return quill;
71
114
  }
72
-
@@ -0,0 +1,5 @@
1
+ $(() => {
2
+ $("form .attachments_container").on("closed.zf.callout", (event) => {
3
+ $(event.target).remove();
4
+ });
5
+ });
@@ -13,6 +13,7 @@ import CommentsComponent from "src/decidim/comments/comments.component"
13
13
  import DataPicker from "src/decidim/data_picker"
14
14
  import FormFilterComponent from "src/decidim/form_filter"
15
15
  import addInputEmoji from "src/decidim/input_emoji"
16
+ import dialogMode from "src/decidim/dialog_mode"
16
17
 
17
18
  window.Decidim = window.Decidim || {};
18
19
  window.Decidim.config = new Configuration()
@@ -27,6 +28,9 @@ $(() => {
27
28
  window.theDataPicker = new DataPicker($(".data-picker"));
28
29
 
29
30
  $(document).foundation();
31
+ $(document).on("open.zf.reveal", (ev) => {
32
+ dialogMode($(ev.target));
33
+ });
30
34
 
31
35
  fixDropdownMenus();
32
36
 
@@ -0,0 +1,3 @@
1
+ /* eslint-disable */
2
+
3
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ImageResize=e():t.ImageResize=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=38)}([function(t,e){function n(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}t.exports=n},function(t,e,n){var o=n(22),r="object"==typeof self&&self&&self.Object===Object&&self,i=o||r||Function("return this")();t.exports=i},function(t,e){function n(t){return null!=t&&"object"==typeof t}t.exports=n},function(t,e,n){function o(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var o=t[e];this.set(o[0],o[1])}}var r=n(75),i=n(76),a=n(77),s=n(78),u=n(79);o.prototype.clear=r,o.prototype.delete=i,o.prototype.get=a,o.prototype.has=s,o.prototype.set=u,t.exports=o},function(t,e,n){function o(t,e){for(var n=t.length;n--;)if(r(t[n][0],e))return n;return-1}var r=n(8);t.exports=o},function(t,e,n){function o(t){return null==t?void 0===t?u:s:c&&c in Object(t)?i(t):a(t)}var r=n(16),i=n(64),a=n(87),s="[object Null]",u="[object Undefined]",c=r?r.toStringTag:void 0;t.exports=o},function(t,e,n){function o(t,e){var n=t.__data__;return r(e)?n["string"==typeof e?"string":"hash"]:n.map}var r=n(73);t.exports=o},function(t,e,n){var o=n(11),r=o(Object,"create");t.exports=r},function(t,e){function n(t,e){return t===e||t!==t&&e!==e}t.exports=n},function(t,e,n){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.d(e,"a",function(){return r});var r=function t(e){o(this,t),this.onCreate=function(){},this.onDestroy=function(){},this.onUpdate=function(){},this.overlay=e.overlay,this.img=e.img,this.options=e.options,this.requestUpdate=e.onUpdate}},function(t,e,n){function o(t,e,n){"__proto__"==e&&r?r(t,e,{configurable:!0,enumerable:!0,value:n,writable:!0}):t[e]=n}var r=n(21);t.exports=o},function(t,e,n){function o(t,e){var n=i(t,e);return r(n)?n:void 0}var r=n(48),i=n(65);t.exports=o},function(t,e,n){function o(t){return null!=t&&i(t.length)&&!r(t)}var r=n(13),i=n(30);t.exports=o},function(t,e,n){function o(t){if(!i(t))return!1;var e=r(t);return e==s||e==u||e==a||e==c}var r=n(5),i=n(0),a="[object AsyncFunction]",s="[object Function]",u="[object GeneratorFunction]",c="[object Proxy]";t.exports=o},function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,e,n){var o=n(11),r=n(1),i=o(r,"Map");t.exports=i},function(t,e,n){var o=n(1),r=o.Symbol;t.exports=r},function(t,e){function n(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}t.exports=n},function(t,e,n){function o(t,e,n){(void 0===n||i(t[e],n))&&(void 0!==n||e in t)||r(t,e,n)}var r=n(10),i=n(8);t.exports=o},function(t,e,n){function o(t,e,n,l,f){t!==e&&a(e,function(a,c){if(u(a))f||(f=new r),s(t,e,c,n,o,l,f);else{var p=l?l(t[c],a,c+"",t,e,f):void 0;void 0===p&&(p=a),i(t,c,p)}},c)}var r=n(41),i=n(18),a=n(46),s=n(51),u=n(0),c=n(32);t.exports=o},function(t,e,n){function o(t,e){return a(i(t,e,r),t+"")}var r=n(26),i=n(89),a=n(90);t.exports=o},function(t,e,n){var o=n(11),r=function(){try{var t=o(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();t.exports=r},function(t,e,n){(function(e){var n="object"==typeof e&&e&&e.Object===Object&&e;t.exports=n}).call(e,n(107))},function(t,e,n){var o=n(88),r=o(Object.getPrototypeOf,Object);t.exports=r},function(t,e){function n(t,e){return!!(e=null==e?o:e)&&("number"==typeof t||r.test(t))&&t>-1&&t%1==0&&t<e}var o=9007199254740991,r=/^(?:0|[1-9]\d*)$/;t.exports=n},function(t,e){function n(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||o)}var o=Object.prototype;t.exports=n},function(t,e){function n(t){return t}t.exports=n},function(t,e,n){var o=n(47),r=n(2),i=Object.prototype,a=i.hasOwnProperty,s=i.propertyIsEnumerable,u=o(function(){return arguments}())?o:function(t){return r(t)&&a.call(t,"callee")&&!s.call(t,"callee")};t.exports=u},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){(function(t){var o=n(1),r=n(102),i="object"==typeof e&&e&&!e.nodeType&&e,a=i&&"object"==typeof t&&t&&!t.nodeType&&t,s=a&&a.exports===i,u=s?o.Buffer:void 0,c=u?u.isBuffer:void 0,l=c||r;t.exports=l}).call(e,n(14)(t))},function(t,e){function n(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=o}var o=9007199254740991;t.exports=n},function(t,e,n){var o=n(49),r=n(54),i=n(86),a=i&&i.isTypedArray,s=a?r(a):o;t.exports=s},function(t,e,n){function o(t){return a(t)?r(t,!0):i(t)}var r=n(43),i=n(50),a=n(12);t.exports=o},function(t,e,n){"use strict";e.a={modules:["DisplaySize","Toolbar","Resize"],overlayStyles:{position:"absolute",boxSizing:"border-box",border:"1px dashed #444"},handleStyles:{position:"absolute",height:"12px",width:"12px",backgroundColor:"white",border:"1px solid #777",boxSizing:"border-box",opacity:"0.80"},displayStyles:{position:"absolute",font:"12px/1.0 Arial, Helvetica, sans-serif",padding:"4px 8px",textAlign:"center",backgroundColor:"white",color:"#333",border:"1px solid #777",boxSizing:"border-box",opacity:"0.80",cursor:"default"},toolbarStyles:{position:"absolute",top:"-12px",right:"0",left:"0",height:"0",minWidth:"100px",font:"12px/1.0 Arial, Helvetica, sans-serif",textAlign:"center",color:"#333",boxSizing:"border-box",cursor:"default"},toolbarButtonStyles:{display:"inline-block",width:"24px",height:"24px",background:"white",border:"1px solid #999",verticalAlign:"middle"},toolbarButtonSvgStyles:{fill:"#444",stroke:"#444",strokeWidth:"2"}}},function(t,e,n){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var a=n(9);n.d(e,"a",function(){return s});var s=function(t){function e(){var t,n,i,a;o(this,e);for(var s=arguments.length,u=Array(s),c=0;c<s;c++)u[c]=arguments[c];return n=i=r(this,(t=e.__proto__||Object.getPrototypeOf(e)).call.apply(t,[this].concat(u))),i.onCreate=function(){i.display=document.createElement("div"),Object.assign(i.display.style,i.options.displayStyles),i.overlay.appendChild(i.display)},i.onDestroy=function(){},i.onUpdate=function(){if(i.display&&i.img){var t=i.getCurrentSize();if(i.display.innerHTML=t.join(" &times; "),t[0]>120&&t[1]>30)Object.assign(i.display.style,{right:"4px",bottom:"4px",left:"auto"});else if("right"==i.img.style.float){var e=i.display.getBoundingClientRect();Object.assign(i.display.style,{right:"auto",bottom:"-"+(e.height+4)+"px",left:"-"+(e.width+4)+"px"})}else{var n=i.display.getBoundingClientRect();Object.assign(i.display.style,{right:"-"+(n.width+4)+"px",bottom:"-"+(n.height+4)+"px",left:"auto"})}}},i.getCurrentSize=function(){return[i.img.width,Math.round(i.img.width/i.img.naturalWidth*i.img.naturalHeight)]},a=n,r(i,a)}return i(e,t),e}(a.a)},function(t,e,n){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var a=n(9);n.d(e,"a",function(){return s});var s=function(t){function e(){var t,n,i,a;o(this,e);for(var s=arguments.length,u=Array(s),c=0;c<s;c++)u[c]=arguments[c];return n=i=r(this,(t=e.__proto__||Object.getPrototypeOf(e)).call.apply(t,[this].concat(u))),i.onCreate=function(){i.boxes=[],i.addBox("nwse-resize"),i.addBox("nesw-resize"),i.addBox("nwse-resize"),i.addBox("nesw-resize"),i.positionBoxes()},i.onDestroy=function(){i.setCursor("")},i.positionBoxes=function(){var t=-parseFloat(i.options.handleStyles.width)/2+"px",e=-parseFloat(i.options.handleStyles.height)/2+"px";[{left:t,top:e},{right:t,top:e},{right:t,bottom:e},{left:t,bottom:e}].forEach(function(t,e){Object.assign(i.boxes[e].style,t)})},i.addBox=function(t){var e=document.createElement("div");Object.assign(e.style,i.options.handleStyles),e.style.cursor=t,e.style.width=i.options.handleStyles.width+"px",e.style.height=i.options.handleStyles.height+"px",e.addEventListener("mousedown",i.handleMousedown,!1),i.overlay.appendChild(e),i.boxes.push(e)},i.handleMousedown=function(t){i.dragBox=t.target,i.dragStartX=t.clientX,i.preDragWidth=i.img.width||i.img.naturalWidth,i.setCursor(i.dragBox.style.cursor),document.addEventListener("mousemove",i.handleDrag,!1),document.addEventListener("mouseup",i.handleMouseup,!1)},i.handleMouseup=function(){i.setCursor(""),document.removeEventListener("mousemove",i.handleDrag),document.removeEventListener("mouseup",i.handleMouseup)},i.handleDrag=function(t){if(i.img){var e=t.clientX-i.dragStartX;i.dragBox===i.boxes[0]||i.dragBox===i.boxes[3]?i.img.width=Math.round(i.preDragWidth-e):i.img.width=Math.round(i.preDragWidth+e),i.requestUpdate()}},i.setCursor=function(t){[document.body,i.img].forEach(function(e){e.style.cursor=t})},a=n,r(i,a)}return i(e,t),e}(a.a)},function(t,e,n){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var a=n(105),s=n.n(a),u=n(104),c=n.n(u),l=n(106),f=n.n(l),p=n(9);n.d(e,"a",function(){return b});var d=window.Quill.imports.parchment,h=new d.Attributor.Style("float","float"),y=new d.Attributor.Style("margin","margin"),v=new d.Attributor.Style("display","display"),b=function(t){function e(){var t,n,i,a;o(this,e);for(var u=arguments.length,l=Array(u),p=0;p<u;p++)l[p]=arguments[p];return n=i=r(this,(t=e.__proto__||Object.getPrototypeOf(e)).call.apply(t,[this].concat(l))),i.onCreate=function(){i.toolbar=document.createElement("div"),Object.assign(i.toolbar.style,i.options.toolbarStyles),i.overlay.appendChild(i.toolbar),i._defineAlignments(),i._addToolbarButtons()},i.onDestroy=function(){},i.onUpdate=function(){},i._defineAlignments=function(){i.alignments=[{icon:s.a,apply:function(){v.add(i.img,"inline"),h.add(i.img,"left"),y.add(i.img,"0 1em 1em 0")},isApplied:function(){return"left"==h.value(i.img)}},{icon:c.a,apply:function(){v.add(i.img,"block"),h.remove(i.img),y.add(i.img,"auto")},isApplied:function(){return"auto"==y.value(i.img)}},{icon:f.a,apply:function(){v.add(i.img,"inline"),h.add(i.img,"right"),y.add(i.img,"0 0 1em 1em")},isApplied:function(){return"right"==h.value(i.img)}}]},i._addToolbarButtons=function(){var t=[];i.alignments.forEach(function(e,n){var o=document.createElement("span");t.push(o),o.innerHTML=e.icon,o.addEventListener("click",function(){t.forEach(function(t){return t.style.filter=""}),e.isApplied()?(h.remove(i.img),y.remove(i.img),v.remove(i.img)):(i._selectButton(o),e.apply()),i.requestUpdate()}),Object.assign(o.style,i.options.toolbarButtonStyles),n>0&&(o.style.borderLeftWidth="0"),Object.assign(o.children[0].style,i.options.toolbarButtonSvgStyles),e.isApplied()&&i._selectButton(o),i.toolbar.appendChild(o)})},i._selectButton=function(t){t.style.filter="invert(20%)"},a=n,r(i,a)}return i(e,t),e}(p.a)},function(t,e,n){var o=n(17),r=n(20),i=n(63),a=n(101),s=r(function(t){return t.push(void 0,i),o(a,void 0,t)});t.exports=s},function(t,e,n){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var r=n(37),i=n.n(r),a=n(33),s=n(34),u=n(36),c=n(35),l={DisplaySize:s.a,Toolbar:u.a,Resize:c.a},f=function t(e){var n=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,t),this.initializeModules=function(){n.removeModules(),n.modules=n.moduleClasses.map(function(t){return new(l[t]||t)(n)}),n.modules.forEach(function(t){t.onCreate()}),n.onUpdate()},this.onUpdate=function(){n.repositionElements(),n.modules.forEach(function(t){t.onUpdate()})},this.removeModules=function(){n.modules.forEach(function(t){t.onDestroy()}),n.modules=[]},this.handleClick=function(t){if(t.target&&t.target.tagName&&"IMG"===t.target.tagName.toUpperCase()){if(n.img===t.target)return;n.img&&n.hide(),n.show(t.target)}else n.img&&n.hide()},this.show=function(t){n.img=t,n.showOverlay(),n.initializeModules()},this.showOverlay=function(){n.overlay&&n.hideOverlay(),n.quill.setSelection(null),n.setUserSelect("none"),document.addEventListener("keyup",n.checkImage,!0),n.quill.root.addEventListener("input",n.checkImage,!0),n.overlay=document.createElement("div"),Object.assign(n.overlay.style,n.options.overlayStyles),n.quill.root.parentNode.appendChild(n.overlay),n.repositionElements()},this.hideOverlay=function(){n.overlay&&(n.quill.root.parentNode.removeChild(n.overlay),n.overlay=void 0,document.removeEventListener("keyup",n.checkImage),n.quill.root.removeEventListener("input",n.checkImage),n.setUserSelect(""))},this.repositionElements=function(){if(n.overlay&&n.img){var t=n.quill.root.parentNode,e=n.img.getBoundingClientRect(),o=t.getBoundingClientRect();Object.assign(n.overlay.style,{left:e.left-o.left-1+t.scrollLeft+"px",top:e.top-o.top+t.scrollTop+"px",width:e.width+"px",height:e.height+"px"})}},this.hide=function(){n.hideOverlay(),n.removeModules(),n.img=void 0},this.setUserSelect=function(t){["userSelect","mozUserSelect","webkitUserSelect","msUserSelect"].forEach(function(e){n.quill.root.style[e]=t,document.documentElement.style[e]=t})},this.checkImage=function(t){n.img&&(46!=t.keyCode&&8!=t.keyCode||window.Quill.find(n.img).deleteAt(0),n.hide())},this.quill=e;var s=!1;r.modules&&(s=r.modules.slice()),this.options=i()({},r,a.a),s!==!1&&(this.options.modules=s),document.execCommand("enableObjectResizing",!1,"false"),this.quill.root.addEventListener("click",this.handleClick,!1),this.quill.root.parentNode.style.position=this.quill.root.parentNode.style.position||"relative",this.moduleClasses=this.options.modules,this.modules=[]};e.default=f,window.Quill&&window.Quill.register("modules/imageResize",f)},function(t,e,n){function o(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var o=t[e];this.set(o[0],o[1])}}var r=n(66),i=n(67),a=n(68),s=n(69),u=n(70);o.prototype.clear=r,o.prototype.delete=i,o.prototype.get=a,o.prototype.has=s,o.prototype.set=u,t.exports=o},function(t,e,n){function o(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var o=t[e];this.set(o[0],o[1])}}var r=n(80),i=n(81),a=n(82),s=n(83),u=n(84);o.prototype.clear=r,o.prototype.delete=i,o.prototype.get=a,o.prototype.has=s,o.prototype.set=u,t.exports=o},function(t,e,n){function o(t){var e=this.__data__=new r(t);this.size=e.size}var r=n(3),i=n(92),a=n(93),s=n(94),u=n(95),c=n(96);o.prototype.clear=i,o.prototype.delete=a,o.prototype.get=s,o.prototype.has=u,o.prototype.set=c,t.exports=o},function(t,e,n){var o=n(1),r=o.Uint8Array;t.exports=r},function(t,e,n){function o(t,e){var n=a(t),o=!n&&i(t),l=!n&&!o&&s(t),p=!n&&!o&&!l&&c(t),d=n||o||l||p,h=d?r(t.length,String):[],y=h.length;for(var v in t)!e&&!f.call(t,v)||d&&("length"==v||l&&("offset"==v||"parent"==v)||p&&("buffer"==v||"byteLength"==v||"byteOffset"==v)||u(v,y))||h.push(v);return h}var r=n(53),i=n(27),a=n(28),s=n(29),u=n(24),c=n(31),l=Object.prototype,f=l.hasOwnProperty;t.exports=o},function(t,e,n){function o(t,e,n){var o=t[e];s.call(t,e)&&i(o,n)&&(void 0!==n||e in t)||r(t,e,n)}var r=n(10),i=n(8),a=Object.prototype,s=a.hasOwnProperty;t.exports=o},function(t,e,n){var o=n(0),r=Object.create,i=function(){function t(){}return function(e){if(!o(e))return{};if(r)return r(e);t.prototype=e;var n=new t;return t.prototype=void 0,n}}();t.exports=i},function(t,e,n){var o=n(62),r=o();t.exports=r},function(t,e,n){function o(t){return i(t)&&r(t)==a}var r=n(5),i=n(2),a="[object Arguments]";t.exports=o},function(t,e,n){function o(t){return!(!a(t)||i(t))&&(r(t)?d:u).test(s(t))}var r=n(13),i=n(74),a=n(0),s=n(97),u=/^\[object .+?Constructor\]$/,c=Function.prototype,l=Object.prototype,f=c.toString,p=l.hasOwnProperty,d=RegExp("^"+f.call(p).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=o},function(t,e,n){function o(t){return a(t)&&i(t.length)&&!!s[r(t)]}var r=n(5),i=n(30),a=n(2),s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s["[object Arguments]"]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s["[object Function]"]=s["[object Map]"]=s["[object Number]"]=s["[object Object]"]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1,t.exports=o},function(t,e,n){function o(t){if(!r(t))return a(t);var e=i(t),n=[];for(var o in t)("constructor"!=o||!e&&u.call(t,o))&&n.push(o);return n}var r=n(0),i=n(25),a=n(85),s=Object.prototype,u=s.hasOwnProperty;t.exports=o},function(t,e,n){function o(t,e,n,o,g,x,m){var _=t[n],j=e[n],w=m.get(j);if(w)return void r(t,n,w);var O=x?x(_,j,n+"",t,e,m):void 0,S=void 0===O;if(S){var E=l(j),A=!E&&p(j),z=!E&&!A&&v(j);O=j,E||A||z?l(_)?O=_:f(_)?O=s(_):A?(S=!1,O=i(j,!0)):z?(S=!1,O=a(j,!0)):O=[]:y(j)||c(j)?(O=_,c(_)?O=b(_):(!h(_)||o&&d(_))&&(O=u(j))):S=!1}S&&(m.set(j,O),g(O,j,o,x,m),m.delete(j)),r(t,n,O)}var r=n(18),i=n(56),a=n(57),s=n(58),u=n(71),c=n(27),l=n(28),f=n(99),p=n(29),d=n(13),h=n(0),y=n(100),v=n(31),b=n(103);t.exports=o},function(t,e,n){var o=n(98),r=n(21),i=n(26),a=r?function(t,e){return r(t,"toString",{configurable:!0,enumerable:!1,value:o(e),writable:!0})}:i;t.exports=a},function(t,e){function n(t,e){for(var n=-1,o=Array(t);++n<t;)o[n]=e(n);return o}t.exports=n},function(t,e){function n(t){return function(e){return t(e)}}t.exports=n},function(t,e,n){function o(t){var e=new t.constructor(t.byteLength);return new r(e).set(new r(t)),e}var r=n(42);t.exports=o},function(t,e,n){(function(t){function o(t,e){if(e)return t.slice();var n=t.length,o=c?c(n):new t.constructor(n);return t.copy(o),o}var r=n(1),i="object"==typeof e&&e&&!e.nodeType&&e,a=i&&"object"==typeof t&&t&&!t.nodeType&&t,s=a&&a.exports===i,u=s?r.Buffer:void 0,c=u?u.allocUnsafe:void 0;t.exports=o}).call(e,n(14)(t))},function(t,e,n){function o(t,e){var n=e?r(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}var r=n(55);t.exports=o},function(t,e){function n(t,e){var n=-1,o=t.length;for(e||(e=Array(o));++n<o;)e[n]=t[n];return e}t.exports=n},function(t,e,n){function o(t,e,n,o){var a=!n;n||(n={});for(var s=-1,u=e.length;++s<u;){var c=e[s],l=o?o(n[c],t[c],c,n,t):void 0;void 0===l&&(l=t[c]),a?i(n,c,l):r(n,c,l)}return n}var r=n(44),i=n(10);t.exports=o},function(t,e,n){var o=n(1),r=o["__core-js_shared__"];t.exports=r},function(t,e,n){function o(t){return r(function(e,n){var o=-1,r=n.length,a=r>1?n[r-1]:void 0,s=r>2?n[2]:void 0;for(a=t.length>3&&"function"==typeof a?(r--,a):void 0,s&&i(n[0],n[1],s)&&(a=r<3?void 0:a,r=1),e=Object(e);++o<r;){var u=n[o];u&&t(e,u,o,a)}return e})}var r=n(20),i=n(72);t.exports=o},function(t,e){function n(t){return function(e,n,o){for(var r=-1,i=Object(e),a=o(e),s=a.length;s--;){var u=a[t?s:++r];if(n(i[u],u,i)===!1)break}return e}}t.exports=n},function(t,e,n){function o(t,e,n,a,s,u){return i(t)&&i(e)&&(u.set(e,t),r(t,e,void 0,o,u),u.delete(e)),t}var r=n(19),i=n(0);t.exports=o},function(t,e,n){function o(t){var e=a.call(t,u),n=t[u];try{t[u]=void 0}catch(t){}var o=s.call(t);return e?t[u]=n:delete t[u],o}var r=n(16),i=Object.prototype,a=i.hasOwnProperty,s=i.toString,u=r?r.toStringTag:void 0;t.exports=o},function(t,e){function n(t,e){return null==t?void 0:t[e]}t.exports=n},function(t,e,n){function o(){this.__data__=r?r(null):{},this.size=0}var r=n(7);t.exports=o},function(t,e){function n(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}t.exports=n},function(t,e,n){function o(t){var e=this.__data__;if(r){var n=e[t];return n===i?void 0:n}return s.call(e,t)?e[t]:void 0}var r=n(7),i="__lodash_hash_undefined__",a=Object.prototype,s=a.hasOwnProperty;t.exports=o},function(t,e,n){function o(t){var e=this.__data__;return r?void 0!==e[t]:a.call(e,t)}var r=n(7),i=Object.prototype,a=i.hasOwnProperty;t.exports=o},function(t,e,n){function o(t,e){var n=this.__data__;return this.size+=this.has(t)?0:1,n[t]=r&&void 0===e?i:e,this}var r=n(7),i="__lodash_hash_undefined__";t.exports=o},function(t,e,n){function o(t){return"function"!=typeof t.constructor||a(t)?{}:r(i(t))}var r=n(45),i=n(23),a=n(25);t.exports=o},function(t,e,n){function o(t,e,n){if(!s(n))return!1;var o=typeof e;return!!("number"==o?i(n)&&a(e,n.length):"string"==o&&e in n)&&r(n[e],t)}var r=n(8),i=n(12),a=n(24),s=n(0);t.exports=o},function(t,e){function n(t){var e=typeof t;return"string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t}t.exports=n},function(t,e,n){function o(t){return!!i&&i in t}var r=n(60),i=function(){var t=/[^.]+$/.exec(r&&r.keys&&r.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}();t.exports=o},function(t,e){function n(){this.__data__=[],this.size=0}t.exports=n},function(t,e,n){function o(t){var e=this.__data__,n=r(e,t);return!(n<0)&&(n==e.length-1?e.pop():a.call(e,n,1),--this.size,!0)}var r=n(4),i=Array.prototype,a=i.splice;t.exports=o},function(t,e,n){function o(t){var e=this.__data__,n=r(e,t);return n<0?void 0:e[n][1]}var r=n(4);t.exports=o},function(t,e,n){function o(t){return r(this.__data__,t)>-1}var r=n(4);t.exports=o},function(t,e,n){function o(t,e){var n=this.__data__,o=r(n,t);return o<0?(++this.size,n.push([t,e])):n[o][1]=e,this}var r=n(4);t.exports=o},function(t,e,n){function o(){this.size=0,this.__data__={hash:new r,map:new(a||i),string:new r}}var r=n(39),i=n(3),a=n(15);t.exports=o},function(t,e,n){function o(t){var e=r(this,t).delete(t);return this.size-=e?1:0,e}var r=n(6);t.exports=o},function(t,e,n){function o(t){return r(this,t).get(t)}var r=n(6);t.exports=o},function(t,e,n){function o(t){return r(this,t).has(t)}var r=n(6);t.exports=o},function(t,e,n){function o(t,e){var n=r(this,t),o=n.size;return n.set(t,e),this.size+=n.size==o?0:1,this}var r=n(6);t.exports=o},function(t,e){function n(t){var e=[];if(null!=t)for(var n in Object(t))e.push(n);return e}t.exports=n},function(t,e,n){(function(t){var o=n(22),r="object"==typeof e&&e&&!e.nodeType&&e,i=r&&"object"==typeof t&&t&&!t.nodeType&&t,a=i&&i.exports===r,s=a&&o.process,u=function(){try{return s&&s.binding&&s.binding("util")}catch(t){}}();t.exports=u}).call(e,n(14)(t))},function(t,e){function n(t){return r.call(t)}var o=Object.prototype,r=o.toString;t.exports=n},function(t,e){function n(t,e){return function(n){return t(e(n))}}t.exports=n},function(t,e,n){function o(t,e,n){return e=i(void 0===e?t.length-1:e,0),function(){for(var o=arguments,a=-1,s=i(o.length-e,0),u=Array(s);++a<s;)u[a]=o[e+a];a=-1;for(var c=Array(e+1);++a<e;)c[a]=o[a];return c[e]=n(u),r(t,this,c)}}var r=n(17),i=Math.max;t.exports=o},function(t,e,n){var o=n(52),r=n(91),i=r(o);t.exports=i},function(t,e){function n(t){var e=0,n=0;return function(){var a=i(),s=r-(a-n);if(n=a,s>0){if(++e>=o)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}var o=800,r=16,i=Date.now;t.exports=n},function(t,e,n){function o(){this.__data__=new r,this.size=0}var r=n(3);t.exports=o},function(t,e){function n(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n}t.exports=n},function(t,e){function n(t){return this.__data__.get(t)}t.exports=n},function(t,e){function n(t){return this.__data__.has(t)}t.exports=n},function(t,e,n){function o(t,e){var n=this.__data__;if(n instanceof r){var o=n.__data__;if(!i||o.length<s-1)return o.push([t,e]),this.size=++n.size,this;n=this.__data__=new a(o)}return n.set(t,e),this.size=n.size,this}var r=n(3),i=n(15),a=n(40),s=200;t.exports=o},function(t,e){function n(t){if(null!=t){try{return r.call(t)}catch(t){}try{return t+""}catch(t){}}return""}var o=Function.prototype,r=o.toString;t.exports=n},function(t,e){function n(t){return function(){return t}}t.exports=n},function(t,e,n){function o(t){return i(t)&&r(t)}var r=n(12),i=n(2);t.exports=o},function(t,e,n){function o(t){if(!a(t)||r(t)!=s)return!1;var e=i(t);if(null===e)return!0;var n=f.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&l.call(n)==p}var r=n(5),i=n(23),a=n(2),s="[object Object]",u=Function.prototype,c=Object.prototype,l=u.toString,f=c.hasOwnProperty,p=l.call(Object);t.exports=o},function(t,e,n){var o=n(19),r=n(61),i=r(function(t,e,n,r){o(t,e,n,r)});t.exports=i},function(t,e){function n(){return!1}t.exports=n},function(t,e,n){function o(t){return r(t,i(t))}var r=n(59),i=n(32);t.exports=o},function(t,e){t.exports='<svg viewbox="0 0 18 18">\n <line class="ql-stroke" x1="15" x2="3" y1="9" y2="9"></line>\n <line class="ql-stroke" x1="14" x2="4" y1="14" y2="14"></line>\n <line class="ql-stroke" x1="12" x2="6" y1="4" y2="4"></line>\n</svg>'},function(t,e){t.exports='<svg viewbox="0 0 18 18">\n <line class="ql-stroke" x1="3" x2="15" y1="9" y2="9"></line>\n <line class="ql-stroke" x1="3" x2="13" y1="14" y2="14"></line>\n <line class="ql-stroke" x1="3" x2="9" y1="4" y2="4"></line>\n</svg>'},function(t,e){t.exports='<svg viewbox="0 0 18 18">\n <line class="ql-stroke" x1="15" x2="3" y1="9" y2="9"></line>\n <line class="ql-stroke" x1="15" x2="5" y1="14" y2="14"></line>\n <line class="ql-stroke" x1="15" x2="9" y1="4" y2="4"></line>\n</svg>'},function(t,e){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n}])});
@@ -0,0 +1,8 @@
1
+ /* eslint-disable */
2
+
3
+ /* Origin: https://github.com/Platoniq/quill-image-upload */
4
+ (function () {
5
+ var exports = {};
6
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function e(e,t){for(var a=0;a<t.length;a++){var i=t[a];i.enumerable=i.enumerable||false;i.configurable=true;if("value"in i)i.writable=true;Object.defineProperty(e,i.key,i)}}return function(t,a,i){if(a)e(t.prototype,a);if(i)e(t,i);return t}}();function _classCallCheck(e,t){if(!(e instanceof t)){throw new TypeError("Cannot call a class as a function")}}var ImageUpload=exports.ImageUpload=function(){function e(t){var a=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,e);this.quill=t;this.options=a;this.quill.getModule("toolbar").addHandler("image",this.selectLocalImage.bind(this));this.handleDrop=this.handleDrop.bind(this);this.handlePaste=this.handlePaste.bind(this);this.quill.root.addEventListener("drop",this.handleDrop,false);this.quill.root.addEventListener("paste",this.handlePaste,false)}_createClass(e,[{key:"selectLocalImage",value:function e(){var t=this;var a=document.createElement("input");a.setAttribute("type","file");a.click();a.onchange=function(){var e=a.files[0];if(/^image\//.test(e.type)){var i=t.options.checkBeforeSend||t.checkBeforeSend.bind(t);i(e,t.sendToServer.bind(t))}else{console.warn("You could only upload images.")}}}},{key:"checkBeforeSend",value:function e(t,a){a(t)}},{key:"sendToServer",value:function e(t){var a=this;if(this.options.customUploader){this.options.customUploader(t,function(e){a.insert(e)})}else{var i=this.options.url,n=this.options.method||"POST",s=this.options.name||"image",o=this.options.headers||{},r=this.options.callbackOK||this.uploadImageCallbackOK.bind(this),l=this.options.callbackKO||this.uploadImageCallbackKO.bind(this);if(i){var d=new FormData;d.append(s,t);if(this.options.csrf){d.append(this.options.csrf.token,this.options.csrf.hash)}var c=new XMLHttpRequest;c.open(n,i,true);for(var u in o){c.setRequestHeader(u,o[u])}c.onload=function(){if(c.status===200){r(JSON.parse(c.responseText),a.insert.bind(a))}else{l({code:c.status,type:c.statusText,body:c.responseText})}};if(this.options.withCredentials){c.withCredentials=true}c.send(d)}else{var f=new FileReader;f.onload=function(e){r(e.target.result,a.insert.bind(a))};f.readAsDataURL(t)}}}},{key:"handleDrop",value:function e(t){t.preventDefault();if(t.dataTransfer&&t.dataTransfer.files&&t.dataTransfer.files.length){if(document.caretRangeFromPoint){var a=document.getSelection();var i=document.caretRangeFromPoint(t.clientX,t.clientY);if(a&&i){a.setBaseAndExtent(i.startContainer,i.startOffset,i.startContainer,i.startOffset)}}this.readFiles(t.dataTransfer.files,this.sendToServer.bind(this))}}},{key:"handlePaste",value:function e(t){var a=this;var i=Quill.import("delta");if(t.clipboardData&&t.clipboardData.items&&t.clipboardData.items.length){this.readFiles(t.clipboardData.items,function(e){var t=a.quill.getSelection();if(t){a.quill.updateContents((new i).retain(t.index-1).delete(1))}setTimeout(function(){return a.sendToServer(e.getAsFile())},0)})}}},{key:"readFiles",value:function e(t,a){var i=this;[].forEach.call(t,function(e){if(!/^image\//.test(e.type)){return}var t=new FileReader;t.onload=function(t){var n=i.options.checkBeforeSend||i.checkBeforeSend.bind(i);n(e,a)};var n=e.getAsFile?e.getAsFile():e;if(n instanceof Blob){t.readAsDataURL(n)}})}},{key:"insert",value:function e(t){var a=(this.quill.getSelection()||{}).index||this.quill.getLength();this.quill.insertEmbed(a,"image",t,"user")}},{key:"uploadImageCallbackOK",value:function e(t,a){a(t)}},{key:"uploadImageCallbackKO",value:function e(t){alert(t)}}]);return e}();
7
+ window.Quill.register('modules/imageUpload', exports.ImageUpload);
8
+ })();