decidim-elections 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_elections_manifest.js +2 -0
  3. data/app/assets/javascripts/decidim/elections/vote.js.es6 +170 -0
  4. data/app/assets/stylesheets/decidim/elections/elections.scss +10 -0
  5. data/app/assets/stylesheets/decidim/elections/focus/_evote.scss +279 -0
  6. data/app/assets/stylesheets/decidim/elections/focus/_focus.scss +128 -0
  7. data/app/cells/decidim/elections/election_cell.rb +22 -0
  8. data/app/cells/decidim/elections/election_m/data.erb +19 -0
  9. data/app/cells/decidim/elections/election_m/footer.erb +5 -0
  10. data/app/cells/decidim/elections/election_m_cell.rb +103 -0
  11. data/app/cells/decidim/elections/voting_step_navigation/show.erb +29 -0
  12. data/app/cells/decidim/elections/voting_step_navigation_cell.rb +42 -0
  13. data/app/commands/decidim/elections/admin/create_election.rb +14 -3
  14. data/app/commands/decidim/elections/admin/create_question.rb +2 -1
  15. data/app/commands/decidim/elections/admin/destroy_election.rb +4 -0
  16. data/app/commands/decidim/elections/admin/import_proposals_to_elections.rb +87 -0
  17. data/app/commands/decidim/elections/admin/publish_election.rb +54 -0
  18. data/app/commands/decidim/elections/admin/unpublish_election.rb +43 -0
  19. data/app/commands/decidim/elections/admin/update_election.rb +15 -3
  20. data/app/commands/decidim/elections/admin/update_question.rb +2 -1
  21. data/app/controllers/concerns/decidim/elections/orderable.rb +36 -0
  22. data/app/controllers/decidim/elections/admin/answers_controller.rb +9 -1
  23. data/app/controllers/decidim/elections/admin/elections_controller.rb +26 -0
  24. data/app/controllers/decidim/elections/admin/proposals_imports_controller.rb +53 -0
  25. data/app/controllers/decidim/elections/elections_controller.rb +68 -0
  26. data/app/controllers/decidim/elections/votes_controller.rb +50 -0
  27. data/app/events/decidim/elections/election_published_event.rb +8 -0
  28. data/app/forms/decidim/elections/admin/answer_import_proposals_form.rb +41 -0
  29. data/app/forms/decidim/elections/admin/election_form.rb +15 -2
  30. data/app/forms/decidim/elections/admin/question_form.rb +1 -0
  31. data/app/helpers/decidim/elections/application_helper.rb +12 -0
  32. data/app/helpers/decidim/elections/election_cells_helper.rb +12 -0
  33. data/app/helpers/decidim/elections/votes_helper.rb +21 -0
  34. data/app/models/decidim/elections/answer.rb +5 -1
  35. data/app/models/decidim/elections/election.rb +69 -0
  36. data/app/models/decidim/elections/question.rb +9 -2
  37. data/app/permissions/decidim/elections/admin/permissions.rb +13 -3
  38. data/app/permissions/decidim/elections/permissions.rb +35 -0
  39. data/app/presenters/decidim/elections/admin_log/election_presenter.rb +41 -0
  40. data/app/presenters/decidim/elections/election_presenter.rb +28 -0
  41. data/app/queries/decidim/elections/filtered_elections.rb +37 -0
  42. data/app/services/decidim/elections/election_search.rb +35 -0
  43. data/app/types/decidim/elections/election_question_type.rb +2 -2
  44. data/app/types/decidim/elections/election_type.rb +2 -1
  45. data/app/types/decidim/elections/elections_type.rb +1 -1
  46. data/app/views/decidim/elections/admin/answers/index.html.erb +2 -1
  47. data/app/views/decidim/elections/admin/elections/_form.html.erb +2 -4
  48. data/app/views/decidim/elections/admin/elections/index.html.erb +23 -1
  49. data/app/views/decidim/elections/admin/proposals_imports/new.html.erb +24 -0
  50. data/app/views/decidim/elections/admin/questions/_form.html.erb +4 -0
  51. data/app/views/decidim/elections/admin/questions/index.html.erb +3 -1
  52. data/app/views/decidim/elections/elections/_count.html.erb +1 -0
  53. data/app/views/decidim/elections/elections/_election.html.erb +1 -0
  54. data/app/views/decidim/elections/elections/_elections.html.erb +24 -0
  55. data/app/views/decidim/elections/elections/_filters.html.erb +24 -0
  56. data/app/views/decidim/elections/elections/_filters_small_view.html.erb +18 -0
  57. data/app/views/decidim/elections/elections/index.html.erb +24 -0
  58. data/app/views/decidim/elections/elections/index.js.erb +10 -0
  59. data/app/views/decidim/elections/elections/show.html.erb +62 -0
  60. data/app/views/decidim/elections/votes/_election_votes_confirm.html.erb +53 -0
  61. data/app/views/decidim/elections/votes/_election_votes_confirm_footer.html.erb +24 -0
  62. data/app/views/decidim/elections/votes/_election_votes_confirmed.html.erb +26 -0
  63. data/app/views/decidim/elections/votes/_election_votes_encrypting.html.erb +20 -0
  64. data/app/views/decidim/elections/votes/_election_votes_header.html.erb +8 -0
  65. data/app/views/decidim/elections/votes/_election_votes_modal.html.erb +46 -0
  66. data/app/views/decidim/elections/votes/_election_votes_question.html.erb +49 -0
  67. data/app/views/decidim/elections/votes/_election_votes_steps_header.html.erb +12 -0
  68. data/app/views/decidim/elections/votes/new.html.erb +44 -0
  69. data/app/views/layouts/decidim/_election_votes_header.html.erb +13 -0
  70. data/app/views/layouts/decidim/election_votes.html.erb +24 -0
  71. data/config/locales/am-ET.yml +1 -0
  72. data/config/locales/bg.yml +7 -0
  73. data/config/locales/ca.yml +136 -6
  74. data/config/locales/cs.yml +133 -1
  75. data/config/locales/da.yml +1 -0
  76. data/config/locales/de.yml +93 -1
  77. data/config/locales/el.yml +11 -1
  78. data/config/locales/en.yml +131 -1
  79. data/config/locales/eo.yml +1 -0
  80. data/config/locales/es-MX.yml +131 -1
  81. data/config/locales/es-PY.yml +131 -1
  82. data/config/locales/es.yml +134 -4
  83. data/config/locales/et.yml +1 -0
  84. data/config/locales/fi-plain.yml +131 -1
  85. data/config/locales/fi.yml +131 -1
  86. data/config/locales/fr-CA.yml +131 -1
  87. data/config/locales/fr.yml +131 -1
  88. data/config/locales/hr.yml +1 -0
  89. data/config/locales/hu.yml +18 -0
  90. data/config/locales/is.yml +1 -0
  91. data/config/locales/it.yml +88 -1
  92. data/config/locales/ja-JP.yml +95 -8
  93. data/config/locales/ja.yml +254 -0
  94. data/config/locales/ko-KR.yml +1 -0
  95. data/config/locales/ko.yml +1 -0
  96. data/config/locales/lt.yml +1 -0
  97. data/config/locales/{lv-LV.yml → lv.yml} +11 -1
  98. data/config/locales/mt.yml +1 -0
  99. data/config/locales/nl.yml +88 -1
  100. data/config/locales/no.yml +64 -0
  101. data/config/locales/om-ET.yml +1 -0
  102. data/config/locales/pl.yml +124 -1
  103. data/config/locales/pt.yml +84 -1
  104. data/config/locales/ro-RO.yml +85 -1
  105. data/config/locales/so-SO.yml +1 -0
  106. data/config/locales/sv.yml +121 -1
  107. data/config/locales/ti-ER.yml +1 -0
  108. data/config/locales/vi-VN.yml +1 -0
  109. data/config/locales/vi.yml +1 -0
  110. data/config/locales/zh-CN.yml +254 -0
  111. data/config/locales/zh-TW.yml +1 -0
  112. data/db/migrate/20200601141412_add_published_at_to_elections.rb +7 -0
  113. data/db/migrate/20200807125040_remove_subtitle_from_decidim_elections.rb +7 -0
  114. data/db/migrate/20200910103648_add_min_selections_to_decidim_elections_questions.rb +7 -0
  115. data/lib/decidim/elections.rb +5 -0
  116. data/lib/decidim/elections/admin_engine.rb +7 -0
  117. data/lib/decidim/elections/bulletin_board_client.rb +35 -0
  118. data/lib/decidim/elections/component.rb +17 -12
  119. data/lib/decidim/elections/engine.rb +8 -1
  120. data/lib/decidim/elections/test/factories.rb +59 -6
  121. data/lib/decidim/elections/version.rb +1 -1
  122. data/lib/tasks/decidim_elections.rake +16 -0
  123. metadata +79 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8ce79876fbac611d30571cad4cf2e451e774d757aef8db6ac626e1150cf7d1b
