decidim-navigation_maps 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -3
- data/Rakefile +8 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_tabs_content.erb +1 -1
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/show.erb +2 -2
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_cell.rb +5 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_form.erb +4 -4
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_tabs_content.erb +0 -1
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/show.erb +4 -2
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form_cell.rb +9 -0
- data/app/controllers/decidim/navigation_maps/admin/blueprints_controller.rb +1 -1
- data/app/jobs/decidim/navigation_maps/migrate_legacy_images_job.rb +32 -0
- data/app/models/decidim/navigation_maps/blueprint.rb +4 -3
- data/app/packs/entrypoints/decidim_admin_navigation_maps.js +4 -0
- data/app/packs/entrypoints/decidim_admin_navigation_maps.scss +1 -0
- data/app/packs/entrypoints/decidim_navigation_maps.js +7 -0
- data/app/packs/entrypoints/decidim_navigation_maps.scss +1 -0
- data/app/packs/src/decidim/navigation_maps/admin/map_editor.js +83 -0
- data/app/packs/src/decidim/navigation_maps/admin/navigation_maps.js +154 -0
- data/app/packs/src/decidim/navigation_maps/map_view.js +125 -0
- data/app/packs/src/decidim/navigation_maps/navigation_maps.js +43 -0
- data/app/{assets → packs}/stylesheets/decidim/navigation_maps/_variables.scss +0 -0
- data/app/{assets → packs}/stylesheets/decidim/navigation_maps/admin/navigation_maps.scss +4 -4
- data/app/{assets → packs}/stylesheets/decidim/navigation_maps/navigation_maps.scss +1 -2
- data/app/uploaders/decidim/navigation_maps/blueprint_uploader.rb +4 -12
- data/app/uploaders/decidim/navigation_maps/cw/blueprint_uploader.rb +24 -0
- data/config/assets.rb +41 -0
- data/config/locales/cs.yml +1 -1
- data/db/seeds.rb +6 -5
- data/lib/decidim/navigation_maps/admin_engine.rb +0 -4
- data/lib/decidim/navigation_maps/engine.rb +4 -4
- data/lib/decidim/navigation_maps/navigation_map_cell_helpers.rb +1 -1
- data/lib/decidim/navigation_maps/version.rb +2 -2
- data/lib/decidim/navigation_maps.rb +0 -2
- data/lib/tasks/decidim_navigation_maps_webpacker_tasks.rake +58 -0
- data/lib/tasks/navigation_maps_active_storage_migration_tasks.rake +37 -0
- metadata +31 -27
- data/app/assets/config/admin/decidim_navigation_maps_manifest.css +0 -3
- data/app/assets/config/admin/decidim_navigation_maps_manifest.js +0 -3
- data/app/assets/config/decidim_navigation_maps_manifest.css +0 -3
- data/app/assets/config/decidim_navigation_maps_manifest.js +0 -1
- data/app/assets/images/decidim/navigation_maps/icon.svg +0 -1
- data/app/assets/javascripts/decidim/navigation_maps/admin/map_editor.js +0 -88
- data/app/assets/javascripts/decidim/navigation_maps/admin/navigation_maps.js +0 -143
- data/app/assets/javascripts/decidim/navigation_maps/map_view.js +0 -123
- data/app/assets/javascripts/decidim/navigation_maps/navigation_maps.js +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 555b93edb92b69f19e3cc10841179b04fb57502a13d347fe69132d01833f88d6
|
4
|
+
data.tar.gz: 76da0880561f5e1e5b1201a048d90c8a862194134f3e485c1d2d045401f61551
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d90681644ff2111df383e19b5e7e7568c97cc225aad75645dcd86369332e91d4ef0d0fcc0ea6413c7bcb83bab0239333fb926958d8a32e62df5e2b52bd7353d1
|
7
|
+
data.tar.gz: bbc246049572a74e697a0382bd084213cdff071149ea1c2ef1a93eae78da2d1ceeba110b394c16c9877b5c88ecd96fca0c674b1f72193b7b86b993a5707c6daf
|
data/README.md
CHANGED
@@ -24,7 +24,7 @@ homepage only).
|
|
24
24
|
Add this line to your application's Gemfile:
|
25
25
|
|
26
26
|
```ruby
|
27
|
-
gem "decidim-navigation_maps"
|
27
|
+
gem "decidim-navigation_maps"
|
28
28
|
```
|
29
29
|
|
30
30
|
And then execute (remember to repeat this if you are upgrading from version 1.1):
|
@@ -32,16 +32,35 @@ And then execute (remember to repeat this if you are upgrading from version 1.1)
|
|
32
32
|
```bash
|
33
33
|
bundle
|
34
34
|
bundle exec rails decidim_navigation_maps:install:migrations
|
35
|
+
bundle exec rails decidim_navigation_maps:webpacker:install
|
35
36
|
bundle exec rails db:migrate
|
36
37
|
```
|
37
38
|
|
39
|
+
> NOTE: the `decidim_notify:webpacker:install` is only necessary for Decidim versions starting at 0.25.
|
40
|
+
|
41
|
+
If you are upgrading from a version prior to 1.3, make sure that you migrate your existing images to Active Storae:
|
42
|
+
|
43
|
+
```
|
44
|
+
RAILS_ENV=production bin/rails navigation_maps:active_storage_migrations:migrate_from_carrierwave
|
45
|
+
```
|
46
|
+
|
47
|
+
Or check your migration status with:
|
48
|
+
```
|
49
|
+
RAILS_ENV=production bin/rails navigation_maps:active_storage_migrations:check_migration_from_carrierwave
|
50
|
+
```
|
51
|
+
|
52
|
+
The correct version of Navigation Maps should resolved automatically by the Bundler.
|
53
|
+
However you can force some specific version using `gem "decidim-navigation_maps", "~> 1.3.0"` in the Gemfile.
|
54
|
+
|
55
|
+
|
38
56
|
Depending on your Decidim version, choose the corresponding Plugin version to ensure compatibility:
|
39
57
|
|
40
58
|
| Navigation Maps version | Compatible Decidim versions |
|
41
59
|
|---|---|
|
42
|
-
| 1.
|
43
|
-
| 1.1.x | 0.22.x, 0.23.x |
|
60
|
+
| 1.3.x | 0.25.x, 0.26.x |
|
44
61
|
| 1.2.x | 0.24.x |
|
62
|
+
| 1.1.x | 0.22.x, 0.23.x |
|
63
|
+
| 1.0.x | 0.18.x - 0.21.x |
|
45
64
|
|
46
65
|
## Contributing
|
47
66
|
|
data/Rakefile
CHANGED
@@ -9,6 +9,12 @@ def install_module(path)
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
def override_webpacker_config_files(path)
|
13
|
+
Dir.chdir(path) do
|
14
|
+
system("bundle exec rake decidim_navigation_maps:webpacker:install")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
12
18
|
def seed_db(path)
|
13
19
|
Dir.chdir(path) do
|
14
20
|
system("bundle exec rake db:seed")
|
@@ -25,6 +31,7 @@ desc "Generates a dummy app for testing"
|
|
25
31
|
task test_app: "decidim:generate_external_test_app" do
|
26
32
|
ENV["RAILS_ENV"] = "test"
|
27
33
|
install_module("spec/decidim_dummy_app")
|
34
|
+
override_webpacker_config_files("spec/decidim_dummy_app")
|
28
35
|
end
|
29
36
|
|
30
37
|
desc "Generates a development app"
|
@@ -42,6 +49,7 @@ task :development_app do
|
|
42
49
|
end
|
43
50
|
|
44
51
|
install_module("development_app")
|
52
|
+
override_webpacker_config_files("development_app")
|
45
53
|
ENV["SKIP_MODULE_SEEDS"] = "1"
|
46
54
|
seed_db("development_app")
|
47
55
|
# manually seed navigation maps to ensure participatory process groups are created
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<div class="tabs-content admin" data-tabs-content="navigation_maps-tabs">
|
3
3
|
<% tabs.each_with_index do |item, index| %>
|
4
4
|
<div class="tabs-panel<%= " is-active" if index.zero? %>" id="map<%= index %>">
|
5
|
-
<%= content_tag(:div, "", id: "navigation_maps-map-#{item.id}", class: "map", style: "height: #{item.height}px", data: { id: item.id, image: item.image
|
5
|
+
<%= content_tag(:div, "", id: "navigation_maps-map-#{item.id}", class: "map", style: "height: #{item.height}px", data: { id: item.id, image: image_path(item.image), blueprint: item.blueprint }) %>
|
6
6
|
</div>
|
7
7
|
<% end %>
|
8
8
|
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%=
|
1
|
+
<%= stylesheet_pack_tag "decidim_navigation_maps" %>
|
2
2
|
<%= render partial: "styles", locals: { blueprints: valid_blueprints } %>
|
3
3
|
|
4
4
|
<section<%= class_tag(section_classes) %>>
|
@@ -18,4 +18,4 @@
|
|
18
18
|
</section>
|
19
19
|
|
20
20
|
<%= render partial: "template" %>
|
21
|
-
<%=
|
21
|
+
<%= javascript_pack_tag "decidim_navigation_maps" %>
|
data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_form.erb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
<ul class="accordion" data-accordion>
|
2
|
-
<li class="accordion-item<%= " is-active" unless
|
2
|
+
<li class="accordion-item<%= " is-active" unless image?(form) %>" data-accordion-item>
|
3
3
|
<a href="#" class="accordion-title"><%= t("navigation_map_settings_form.info", scope: "decidim.navigation_maps.content_blocks") %></a>
|
4
4
|
|
5
5
|
<div class="accordion-content" data-tab-content>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
<%= label_tag t("navigation_map_settings_form.blueprint_image", scope: "decidim.navigation_maps.content_blocks") %>
|
11
11
|
<div class="thumbnail">
|
12
|
-
<%= image_tag form.image
|
12
|
+
<%= image_tag image_path(form.image, variant: :thumbnail) if image?(form) %>
|
13
13
|
</div>
|
14
14
|
<%= file_field_tag "blueprints[#{form.ident}][image]", { id: "blueprints_#{form.ident}_image", label: t("navigation_map_settings_form.title", scope: "decidim.navigation_maps.content_blocks") } %>
|
15
15
|
|
@@ -25,12 +25,12 @@
|
|
25
25
|
</div>
|
26
26
|
</li>
|
27
27
|
|
28
|
-
<% if
|
28
|
+
<% if image?(form) %>
|
29
29
|
<li class="accordion-item is-active" data-accordion-item>
|
30
30
|
<a href="#" class="accordion-title"><%= t("navigation_map_settings_form.editor", scope: "decidim.navigation_maps.content_blocks") %></a>
|
31
31
|
<div class="accordion-content navigation_maps-content" data-tab-content>
|
32
32
|
|
33
|
-
<%= content_tag(:div, "", id: "navigation_maps-map-#{form.ident}", class: "map", data: { id: form.ident, image: form.image
|
33
|
+
<%= content_tag(:div, "", id: "navigation_maps-map-#{form.ident}", class: "map", data: { id: form.ident, image: image_path(form.image), blueprint: form.blueprint }) %>
|
34
34
|
|
35
35
|
</div>
|
36
36
|
</li>
|
@@ -33,5 +33,7 @@
|
|
33
33
|
</div>
|
34
34
|
|
35
35
|
<%= render partial: "modal" %>
|
36
|
-
|
37
|
-
<%=
|
36
|
+
<%# we need to rely on a CDN due a bug in webpacker that renders twice jquery if importing a plugin %>
|
37
|
+
<%= javascript_include_tag "https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.3.0/jquery.form.min.js", integrity: "sha384-qlmct0AOBiA2VPZkMY3+2WqkHtIQ9lSdAsAn5RUJD/3vA5MKDgSGcdmIv4ycVxyn", crossorigin: "anonymous" %>
|
38
|
+
<%= javascript_pack_tag "decidim_admin_navigation_maps" %>
|
39
|
+
<%= stylesheet_pack_tag "decidim_admin_navigation_maps" %>
|
@@ -26,6 +26,15 @@ module Decidim
|
|
26
26
|
def label
|
27
27
|
I18n.t("decidim.content_blocks.html.html_content")
|
28
28
|
end
|
29
|
+
|
30
|
+
def image?(frm)
|
31
|
+
frm.image.attached?
|
32
|
+
end
|
33
|
+
|
34
|
+
def image_path(image, options = {})
|
35
|
+
options.merge!({ only_path: true })
|
36
|
+
Rails.application.routes.url_helpers.rails_blob_url(image, options)
|
37
|
+
end
|
29
38
|
end
|
30
39
|
end
|
31
40
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module NavigationMaps
|
5
|
+
class MigrateLegacyImagesJob < ApplicationJob
|
6
|
+
queue_as :default
|
7
|
+
|
8
|
+
def perform(organization_id, mappings = [], logger = Rails.logger)
|
9
|
+
@organization_id = organization_id
|
10
|
+
@routes_mappings = mappings
|
11
|
+
@logger = logger
|
12
|
+
|
13
|
+
migrate_all!
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :routes_mappings, :logger
|
19
|
+
|
20
|
+
def migrate_all!
|
21
|
+
Decidim::CarrierWaveMigratorService.migrate_attachment!(
|
22
|
+
klass: Decidim::NavigationMaps::BluePrint,
|
23
|
+
cw_attribute: "image",
|
24
|
+
cw_uploader: Decidim::NavigationMaps::Cw::ImageUploader,
|
25
|
+
as_attribute: "image",
|
26
|
+
logger: @logger,
|
27
|
+
routes_mappings: routes_mappings
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -4,6 +4,8 @@ module Decidim
|
|
4
4
|
module NavigationMaps
|
5
5
|
# Abstract class from which all models in this engine inherit.
|
6
6
|
class Blueprint < ApplicationRecord
|
7
|
+
include Decidim::HasUploadValidations
|
8
|
+
|
7
9
|
self.table_name = "decidim_navigation_maps_blueprints"
|
8
10
|
|
9
11
|
attribute :height, :integer, default: 475
|
@@ -16,11 +18,10 @@ module Decidim
|
|
16
18
|
dependent: :destroy
|
17
19
|
|
18
20
|
validates :organization, presence: true
|
19
|
-
validates :image,
|
20
|
-
file_content_type: { allow: ["image/jpeg", "image/png", "image/svg+xml"] }
|
21
21
|
validates :height, numericality: { greater_than: 0 }
|
22
22
|
|
23
|
-
|
23
|
+
has_one_attached :image
|
24
|
+
validates_upload :image, uploader: Decidim::NavigationMaps::BlueprintUploader
|
24
25
|
|
25
26
|
def blueprint
|
26
27
|
areas.map { |area| [area.area_id.to_s, area.to_geoson] }.to_h
|
@@ -0,0 +1 @@
|
|
1
|
+
@import "stylesheets/decidim/navigation_maps/admin/navigation_maps";
|
@@ -0,0 +1 @@
|
|
1
|
+
@import "stylesheets/decidim/navigation_maps/navigation_maps";
|
@@ -0,0 +1,83 @@
|
|
1
|
+
// Creates a map
|
2
|
+
import NavigationMapView from "src/decidim/navigation_maps/map_view.js";
|
3
|
+
|
4
|
+
export default class NavigationMapEditor extends NavigationMapView {
|
5
|
+
constructor(map_object, table_object) {
|
6
|
+
// Call constructor of superclass to initialize superclass-derived members.
|
7
|
+
super(map_object, () => {
|
8
|
+
this.createControls();
|
9
|
+
if (this.blueprint) {
|
10
|
+
this.createAreas();
|
11
|
+
}
|
12
|
+
});
|
13
|
+
this.table_object = table_object;
|
14
|
+
this.createAreaCallback = function () {};
|
15
|
+
this.editAreaCallback = function () {};
|
16
|
+
this.removeAreaCallback = function () {};
|
17
|
+
}
|
18
|
+
|
19
|
+
createControls() {
|
20
|
+
this.map.pm.addControls({
|
21
|
+
position: "topleft",
|
22
|
+
drawCircle: false,
|
23
|
+
drawMarker: false,
|
24
|
+
drawCircleMarker: false,
|
25
|
+
drawPolyline: false,
|
26
|
+
cutPolygon: false
|
27
|
+
});
|
28
|
+
|
29
|
+
this.map.on("pm:create", (e) => {
|
30
|
+
let geojson = e.layer.toGeoJSON();
|
31
|
+
this.blueprint[e.layer._leaflet_id] = geojson;
|
32
|
+
this.attachEditorEvents(e.layer);
|
33
|
+
this.createAreaCallback(e.layer._leaflet_id, e.layer, this);
|
34
|
+
});
|
35
|
+
|
36
|
+
this.map.on("pm:remove", (e) => {
|
37
|
+
delete this.blueprint[e.layer._leaflet_id];
|
38
|
+
this.removeAreaCallback(e.layer._leaflet_id, e.layer, this);
|
39
|
+
});
|
40
|
+
};
|
41
|
+
|
42
|
+
editing() {
|
43
|
+
let pm = this.map.pm;
|
44
|
+
return pm.globalRemovalEnabled() || pm.globalDragModeEnabled() || pm.globalEditEnabled();
|
45
|
+
};
|
46
|
+
|
47
|
+
// register callback to handle area edits,removals and creations
|
48
|
+
onCreateArea(callback) {
|
49
|
+
this.createAreaCallback = callback;
|
50
|
+
};
|
51
|
+
onEditArea(callback) {
|
52
|
+
this.editAreaCallback = callback;
|
53
|
+
};
|
54
|
+
onRemoveArea(callback) {
|
55
|
+
this.removeCreateCallback = callback;
|
56
|
+
};
|
57
|
+
|
58
|
+
attachEditorEvents (layer) {
|
59
|
+
layer.on("mouseover", (e) => {
|
60
|
+
e.target.getElement().classList.add("selected")
|
61
|
+
});
|
62
|
+
|
63
|
+
layer.on("mouseout", (e) => {
|
64
|
+
e.target.getElement().classList.remove("selected")
|
65
|
+
});
|
66
|
+
|
67
|
+
layer.on("pm:edit", (e) => {
|
68
|
+
this.blueprint[e.target._leaflet_id] = e.target.toGeoJSON();
|
69
|
+
this.editAreaCallback(e.target._leaflet_id, e.target, this);
|
70
|
+
});
|
71
|
+
|
72
|
+
layer.on("click", (e) => {
|
73
|
+
if (!this.editing()) {
|
74
|
+
this.clickAreaCallback(e.target._leaflet_id, e.target, this);
|
75
|
+
}
|
76
|
+
});
|
77
|
+
};
|
78
|
+
|
79
|
+
getBlueprint () {
|
80
|
+
return this.blueprint;
|
81
|
+
};
|
82
|
+
|
83
|
+
}
|
@@ -0,0 +1,154 @@
|
|
1
|
+
// Place all the behaviors and hooks related to the matching controller here.
|
2
|
+
// All this logic will automatically be available in application.js.
|
3
|
+
// import "jquery-form"; // we use a CDN instead due a bug in webpacker
|
4
|
+
import NavigationMapEditor from "src/decidim/navigation_maps/admin/map_editor.js";
|
5
|
+
|
6
|
+
$(() => {
|
7
|
+
|
8
|
+
let $maps = $(".navigation_maps.admin .map");
|
9
|
+
let $progress = $(".navigation_maps.admin .progress");
|
10
|
+
let $bar = $(".navigation_maps.admin .progress-meter");
|
11
|
+
let $loading = $(".navigation_maps.admin .loading");
|
12
|
+
let $callout = $(".navigation_maps.admin .callout");
|
13
|
+
let $modal = $("#mapEditModal");
|
14
|
+
let $form = $("form");
|
15
|
+
let $tabs = $("#navigation_maps-tabs");
|
16
|
+
let $accordion = $(".navigation_maps.admin .accordion");
|
17
|
+
let editors = {};
|
18
|
+
let new_areas = {};
|
19
|
+
|
20
|
+
$maps.each((_i, el) => {
|
21
|
+
let id = $(el).data("id");
|
22
|
+
let table = document.getElementById(`navigation_maps-table-${id}`);
|
23
|
+
editors[id] = new NavigationMapEditor(el, table);
|
24
|
+
editors[id].onCreateArea((area_id) => {
|
25
|
+
new_areas[area_id] = true;
|
26
|
+
});
|
27
|
+
|
28
|
+
editors[id].onClickArea((area_id, area) => {
|
29
|
+
$modal.find(".modal-content").html("");
|
30
|
+
$modal.addClass("loading").foundation("open");
|
31
|
+
$callout.hide();
|
32
|
+
$callout.removeClass("alert success");
|
33
|
+
// "new" form insted of editing
|
34
|
+
let rel = new_areas[area_id]
|
35
|
+
? "new"
|
36
|
+
: area_id;
|
37
|
+
$modal.find(".modal-content").load(`/admin/navigation_maps/blueprints/${id}/areas/${rel}`, () => {
|
38
|
+
let $input1 = $modal.find('input[name="blueprint_area[area_id]"]');
|
39
|
+
let $input2 = $modal.find('input[name="blueprint_area[area_type]"]');
|
40
|
+
let $input3 = $modal.find('input[name="blueprint_area[area]"]');
|
41
|
+
let a = area.toGeoJSON();
|
42
|
+
$modal.removeClass("loading");
|
43
|
+
if ($input1.length) {
|
44
|
+
$input1.val(area_id);
|
45
|
+
}
|
46
|
+
if ($input2.length) {
|
47
|
+
$input2.val(a.type);
|
48
|
+
}
|
49
|
+
if ($input3.length) {
|
50
|
+
$input3.val(JSON.stringify(a));
|
51
|
+
}
|
52
|
+
$modal.find("ul[data-tabs=true]").each(() => {
|
53
|
+
new Foundation.Tabs($(el)); // eslint-disable-line
|
54
|
+
});
|
55
|
+
});
|
56
|
+
});
|
57
|
+
});
|
58
|
+
|
59
|
+
// Rails AJAX events
|
60
|
+
document.body.addEventListener("ajax:error", (responseText) => {
|
61
|
+
$callout.contents("p").html(`${responseText.detail[0].message}: <strong>${responseText.detail[0].error}</strong>`);
|
62
|
+
$callout.addClass("alert");
|
63
|
+
});
|
64
|
+
|
65
|
+
document.body.addEventListener("ajax:success", (responseText) => {
|
66
|
+
if (new_areas[responseText.detail[0].area]) {
|
67
|
+
delete new_areas[responseText.detail[0].area]
|
68
|
+
}
|
69
|
+
let blueprint_id = responseText.detail[0].blueprint_id;
|
70
|
+
let area_id = responseText.detail[0].area_id;
|
71
|
+
let area = responseText.detail[0].area;
|
72
|
+
editors[blueprint_id].setLayerProperties(editors[blueprint_id].map._layers[area_id], area);
|
73
|
+
editors[blueprint_id].blueprint[area_id] = area;
|
74
|
+
$callout.contents("p").html(responseText.detail[0].message);
|
75
|
+
$callout.addClass("success");
|
76
|
+
});
|
77
|
+
|
78
|
+
document.body.addEventListener("ajax:complete", () => {
|
79
|
+
$callout.show();
|
80
|
+
$modal.foundation("close");
|
81
|
+
})
|
82
|
+
|
83
|
+
$tabs.on("change.zf.tabs", (e, $tab, $content) => {
|
84
|
+
let id = $content.find(".map").data("id");
|
85
|
+
if (id) {
|
86
|
+
editors[id].reload();
|
87
|
+
}
|
88
|
+
});
|
89
|
+
|
90
|
+
$accordion.on("down.zf.accordion", () => {
|
91
|
+
let id = $accordion.find(".map").data("id");
|
92
|
+
if (id) {
|
93
|
+
editors[id].reload();
|
94
|
+
}
|
95
|
+
});
|
96
|
+
|
97
|
+
// If a new item si going to be created o the image is changed a reload is needed
|
98
|
+
let needsReload = () => {
|
99
|
+
let reload = false;
|
100
|
+
if ($form.find("#map-new input:checked").length) {
|
101
|
+
return true;
|
102
|
+
}
|
103
|
+
if ($form.find(".delete-tab input[type=checkbox]:checked").length) {
|
104
|
+
return true;
|
105
|
+
}
|
106
|
+
|
107
|
+
$form.find("input[type=file],input[tabs_id=blueprints___title]").each((_i, el) => {
|
108
|
+
if ($(el).val()) {
|
109
|
+
reload = true;
|
110
|
+
return false;
|
111
|
+
}
|
112
|
+
});
|
113
|
+
return reload;
|
114
|
+
};
|
115
|
+
|
116
|
+
$form.ajaxForm({
|
117
|
+
url: $form.find("[name=action]").val(),
|
118
|
+
beforeSerialize: () => {
|
119
|
+
Object.keys(editors).forEach((key) => {
|
120
|
+
let editor = editors[key];
|
121
|
+
$(`#blueprints_${editor.id}_blueprint`).val(JSON.stringify(editor.getBlueprint()));
|
122
|
+
});
|
123
|
+
},
|
124
|
+
beforeSend: () => {
|
125
|
+
let percentVal = "0%";
|
126
|
+
$bar.width(percentVal).html(percentVal);
|
127
|
+
$progress.show();
|
128
|
+
$callout.hide();
|
129
|
+
$callout.removeClass("alert success");
|
130
|
+
$loading.show();
|
131
|
+
},
|
132
|
+
uploadProgress: (event, position, total, percentComplete) => { // eslint-disable-line
|
133
|
+
let percentVal = `${percentComplete}%`;
|
134
|
+
$bar.width(percentVal).html(percentVal);
|
135
|
+
},
|
136
|
+
success: (responseText) => {
|
137
|
+
$callout.show();
|
138
|
+
$progress.hide();
|
139
|
+
$callout.contents("p").html(responseText);
|
140
|
+
$callout.addClass("success");
|
141
|
+
$loading.hide();
|
142
|
+
if (needsReload()) {
|
143
|
+
$loading.show();
|
144
|
+
location.reload();
|
145
|
+
}
|
146
|
+
},
|
147
|
+
error: (xhr) => {
|
148
|
+
$loading.hide();
|
149
|
+
$callout.show();
|
150
|
+
$callout.contents("p").html(xhr.responseText);
|
151
|
+
$callout.addClass("alert");
|
152
|
+
}
|
153
|
+
});
|
154
|
+
});
|
@@ -0,0 +1,125 @@
|
|
1
|
+
// Creates a map view
|
2
|
+
import "leaflet";
|
3
|
+
import "leaflet/dist/leaflet.css";
|
4
|
+
import "@geoman-io/leaflet-geoman-free";
|
5
|
+
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
|
6
|
+
|
7
|
+
export default class NavigationMapView {
|
8
|
+
constructor(map_object, imageDecorator) {
|
9
|
+
this.features = {};
|
10
|
+
this.map_object = map_object;
|
11
|
+
this.id = map_object.dataset.id;
|
12
|
+
this.image_path = map_object.dataset.image;
|
13
|
+
this.blueprint = map_object.dataset.blueprint
|
14
|
+
? JSON.parse(map_object.dataset.blueprint)
|
15
|
+
: {};
|
16
|
+
this.image = new Image();
|
17
|
+
this.image.onload = () => {
|
18
|
+
this.createMap();
|
19
|
+
if (typeof imageDecorator === "function") {
|
20
|
+
imageDecorator(this);
|
21
|
+
} else if (this.blueprint) {
|
22
|
+
this.createAreas();
|
23
|
+
}
|
24
|
+
};
|
25
|
+
this.image.src = this.image_path;
|
26
|
+
this.clickAreaCallback = () => {};
|
27
|
+
this.setLayerPropertiesCallback = () => {};
|
28
|
+
}
|
29
|
+
|
30
|
+
createMap() {
|
31
|
+
let bounds = [[0, 0], [this.image.height, this.image.width]];
|
32
|
+
this.map = L.map(this.map_object, {
|
33
|
+
minZoom: -1,
|
34
|
+
maxZoom: 2,
|
35
|
+
crs: L.CRS.Simple,
|
36
|
+
noWrap: true,
|
37
|
+
zoomSnap: 0,
|
38
|
+
// zoomDelta: 0.1,
|
39
|
+
maxBounds: [[0, 0], [this.image.height, this.image.width]],
|
40
|
+
center: [this.image.height / 2, this.image.width / 2],
|
41
|
+
zoom: -1,
|
42
|
+
scrollWheelZoom: false,
|
43
|
+
attributionControl: false
|
44
|
+
});
|
45
|
+
|
46
|
+
L.imageOverlay(this.image.src, bounds).addTo(this.map);
|
47
|
+
this.fitBounds();
|
48
|
+
};
|
49
|
+
|
50
|
+
fitBounds() {
|
51
|
+
let image_ratio = this.image.height / this.image.width;
|
52
|
+
let map_ratio = this.map_object.offsetHeight / this.map_object.offsetWidth;
|
53
|
+
|
54
|
+
if (image_ratio > map_ratio) {
|
55
|
+
this.map.fitBounds([[0, 0], [0, this.image.width]]);
|
56
|
+
}
|
57
|
+
else {
|
58
|
+
this.map.fitBounds([[0, 0], [this.image.height, 0]]);
|
59
|
+
}
|
60
|
+
this.map.setView([this.image.height / 2, this.image.width / 2]);
|
61
|
+
};
|
62
|
+
|
63
|
+
createAreas() {
|
64
|
+
this.forEachBlueprint((id, geoarea) => {
|
65
|
+
new L.GeoJSON(geoarea, {
|
66
|
+
onEachFeature: (feature, layer) => {
|
67
|
+
layer._leaflet_id = id;
|
68
|
+
this.setLayerProperties(layer, geoarea);
|
69
|
+
this.attachEditorEvents(layer);
|
70
|
+
}
|
71
|
+
}).addTo(this.map);
|
72
|
+
});
|
73
|
+
};
|
74
|
+
|
75
|
+
setLayerProperties (layer, area) {
|
76
|
+
let props = area.properties;
|
77
|
+
if (props) {
|
78
|
+
if (props.color) {
|
79
|
+
layer.setStyle({fillColor: props.color, color: props.color});
|
80
|
+
}
|
81
|
+
this.setLayerPropertiesCallback(layer, props);
|
82
|
+
}
|
83
|
+
};
|
84
|
+
|
85
|
+
attachEditorEvents (layer) {
|
86
|
+
layer.on("mouseover", (e) => {
|
87
|
+
e.target.getElement().classList.add("selected")
|
88
|
+
});
|
89
|
+
|
90
|
+
layer.on("mouseout", (e) => {
|
91
|
+
e.target.getElement().classList.remove("selected")
|
92
|
+
});
|
93
|
+
|
94
|
+
layer.on("click", (e) => {
|
95
|
+
this.clickAreaCallback(e.target, this);
|
96
|
+
});
|
97
|
+
};
|
98
|
+
|
99
|
+
// register callback to handle area clicks
|
100
|
+
onClickArea(callback) {
|
101
|
+
this.clickAreaCallback = callback;
|
102
|
+
};
|
103
|
+
|
104
|
+
onSetLayerProperties(callback) {
|
105
|
+
this.setLayerPropertiesCallback = callback;
|
106
|
+
};
|
107
|
+
|
108
|
+
forEachBlueprint (decorator) {
|
109
|
+
for (let id in this.blueprint) {
|
110
|
+
let geoarea = this.blueprint[id];
|
111
|
+
// avoid non-polygons for the moment
|
112
|
+
if (geoarea.geometry && geoarea.geometry.type === "Polygon") {
|
113
|
+
decorator(id, geoarea);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
};
|
117
|
+
|
118
|
+
reload () {
|
119
|
+
if (this.map) {
|
120
|
+
this.map.invalidateSize(true);
|
121
|
+
this.fitBounds();
|
122
|
+
}
|
123
|
+
};
|
124
|
+
}
|
125
|
+
|