decidim-budgets 0.25.2 → 0.26.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/decidim/budgets/budget/_budget-vote-button.scss +22 -0
- data/app/cells/decidim/budgets/budget_information_modal/show.erb +3 -3
- data/app/cells/decidim/budgets/budget_list_item/show.erb +31 -15
- data/app/cells/decidim/budgets/budget_list_item_cell.rb +30 -1
- data/app/cells/decidim/budgets/budgets_header/show.erb +1 -1
- data/app/cells/decidim/budgets/budgets_list/card_list.erb +17 -6
- data/app/cells/decidim/budgets/budgets_list/show.erb +2 -3
- data/app/cells/decidim/budgets/budgets_list/voted.erb +6 -0
- data/app/cells/decidim/budgets/project_list_item/project_data.erb +1 -1
- data/app/cells/decidim/budgets/{project_list_item/project_data_vote_button.erb → project_vote_button/show.erb} +1 -0
- data/app/cells/decidim/budgets/project_vote_button_cell.rb +10 -0
- data/app/commands/decidim/budgets/add_line_item.rb +5 -1
- data/app/controllers/concerns/decidim/budgets/admin/filterable.rb +51 -0
- data/app/controllers/decidim/budgets/admin/projects_controller.rb +6 -1
- data/app/controllers/decidim/budgets/line_items_controller.rb +2 -2
- data/app/helpers/decidim/budgets/admin/filterable_helper.rb +10 -0
- data/app/models/decidim/budgets/project.rb +28 -1
- data/app/packs/entrypoints/decidim_budgets.js +1 -0
- data/app/packs/src/decidim/budgets/exit_handler.js +131 -0
- data/app/packs/src/decidim/budgets/projects.js +9 -39
- data/app/packs/stylesheets/decidim/budgets/budget/_budget-list.scss +35 -1
- data/app/views/decidim/budgets/admin/projects/index.html.erb +16 -5
- data/app/views/decidim/budgets/projects/_exit_modal.html.erb +22 -0
- data/app/views/decidim/budgets/projects/_filters_small_view.html.erb +3 -3
- data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +17 -38
- data/app/views/decidim/budgets/projects/index.html.erb +25 -22
- data/app/views/decidim/budgets/projects/show.html.erb +41 -38
- data/config/locales/ca.yml +3 -0
- data/config/locales/cs.yml +23 -0
- data/config/locales/de.yml +9 -0
- data/config/locales/en.yml +23 -0
- data/config/locales/es.yml +23 -0
- data/config/locales/eu.yml +3 -0
- data/config/locales/fi-plain.yml +23 -0
- data/config/locales/fi.yml +23 -0
- data/config/locales/fr-CA.yml +11 -0
- data/config/locales/fr.yml +13 -2
- data/config/locales/gl.yml +9 -0
- data/config/locales/it.yml +9 -0
- data/config/locales/ja.yml +28 -5
- data/config/locales/lb-LU.yml +294 -0
- data/config/locales/nl.yml +18 -0
- data/config/locales/pl.yml +2 -0
- data/config/locales/pt-BR.yml +1 -1
- data/config/locales/pt.yml +3 -0
- data/config/locales/ro-RO.yml +15 -0
- data/config/locales/sv.yml +3 -0
- data/config/locales/val-ES.yml +1 -0
- data/lib/decidim/budgets/version.rb +1 -1
- metadata +23 -17
- data/app/cells/decidim/budgets/budgets_list/highlighted.erb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5faa45ba2c53c8c620e02d864b28790d7a776a82aa4650fdf6e5bfa36353adb3
|
4
|
+
data.tar.gz: d4698f56fef1acacb46f2f37f0eea903c543814d063b6473e7ebfa5677113fac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a19091bcad973926f835062473591c953166beda0fce9f7529cc1902569c40aa0fb9526fa4f25d8810ca62a9e1d2fb9d93a3e32845f3e9f5f8cc2f0966e432e5
|
7
|
+
data.tar.gz: 9f10d173bdf303db02468bd2bf3fcb78d9f18a052d148e955d934d7bdb1df78150bd90136442d63eb7627e9cc03af1c584ddcbd417aba49188712ab07eb349c8
|
@@ -0,0 +1,22 @@
|
|
1
|
+
.budget-vote-button.expanded{
|
2
|
+
display: flex;
|
3
|
+
text-align: left;
|
4
|
+
justify-content: space-between;
|
5
|
+
align-items: center;
|
6
|
+
|
7
|
+
span{
|
8
|
+
font-size: 1rem;
|
9
|
+
}
|
10
|
+
|
11
|
+
&.added{
|
12
|
+
background-color: tint($success, 80%);
|
13
|
+
color: $body-font-color;
|
14
|
+
}
|
15
|
+
|
16
|
+
&:not(.added){
|
17
|
+
.budget-list__action{
|
18
|
+
border-color: white;
|
19
|
+
color: white;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
@@ -1,10 +1,10 @@
|
|
1
|
-
<button class="link" data-open="budget-modal-info" aria-controls="budget-modal-info" aria-haspopup="
|
1
|
+
<button class="link" data-open="budget-modal-info" aria-controls="budget-modal-info" aria-haspopup="dialog" tabindex="0">
|
2
2
|
<%= t(:more_information, scope: i18n_scope) %>
|
3
3
|
</button>
|
4
4
|
|
5
|
-
<div class="reveal" data-reveal id="budget-modal-info">
|
5
|
+
<div class="reveal" data-reveal id="budget-modal-info" aria-modal="true" aria-labelledby="budget-modal-info-label">
|
6
6
|
<div class="reveal__header">
|
7
|
-
<h3 class="reveal__title"><%= decidim_sanitize(component_name) %></h3>
|
7
|
+
<h3 id="budget-modal-info-label" class="reveal__title"><%= decidim_sanitize(component_name) %></h3>
|
8
8
|
<button class="close-button" data-close aria-label="<%= t(:close_modal, scope: i18n_scope) %>" type="button">
|
9
9
|
<span aria-hidden="true">×</span>
|
10
10
|
</button>
|
@@ -1,22 +1,38 @@
|
|
1
|
-
<div class="<%= card_class %>">
|
2
|
-
<div class="
|
1
|
+
<div class="<%= card_class %> budget-list__item budget-list__item-cell">
|
2
|
+
<div class="budget-list__text flex-horizontal">
|
3
3
|
<%= link_to budget_path(budget), class: link_class do %>
|
4
|
-
|
5
|
-
<strong>
|
6
|
-
<%= translated_attribute(title) %>
|
7
|
-
</strong>
|
8
|
-
<span class="button tiny success card--list__check card--list__check--disabled">
|
9
|
-
<%= icon "check", class: "icon--small", role: "img", aria_label: t("decidim.budgets.budget_list_item.voting_finished") %>
|
10
|
-
</span>
|
11
|
-
<% else %>
|
4
|
+
<h5 class="card--list__heading">
|
12
5
|
<%= translated_attribute(title) %>
|
6
|
+
</h5>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<h5>
|
10
|
+
<strong>
|
11
|
+
<%= budget_to_currency(total_budget) %>
|
12
|
+
</strong>
|
13
|
+
</h5>
|
14
|
+
|
15
|
+
<%= decidim_sanitize html_truncate(translated_attribute(description), length: 140) %>
|
16
|
+
</div>
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
<% if !voting_finished? %>
|
19
|
+
<div class="budget-list__icon mr-s">
|
20
|
+
<% if voted? %>
|
21
|
+
<span class="button tiny success card--list__check card--list__check--disabled card--list__check--inline">
|
22
|
+
<%= icon "check", class: "icon--small", role: "img", aria_label: t("decidim.budgets.budget_list_item.voting_finished") %>
|
23
|
+
</span>
|
24
|
+
<% elsif progress? %>
|
25
|
+
<span class="button tiny warning card--list__check card--list__check--disabled card--list__check--inline">
|
26
|
+
<%= icon "bookmark", class: "icon--small", role: "img", aria_label: t("decidim.budgets.budget_list_item.voting_started") %>
|
27
|
+
</span>
|
19
28
|
<% end %>
|
29
|
+
</div>
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
<div class="budget-list__data">
|
33
|
+
<%= link_to budget_path(budget), class: "button button--sc expanded #{button_class} mb-none" do %>
|
34
|
+
<span><%= button_text %></span>
|
35
|
+
<%= icon "chevron-right", class: "icon--small", role: "img" %>
|
20
36
|
<% end %>
|
21
37
|
</div>
|
22
38
|
</div>
|
@@ -4,9 +4,15 @@ module Decidim
|
|
4
4
|
module Budgets
|
5
5
|
# This cell renders the budget item list in the budgets list
|
6
6
|
class BudgetListItemCell < BaseCell
|
7
|
+
include Decidim::SanitizeHelper
|
8
|
+
include Decidim::ApplicationHelper
|
9
|
+
include ActiveSupport::NumberHelper
|
10
|
+
include Decidim::Budgets::ProjectsHelper
|
11
|
+
|
7
12
|
delegate :voting_finished?, to: :controller
|
13
|
+
delegate :highlighted, to: :current_workflow
|
8
14
|
|
9
|
-
property :title
|
15
|
+
property :title, :description, :total_budget
|
10
16
|
alias budget model
|
11
17
|
|
12
18
|
private
|
@@ -17,6 +23,7 @@ module Decidim
|
|
17
23
|
list << "card--list__data-added" if voted?
|
18
24
|
list << "card--list__data-progress" if progress?
|
19
25
|
end
|
26
|
+
list << "budget--highlighted" if highlighted?
|
20
27
|
end.join(" ")
|
21
28
|
end
|
22
29
|
|
@@ -32,9 +39,31 @@ module Decidim
|
|
32
39
|
current_user && status == :progress
|
33
40
|
end
|
34
41
|
|
42
|
+
def highlighted?
|
43
|
+
highlighted.include?(budget)
|
44
|
+
end
|
45
|
+
|
35
46
|
def status
|
36
47
|
@status ||= current_workflow.status(budget)
|
37
48
|
end
|
49
|
+
|
50
|
+
def button_class
|
51
|
+
"hollow" if voted? || !highlighted?
|
52
|
+
end
|
53
|
+
|
54
|
+
def button_text
|
55
|
+
key = if current_workflow.vote_allowed?(budget) && !voted?
|
56
|
+
progress? ? :progress : :vote
|
57
|
+
else
|
58
|
+
:show
|
59
|
+
end
|
60
|
+
|
61
|
+
t(key, scope: i18n_scope)
|
62
|
+
end
|
63
|
+
|
64
|
+
def i18n_scope
|
65
|
+
"decidim.budgets.budgets_list"
|
66
|
+
end
|
38
67
|
end
|
39
68
|
end
|
40
69
|
end
|
@@ -1,7 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
<%# show highlighted budgets first %>
|
2
|
+
<% if highlighted.any? %>
|
3
|
+
<div id="highlighted-budgets" class="card card--list budget-list">
|
4
|
+
<% highlighted.each do |budget| %>
|
5
|
+
<%= cell("decidim/budgets/budget_list_item", budget) %>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
8
|
+
<% end %>
|
4
9
|
|
5
|
-
|
6
|
-
|
7
|
-
|
10
|
+
<% non_highlighted = (budgets - highlighted - voted) %>
|
11
|
+
|
12
|
+
<% if non_highlighted.any? %>
|
13
|
+
<div id="budgets" class="card card--list budget-list">
|
14
|
+
<% non_highlighted.each do |budget| %>
|
15
|
+
<%= cell("decidim/budgets/budget_list_item", budget) %>
|
16
|
+
<% end %>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
@@ -1,18 +1,17 @@
|
|
1
1
|
<div class="row">
|
2
2
|
<div class="columns medium-7 mediumlarge-8">
|
3
|
-
<% if !voting_finished? && (
|
3
|
+
<% if !voting_finished? && (voted?) %>
|
4
4
|
<div class="section">
|
5
5
|
<h3 class="section-heading">
|
6
6
|
<%= t(:my_budgets, scope: i18n_scope) %>
|
7
7
|
</h3>
|
8
8
|
|
9
|
-
<%= render :highlighted %>
|
10
9
|
<%= render :voted %>
|
11
10
|
</div>
|
12
11
|
<% end %>
|
13
12
|
|
14
13
|
<div class="row">
|
15
|
-
<div class="columns mediumlarge-
|
14
|
+
<div class="columns mediumlarge-12">
|
16
15
|
<%= render :card_list %>
|
17
16
|
</div>
|
18
17
|
</div>
|
@@ -4,6 +4,12 @@
|
|
4
4
|
<%= t(:voted_on, scope: i18n_scope, links: budgets_link_list(voted)) %>
|
5
5
|
</p>
|
6
6
|
|
7
|
+
<div id="voted-budgets" class="card card--list budget-list">
|
8
|
+
<% voted.each do |budget| %>
|
9
|
+
<%= cell("decidim/budgets/budget_list_item", budget) %>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
12
|
+
|
7
13
|
<% if finished? %>
|
8
14
|
<p class="lead">
|
9
15
|
<%= t(:finished_message, scope: i18n_scope) %>
|
@@ -14,6 +14,6 @@
|
|
14
14
|
<%= cell("decidim/budgets/project_voted_hint", model, class: "display-block margin-top-1") if current_order_checked_out? && resource_added? %>
|
15
15
|
</span>
|
16
16
|
|
17
|
-
<%=
|
17
|
+
<%= cell("decidim/budgets/project_vote_button", model) if !current_order_checked_out? && voting_open? %>
|
18
18
|
<% end %>
|
19
19
|
</div>
|
@@ -23,7 +23,7 @@ module Decidim
|
|
23
23
|
# Returns nothing.
|
24
24
|
def call
|
25
25
|
transaction do
|
26
|
-
return broadcast(:invalid) if voting_not_enabled? || order.checked_out?
|
26
|
+
return broadcast(:invalid) if voting_not_enabled? || order.checked_out? || exceeds_budget?
|
27
27
|
|
28
28
|
add_line_item
|
29
29
|
broadcast(:ok, order)
|
@@ -44,6 +44,10 @@ module Decidim
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
def exceeds_budget?
|
48
|
+
order.allocation_for(project) + order.total > order.available_allocation
|
49
|
+
end
|
50
|
+
|
47
51
|
def voting_not_enabled?
|
48
52
|
project.component.current_settings.votes != "enabled"
|
49
53
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module Budgets
|
7
|
+
module Admin
|
8
|
+
module Filterable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
include Decidim::Admin::Filterable
|
13
|
+
|
14
|
+
helper Decidim::Budgets::Admin::FilterableHelper
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def base_query
|
19
|
+
collection
|
20
|
+
end
|
21
|
+
|
22
|
+
def search_field_predicate
|
23
|
+
:id_string_or_title_cont
|
24
|
+
end
|
25
|
+
|
26
|
+
def filters
|
27
|
+
[
|
28
|
+
:scope_id_eq,
|
29
|
+
:category_id_eq,
|
30
|
+
:selected_at_null
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
def filters_with_values
|
35
|
+
{
|
36
|
+
scope_id_eq: scope_ids_hash(scopes.top_level),
|
37
|
+
category_id_eq: category_ids_hash(categories.first_class),
|
38
|
+
selected_at_null: [true, false]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
# Can't user `super` here, because it does not belong to a superclass
|
43
|
+
# but to a concern.
|
44
|
+
def dynamically_translated_filters
|
45
|
+
[:scope_id_eq, :category_id_eq]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -7,9 +7,14 @@ module Decidim
|
|
7
7
|
class ProjectsController < Admin::ApplicationController
|
8
8
|
include Decidim::ApplicationHelper
|
9
9
|
include Decidim::Proposals::Admin::Picker if Decidim::Budgets.enable_proposal_linking
|
10
|
+
include Decidim::Budgets::Admin::Filterable
|
10
11
|
|
11
12
|
helper_method :projects, :finished_orders, :pending_orders, :present
|
12
13
|
|
14
|
+
def collection
|
15
|
+
@collection ||= budget.projects.page(params[:page]).per(15)
|
16
|
+
end
|
17
|
+
|
13
18
|
def new
|
14
19
|
enforce_permission_to :create, :project
|
15
20
|
@form = form(ProjectForm).from_params(
|
@@ -72,7 +77,7 @@ module Decidim
|
|
72
77
|
private
|
73
78
|
|
74
79
|
def projects
|
75
|
-
@projects ||=
|
80
|
+
@projects ||= filtered_collection
|
76
81
|
end
|
77
82
|
|
78
83
|
def orders
|
@@ -20,7 +20,7 @@ module Decidim
|
|
20
20
|
end
|
21
21
|
|
22
22
|
on(:invalid) do
|
23
|
-
render
|
23
|
+
format.js { render "update_budget", status: :unprocessable_entity }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -35,7 +35,7 @@ module Decidim
|
|
35
35
|
end
|
36
36
|
|
37
37
|
on(:invalid) do
|
38
|
-
render
|
38
|
+
format.js { render "update_budget", status: :unprocessable_entity }
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -46,7 +46,8 @@ module Decidim
|
|
46
46
|
# delimiter. Otherwise e.g. ID 2 would match ID "26" in the original
|
47
47
|
# array. This is why we search for match ",2," instead to get the actual
|
48
48
|
# position for ID 2.
|
49
|
-
|
49
|
+
concat_ids = connection.quote(",#{ids.join(",")},")
|
50
|
+
order(Arel.sql("position(concat(',', id::text, ',') in #{concat_ids})"))
|
50
51
|
end
|
51
52
|
|
52
53
|
def self.log_presenter_class_for(_log)
|
@@ -92,6 +93,32 @@ module Decidim
|
|
92
93
|
def attachment_context
|
93
94
|
:admin
|
94
95
|
end
|
96
|
+
|
97
|
+
ransacker :id_string do
|
98
|
+
Arel.sql(%{cast("decidim_budgets_projects"."id" as text)})
|
99
|
+
end
|
100
|
+
|
101
|
+
# Allow ransacker to search for a key in a hstore column (`title`.`en`)
|
102
|
+
ransacker :title do |parent|
|
103
|
+
Arel::Nodes::InfixOperation.new("->>", parent.table[:title], Arel::Nodes.build_quoted(I18n.locale.to_s))
|
104
|
+
end
|
105
|
+
|
106
|
+
ransacker :selected do
|
107
|
+
Arel.sql(%{("decidim_budgets_projects"."selected_at")::text})
|
108
|
+
end
|
109
|
+
|
110
|
+
ransacker :confirmed_orders_count do
|
111
|
+
query = <<-SQL.squish
|
112
|
+
(
|
113
|
+
SELECT COUNT(decidim_budgets_line_items.decidim_order_id)
|
114
|
+
FROM decidim_budgets_line_items
|
115
|
+
LEFT JOIN decidim_budgets_orders ON decidim_budgets_orders.id = decidim_budgets_line_items.decidim_order_id
|
116
|
+
WHERE decidim_budgets_orders.checked_out_at IS NOT NULL
|
117
|
+
AND decidim_budgets_projects.id = decidim_budgets_line_items.decidim_project_id
|
118
|
+
)
|
119
|
+
SQL
|
120
|
+
Arel.sql(query)
|
121
|
+
end
|
95
122
|
end
|
96
123
|
end
|
97
124
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
const currentAllocationZero = () => {
|
2
|
+
const $budgetSummary = $(".budget-summary__progressbox");
|
3
|
+
return parseInt($budgetSummary.attr("data-current-allocation"), 10) === 0;
|
4
|
+
}
|
5
|
+
|
6
|
+
const isSafeUrl = (exitUrl) => {
|
7
|
+
if (!exitUrl) {
|
8
|
+
return false
|
9
|
+
}
|
10
|
+
|
11
|
+
const safeUrls = [
|
12
|
+
$(".budget-summary").attr("data-safe-url").split("?")[0],
|
13
|
+
`${location.pathname}#`,
|
14
|
+
`${location.href}#`,
|
15
|
+
"#"
|
16
|
+
];
|
17
|
+
|
18
|
+
let safe = false;
|
19
|
+
safeUrls.forEach((url) => {
|
20
|
+
if (exitUrl.startsWith(url)) {
|
21
|
+
safe = true
|
22
|
+
}
|
23
|
+
});
|
24
|
+
|
25
|
+
return safe;
|
26
|
+
}
|
27
|
+
|
28
|
+
const allowExitFrom = ($el) => {
|
29
|
+
if (currentAllocationZero()) {
|
30
|
+
return true
|
31
|
+
} else if ($el.attr("target") === "_blank") {
|
32
|
+
return true;
|
33
|
+
} else if ($el.parents("#loginModal").length > 0) {
|
34
|
+
return true;
|
35
|
+
} else if ($el.parents("#authorizationModal").length > 0) {
|
36
|
+
return true;
|
37
|
+
} else if ($el.attr("id") === "exit-notification-link") {
|
38
|
+
return true;
|
39
|
+
} else if ($el.parents(".voting-wrapper").length > 0) {
|
40
|
+
return true;
|
41
|
+
} else if (isSafeUrl($el.attr("href"))) {
|
42
|
+
return true
|
43
|
+
}
|
44
|
+
|
45
|
+
return false;
|
46
|
+
}
|
47
|
+
|
48
|
+
// Don't show browser's default confirmation panel when visit current_path is called in tests.
|
49
|
+
const testReload = (initialLocation) => {
|
50
|
+
if (navigator && navigator.webdriver && initialLocation === location.href) {
|
51
|
+
return true;
|
52
|
+
}
|
53
|
+
|
54
|
+
return false;
|
55
|
+
}
|
56
|
+
|
57
|
+
$(() => {
|
58
|
+
const $exitNotification = $("#exit-notification");
|
59
|
+
const $exitLink = $("#exit-notification-link");
|
60
|
+
const defaultExitUrl = $exitLink.attr("href");
|
61
|
+
const defaultExitLinkText = $exitLink.text();
|
62
|
+
let exitLinkText = defaultExitLinkText;
|
63
|
+
const initialLocation = location.href;
|
64
|
+
|
65
|
+
if ($exitNotification.length < 1) {
|
66
|
+
// Do not apply when not inside the voting pipeline
|
67
|
+
return;
|
68
|
+
}
|
69
|
+
|
70
|
+
const openExitNotification = (url, method = null) => {
|
71
|
+
if (method && method !== "get") {
|
72
|
+
$exitLink.attr("data-method", method);
|
73
|
+
} else {
|
74
|
+
$exitLink.removeAttr("data-method");
|
75
|
+
}
|
76
|
+
|
77
|
+
$exitLink.attr("href", url);
|
78
|
+
$exitLink.html(exitLinkText);
|
79
|
+
$exitNotification.foundation("open");
|
80
|
+
};
|
81
|
+
|
82
|
+
// Handle "beforeunload"
|
83
|
+
window.allowExit = false;
|
84
|
+
$(document).on("click", "a", (event) => {
|
85
|
+
exitLinkText = defaultExitLinkText;
|
86
|
+
window.allowExit = false;
|
87
|
+
|
88
|
+
const $link = $(event.currentTarget);
|
89
|
+
if (allowExitFrom($link)) {
|
90
|
+
window.allowExit = true;
|
91
|
+
} else {
|
92
|
+
event.preventDefault();
|
93
|
+
openExitNotification($link.attr("href"), $link.data("method"));
|
94
|
+
}
|
95
|
+
});
|
96
|
+
// Custom handling for the header sign out so that it won't trigger the
|
97
|
+
// logout form submit and so that it changes the exit link text. This does
|
98
|
+
// not trigger the document link click listener because it has the
|
99
|
+
// data-method attribute to trigger a form submit event.
|
100
|
+
$(".header a.sign-out-link").on("click", (event) => {
|
101
|
+
event.preventDefault();
|
102
|
+
event.stopPropagation();
|
103
|
+
|
104
|
+
const $link = $(event.currentTarget);
|
105
|
+
exitLinkText = $link.text();
|
106
|
+
openExitNotification($link.attr("href"), $link.data("method"));
|
107
|
+
});
|
108
|
+
// Custom handling for the exit link which needs to change the exit link
|
109
|
+
// text to the default text as this is not handled by the document click
|
110
|
+
// listener.
|
111
|
+
$("a[data-open='exit-notification']").on("click", () => {
|
112
|
+
exitLinkText = defaultExitLinkText;
|
113
|
+
openExitNotification(defaultExitUrl);
|
114
|
+
});
|
115
|
+
// Allow all form submits on the page, including language change and sign
|
116
|
+
// out form (when triggered by the exit link click).
|
117
|
+
$(document).on("submit", "form", () => {
|
118
|
+
window.allowExit = true;
|
119
|
+
});
|
120
|
+
|
121
|
+
window.addEventListener("beforeunload", (event) => {
|
122
|
+
const allowExit = window.allowExit;
|
123
|
+
window.allowExit = false;
|
124
|
+
|
125
|
+
if (allowExit || testReload(initialLocation)) {
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
|
129
|
+
event.returnValue = true;
|
130
|
+
});
|
131
|
+
});
|
@@ -3,28 +3,28 @@ $(() => {
|
|
3
3
|
const $budgetSummaryTotal = $(".budget-summary__total");
|
4
4
|
const $budgetExceedModal = $("#budget-excess");
|
5
5
|
const $budgetSummary = $(".budget-summary__progressbox");
|
6
|
+
const $voteButton = $(".budget-vote-button");
|
6
7
|
const totalAllocation = parseInt($budgetSummaryTotal.attr("data-total-allocation"), 10);
|
7
8
|
|
8
9
|
const cancelEvent = (event) => {
|
10
|
+
$(event.currentTarget).removeClass("loading-spinner");
|
9
11
|
event.stopPropagation();
|
10
12
|
event.preventDefault();
|
11
13
|
};
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
} else if ($el.parents("#authorizationModal").length > 0) {
|
17
|
-
return true;
|
18
|
-
}
|
19
|
-
|
20
|
-
return false;
|
21
|
-
}
|
15
|
+
$voteButton.on("click", "span", () => {
|
16
|
+
$(".budget-list__action").click();
|
17
|
+
});
|
22
18
|
|
23
19
|
$projects.on("click", ".budget-list__action", (event) => {
|
24
20
|
const currentAllocation = parseInt($budgetSummary.attr("data-current-allocation"), 10);
|
25
21
|
const $currentTarget = $(event.currentTarget);
|
26
22
|
const projectAllocation = parseInt($currentTarget.attr("data-allocation"), 10);
|
27
23
|
|
24
|
+
if (!$currentTarget.attr("data-open")) {
|
25
|
+
$currentTarget.addClass("loading-spinner");
|
26
|
+
}
|
27
|
+
|
28
28
|
if ($currentTarget.attr("disabled")) {
|
29
29
|
cancelEvent(event);
|
30
30
|
} else if (($currentTarget.attr("data-add") === "true") && ((currentAllocation + projectAllocation) > totalAllocation)) {
|
@@ -32,34 +32,4 @@ $(() => {
|
|
32
32
|
cancelEvent(event);
|
33
33
|
}
|
34
34
|
});
|
35
|
-
|
36
|
-
if ($("#order-progress [data-toggle=budget-confirm]").length > 0) {
|
37
|
-
const safeUrl = $(".budget-summary").attr("data-safe-url").split("?")[0];
|
38
|
-
$(document).on("click", "a", (event) => {
|
39
|
-
if (allowExitFrom($(event.currentTarget))) {
|
40
|
-
window.exitUrl = null;
|
41
|
-
} else {
|
42
|
-
window.exitUrl = event.currentTarget.href;
|
43
|
-
}
|
44
|
-
});
|
45
|
-
$(document).on("submit", "form", (event) => {
|
46
|
-
if (allowExitFrom($(event.currentTarget))) {
|
47
|
-
window.exitUrl = null;
|
48
|
-
} else {
|
49
|
-
window.exitUrl = event.currentTarget.action;
|
50
|
-
}
|
51
|
-
});
|
52
|
-
|
53
|
-
window.addEventListener("beforeunload", (event) => {
|
54
|
-
const currentAllocation = parseInt($budgetSummary.attr("data-current-allocation"), 10);
|
55
|
-
const exitUrl = window.exitUrl;
|
56
|
-
window.exitUrl = null;
|
57
|
-
|
58
|
-
if (currentAllocation === 0 || (exitUrl && exitUrl.startsWith(safeUrl))) {
|
59
|
-
return;
|
60
|
-
}
|
61
|
-
|
62
|
-
event.returnValue = true;
|
63
|
-
});
|
64
|
-
}
|
65
35
|
});
|