4
- data.tar.gz: 4b323700709a0c42ca51269fefcb23bcfed7325075af7ea42ee7f7889ab19bc1
3
+ metadata.gz: 8aa245d79cc6f29e504c2da89b7b84fb2653013e777e8e5213b94e75a196deb8
4
+ data.tar.gz: 52ad70fec46cf00e6559908d2ad27249a8009d55aaf5248a24146702db986a71
5
5
  SHA512:
6
- metadata.gz: 0f252f309ef75a273938ac811d9b1ec6493b272ee3b9916debadf7d41e0f5b0c03ce2250128b46f615046a24c868bb3286316b930390261b19970f470fe8e68c
7
- data.tar.gz: 54db270fd7447ab0d6f0e541b84766d23fa89beb05c37eebfb403a4b480c0c55b66b905a2a5815187ce352df5c959850bb24b96a1b3edc9f3331cc90d51a1789
6
+ metadata.gz: 178582a83f6078448a5c64a6f4d2994c326d7f18d8ae0083e49fa8145ac0627d5c54d57a82f30e8027e3c8ea5bd9fc8f3ed4e5373d4248565997bf131ff1bfca
7
+ data.tar.gz: f7910f739ef98c6dce4ce117ea36830fc02f40dcbedb365ef3bb6927d02d05741b40697bd31fd158dcf2473d74a394bc2cc27457937988d151b7eca0a1bd3e00
@@ -0,0 +1,2 @@
1
+ //= link decidim/elections/vote.js
2
+ //= link_tree ../images/decidim
@@ -0,0 +1,170 @@
1
+ /* eslint-disable require-jsdoc, prefer-template, func-style, id-length, no-use-before-define, init-declarations, no-invalid-this */
2
+ /* eslint no-unused-vars: ["error", { "args": "none" }] */
3
+
4
+ $(() => {
5
+ const $vote = $(".focus");
6
+ const $continueButton = $vote.find("a.focus__next");
7
+ const $confirmButton = $vote.find("a.focus__next.confirm");
8
+ const $continueSpan = $vote.find("span.disabled-continue");
9
+ let $answerCounter = 0;
10
+ let $currentStep,
11
+ $currentStepMaxSelection = "";
12
+ let $formData = $vote.find(".answer_input");
13
+
14
+ function initStep() {
15
+ setCurrentStep();
16
+ toggleContinueButton();
17
+ $($confirmButton).addClass("show").removeClass("hide");
18
+ $(".evote__counter-min").text($answerCounter);
19
+ answerCounter();
20
+ disableCheckbox();
21
+ }
22
+
23
+ initStep()
24
+
25
+ function setCurrentStep() {
26
+ $currentStep = $vote.find(".focus__step:visible")
27
+ setSelections();
28
+ onSelectionChange();
29
+ }
30
+
31
+ function setSelections() {
32
+ $currentStepMaxSelection = $currentStep.find(".evote__options").data("max-selection")
33
+ }
34
+
35
+ function onSelectionChange() {
36
+ let $voteOptions = $currentStep.find(".evote__options");
37
+ $voteOptions.on("change", (event) => {
38
+ toggleContinueButton();
39
+ toggleConfirmAnswers();
40
+ answerCounter();
41
+ });
42
+ }
43
+
44
+ // disable checkboxes if NOTA option is selected
45
+ function disableCheckbox() {
46
+ $("[data-disabled-by]").on("click", function(e) {
47
+ if ($(this).attr("aria-disabled") || $(this).hasClass("is-disabled")) {
48
+ e.preventDefault();
49
+ }
50
+ });
51
+
52
+ $("[data-disable-check]").on("change", function() {
53
+ let checkId = $(this).attr("id");
54
+ let checkStatus = this.checked;
55
+
56
+ $($currentStep).find("[data-disabled-by='#" + checkId + "']").each(function() {
57
+ if (checkStatus) {
58
+ $(this).addClass("is-disabled");
59
+ $(this).find("input[type=checkbox]").prop("checked", false);
60
+ } else {
61
+ $(this).removeClass("is-disabled");
62
+ }
63
+
64
+ $(this).find("input[type=checkbox]").attr("aria-disabled", checkStatus);
65
+ });
66
+ });
67
+ }
68
+
69
+ function toggleContinueButton() {
70
+ if (checkAnswers() === true) {
71
+ // next step enabled
72
+ $($continueButton).addClass("show").removeClass("hide")
73
+ $($continueSpan).addClass("hide").removeClass("show")
74
+ } else {
75
+ // next step disabled
76
+ $($continueButton).addClass("hide").removeClass("show")
77
+ $($continueSpan).addClass("show").removeClass("hide")
78
+ }
79
+ }
80
+
81
+ // check if answers are correctly checked
82
+ function checkAnswers() {
83
+ let currentAnswersChecked = $("#" + $currentStep.attr("id") + " .answer_input:checked").length
84
+ let notaAnswerChecked = $("#" + $currentStep.attr("id") + " .nota_input:checked").length
85
+
86
+ if ((currentAnswersChecked >= 1 || notaAnswerChecked > 0) && (currentAnswersChecked <= $currentStepMaxSelection)) {
87
+ return true;
88
+ }
89
+
90
+ return false;
91
+ }
92
+
93
+ // receive confirmed answers
94
+ function toggleConfirmAnswers() {
95
+ $(".answer_input:checked").each(function() {
96
+ let confirmedAnswer = $(".evote__confirm").find("#" + this.value);
97
+ $(confirmedAnswer).removeClass("hide")
98
+ })
99
+
100
+ $(".answer_input").not(":checked").each(function() {
101
+ let confirmedAnswer = $(".evote__confirm").find("#" + this.value);
102
+ $(confirmedAnswer).addClass("hide")
103
+ })
104
+
105
+ $(".nota_input:checked").each(function() {
106
+ let confirmedAnswer = $(".evote__confirm").find("." + this.value);
107
+ $(confirmedAnswer).removeClass("hide")
108
+ })
109
+
110
+ $(".nota_input").not(":checked").each(function() {
111
+ let confirmedAnswer = $(".evote__confirm").find("." + this.value);
112
+ $(confirmedAnswer).addClass("hide")
113
+ })
114
+ }
115
+
116
+ function answerCounter() {
117
+ let checked = $("#" + $currentStep.attr("id") + " .answer_input:checked").length
118
+ $(".evote__counter-min").text(checked);
119
+ }
120
+
121
+ // get form Data
122
+ function getFormData(formData) {
123
+ let unindexedArray = formData.serializeArray();
124
+ let indexedArray = {};
125
+ $.map(unindexedArray, function(n, i) {
126
+ indexedArray[n.name] = n.value;
127
+ });
128
+
129
+ return indexedArray;
130
+ }
131
+
132
+ // confirm vote
133
+ $(".button.confirm").on("click", (event) => {
134
+ const boothMode = $(event.currentTarget).data("booth-mode");
135
+ const formData = getFormData($formData);
136
+ castVote(boothMode, formData)
137
+ });
138
+
139
+ // cast vote
140
+ function castVote(boothMode, formData) {
141
+ // log form Data
142
+ console.log(`Your vote got encrypted successfully. The booth mode is ${boothMode}. Your vote content is:`, formData) // eslint-disable-line no-console
143
+
144
+ window.setTimeout(function() {
145
+ $($vote).find("#encrypting").addClass("hide")
146
+ $($vote).find("#confirmed_page").removeClass("hide")
147
+ window.confirmed = true;
148
+ }, 3000)
149
+ }
150
+
151
+ // exit message before confirming
152
+ const $form = $(".evote__options");
153
+ if ($form.length > 0) {
154
+
155
+ window.onbeforeunload = () => {
156
+ const voteCast = window.confirmed;
157
+
158
+ if (voteCast) {
159
+ return null;
160
+ }
161
+
162
+ return "";
163
+ }
164
+ }
165
+
166
+ $(document).on("on.zf.toggler", (event) => {
167
+ // continue and back btn
168
+ initStep()
169
+ });
170
+ });
@@ -0,0 +1,10 @@
1
+ @import "focus/*";
2
+
3
+ li.card-data__item{
4
+ flex-direction: inherit;
5
+ }
6
+
7
+ .card__icondata ul li:not(:first-child) strong,
8
+ .card__block ul li:not(:first-child) strong{
9
+ font-size: 100%;
10
+ }
@@ -0,0 +1,279 @@
1
+ .evote{
2
+ $checkfocus: 1px dotted rgba(black, .5);
3
+ $checkfocus-offset: .1em;
4
+
5
+ padding: 1rem;
6
+ margin-top: 1rem;
7
+
8
+ @include breakpoint(medium){
9
+ padding: 2rem;
10
+ margin-top: 2rem;
11
+ }
12
+
13
+ .row{
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: center;
17
+ text-align: center;
18
+ }
19
+
20
+ &__content{
21
+ margin: 1rem auto;
22
+
23
+ @include breakpoint(medium){
24
+ margin: 2rem auto;
25
+ }
26
+ }
27
+
28
+ &__options{
29
+ text-align: left;
30
+ margin: 1rem auto;
31
+ flex-grow: 1;
32
+
33
+ @include breakpoint(medium){
34
+ margin: 2rem auto;
35
+ }
36
+
37
+ &--boolean{
38
+ @include breakpoint(medium){
39
+ display: flex;
40
+ width: 100%;
41
+ justify-content: center;
42
+ }
43
+
44
+ > *{
45
+ flex-basis: 200px;
46
+ margin-left: 1rem;
47
+ margin-right: 1rem;
48
+ }
49
+ }
50
+ }
51
+
52
+ &__card{
53
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06);
54
+ padding: 1rem 2rem;
55
+ border-radius: .5rem;
56
+ background-color: $white;
57
+ margin-bottom: 1rem;
58
+
59
+ &.is-disabled{
60
+ background-color: $medium-gray;
61
+ cursor: not-allowed;
62
+
63
+ > *{
64
+ opacity: .5;
65
+ }
66
+ }
67
+ }
68
+
69
+ &__check{
70
+ cursor: pointer;
71
+ display: flex;
72
+ align-items: center;
73
+
74
+ @include breakpoint(medium){
75
+ font-size: 1.2rem;
76
+ }
77
+
78
+ input[type="checkbox"],
79
+ input[type="radio"]{
80
+ position: absolute;
81
+ width: 1px;
82
+ height: 1px;
83
+ padding: 0;
84
+ margin: -1px;
85
+ overflow: hidden;
86
+ clip: rect(0, 0, 0, 0);
87
+ border: 0;
88
+ }
89
+
90
+ [aria-disabled="true"]{
91
+ pointer-events: none;
92
+ }
93
+ }
94
+
95
+ &__check-label{
96
+ position: relative;
97
+ padding-left: 1em;
98
+ line-height: 1.4;
99
+
100
+ input[type="radio"] + &::before{
101
+ content: "";
102
+ width: 1em;
103
+ height: 1em;
104
+ border-radius: 50%;
105
+ border: 1px solid;
106
+ position: absolute;
107
+ left: -.7em;
108
+ top: .2em;
109
+ color: $secondary;
110
+ }
111
+
112
+ input[type="radio"]:focus + &::before{
113
+ outline: $checkfocus;
114
+ outline-offset: $checkfocus-offset;
115
+ }
116
+
117
+ input[type="radio"]:checked + &::after{
118
+ content: "";
119
+ width: .7em;
120
+ height: .7em;
121
+ border-radius: 50%;
122
+ background-color: $secondary;
123
+ position: absolute;
124
+ left: -.55em;
125
+ top: .35em;
126
+ }
127
+
128
+ input[type="checkbox"] + &::before{
129
+ content: "";
130
+ width: 1em;
131
+ height: 1em;
132
+ border: 1px solid;
133
+ position: absolute;
134
+ left: -.7em;
135
+ top: .2em;
136
+ color: $secondary;
137
+ border-radius: 3px;
138
+ }
139
+
140
+ input[type="checkbox"]:focus + &::before{
141
+ outline: $checkfocus;
142
+ outline-offset: $checkfocus-offset;
143
+ }
144
+
145
+ input[type="checkbox"]:checked + &::before{
146
+ background-color: $secondary;
147
+ }
148
+
149
+ input[type="checkbox"]:checked + &::after{
150
+ content: "";
151
+ width: .3em;
152
+ height: .6em;
153
+ position: absolute;
154
+ left: -.5em;
155
+ top: .15em;
156
+ border-width: 0 2px 2px 0;
157
+ border-style: solid;
158
+ border-color: $white;
159
+ transform-origin: bottom left;
160
+ transform: rotate(45deg);
161
+ }
162
+ }
163
+
164
+ &__check-extra{
165
+ display: block;
166
+ font-size: 60%;
167
+ text-transform: uppercase;
168
+ letter-spacing: .01em;
169
+ font-weight: 600;
170
+
171
+ button{
172
+ font-size: inherit;
173
+ text-transform: inherit;
174
+ font-family: inherit;
175
+ }
176
+ }
177
+
178
+ &__counter{
179
+ position: sticky;
180
+ bottom: 2rem;
181
+ right: 0;
182
+ margin-left: auto;
183
+ text-align: right;
184
+ line-height: 1.2;
185
+ background-color: $medium-gray;
186
+ padding: .3rem 1rem;
187
+ border-radius: $global-radius;
188
+ }
189
+
190
+ &__counter-num{
191
+ font-size: 1.2em;
192
+ }
193
+
194
+ &__confirm{
195
+ margin-top: 2rem;
196
+ max-width: 40em;
197
+ text-align: left;
198
+ line-height: 1.2;
199
+
200
+ dt{
201
+ font-weight: 600;
202
+ }
203
+
204
+ dd:not(:last-child){
205
+ margin-bottom: 2rem;
206
+ }
207
+ }
208
+
209
+ &__confirm-label{
210
+ font-size: 80%;
211
+ text-transform: uppercase;
212
+ letter-spacing: .01em;
213
+ color: $primary;
214
+ }
215
+
216
+ &__edit-answer{
217
+ text-transform: none;
218
+ letter-spacing: normal;
219
+ }
220
+
221
+ &__encrypting{
222
+ width: 200px;
223
+ height: 40px;
224
+ display: flex;
225
+ margin: 2rem auto;
226
+ }
227
+
228
+ &__dot{
229
+ width: 10px;
230
+ height: 10px;
231
+ margin: 10px auto;
232
+ border-radius: 50px;
233
+ background: $primary;
234
+
235
+ &:nth-child(odd){
236
+ animation: dotTop 1s infinite ease-in-out;
237
+ }
238
+
239
+ &:nth-child(even){
240
+ animation: dotBottom 1s infinite ease-in-out;
241
+ }
242
+
243
+ @media (prefers-reduced-motion){
244
+ animation: none !important;
245
+ }
246
+
247
+ @keyframes dotTop{
248
+ 0%{
249
+ transform: translateY(-15px);
250
+ }
251
+
252
+ 50%{
253
+ transform: translateY(15px);
254
+ }
255
+
256
+ 100%{
257
+ transform: translateY(-15px);
258
+ }
259
+ }
260
+
261
+ @keyframes dotBottom{
262
+ 0%{
263
+ transform: translateY(15px);
264
+ }
265
+
266
+ 50%{
267
+ transform: translateY(-15px);
268
+ }
269
+
270
+ 100%{
271
+ transform: translateY(15px);
272
+ }
273
+ }
274
+ }
275
+
276
+ &__poll-id{
277
+ overflow-wrap: anywhere;
278
+ }
279
+ }