decidim-navigation_maps 1.2.0 → 1.3.0

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -3
  3. data/Rakefile +8 -0
  4. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_tabs_content.erb +1 -1
  5. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/show.erb +2 -2
  6. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_cell.rb +5 -0
  7. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_form.erb +4 -4
  8. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_tabs_content.erb +0 -1
  9. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/show.erb +4 -2
  10. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form_cell.rb +9 -0
  11. data/app/controllers/decidim/navigation_maps/admin/blueprints_controller.rb +1 -1
  12. data/app/jobs/decidim/navigation_maps/migrate_legacy_images_job.rb +32 -0
  13. data/app/models/decidim/navigation_maps/blueprint.rb +4 -3
  14. data/app/packs/entrypoints/decidim_admin_navigation_maps.js +4 -0
  15. data/app/packs/entrypoints/decidim_admin_navigation_maps.scss +1 -0
  16. data/app/packs/entrypoints/decidim_navigation_maps.js +7 -0
  17. data/app/packs/entrypoints/decidim_navigation_maps.scss +1 -0
  18. data/app/packs/src/decidim/navigation_maps/admin/map_editor.js +83 -0
  19. data/app/packs/src/decidim/navigation_maps/admin/navigation_maps.js +154 -0
  20. data/app/packs/src/decidim/navigation_maps/map_view.js +125 -0
  21. data/app/packs/src/decidim/navigation_maps/navigation_maps.js +43 -0
  22. data/app/{assets → packs}/stylesheets/decidim/navigation_maps/_variables.scss +0 -0
  23. data/app/{assets → packs}/stylesheets/decidim/navigation_maps/admin/navigation_maps.scss +4 -4
  24. data/app/{assets → packs}/stylesheets/decidim/navigation_maps/navigation_maps.scss +1 -2
  25. data/app/uploaders/decidim/navigation_maps/blueprint_uploader.rb +4 -12
  26. data/app/uploaders/decidim/navigation_maps/cw/blueprint_uploader.rb +24 -0
  27. data/config/assets.rb +41 -0
  28. data/config/locales/cs.yml +1 -1
  29. data/db/seeds.rb +6 -5
  30. data/lib/decidim/navigation_maps/admin_engine.rb +0 -4
  31. data/lib/decidim/navigation_maps/engine.rb +4 -4
  32. data/lib/decidim/navigation_maps/navigation_map_cell_helpers.rb +1 -1
  33. data/lib/decidim/navigation_maps/version.rb +2 -2
  34. data/lib/decidim/navigation_maps.rb +0 -2
  35. data/lib/tasks/decidim_navigation_maps_webpacker_tasks.rake +58 -0
  36. data/lib/tasks/navigation_maps_active_storage_migration_tasks.rake +37 -0
  37. metadata +31 -27
  38. data/app/assets/config/admin/decidim_navigation_maps_manifest.css +0 -3
  39. data/app/assets/config/admin/decidim_navigation_maps_manifest.js +0 -3
  40. data/app/assets/config/decidim_navigation_maps_manifest.css +0 -3
  41. data/app/assets/config/decidim_navigation_maps_manifest.js +0 -1
  42. data/app/assets/images/decidim/navigation_maps/icon.svg +0 -1
  43. data/app/assets/javascripts/decidim/navigation_maps/admin/map_editor.js +0 -88
  44. data/app/assets/javascripts/decidim/navigation_maps/admin/navigation_maps.js +0 -143
  45. data/app/assets/javascripts/decidim/navigation_maps/map_view.js +0 -123
  46. 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: 0e99886ba8f12f6602904f174d2d82542def72cc7e6eb2dcdaa07861876d7eed
4
- data.tar.gz: d57eef525c3197b6dcd5645cb1f5ed433762558223ee80895f78b34af4216230
3
+ metadata.gz: 555b93edb92b69f19e3cc10841179b04fb57502a13d347fe69132d01833f88d6
4
+ data.tar.gz: 76da0880561f5e1e5b1201a048d90c8a862194134f3e485c1d2d045401f61551
5
5
  SHA512:
6
- metadata.gz: b4a1b325b560400a2ee97b8ebd1d2e67e40a5472922e3cf631630233f8552576f54574c453ca4c73d6093410059cb154d3062861b8e6f29729a40db4f62cb6f7
7
- data.tar.gz: 71a153f0cc0c8e4675c5292e0a40248cd7510c39052e1b83856006bf3798340a9489078a0bfc23f02f68bc4087d377a8a9f724a5e5a52e1a8f14a2266d6e6a31
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", "~> 1.2.0"
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.0.x | 0.18.x - 0.21.x |
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.url, blueprint: item.blueprint }) %>
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
- <%= stylesheet_link_tag "decidim/navigation_maps/navigation_maps" %>
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
- <%= javascript_include_tag "decidim/navigation_maps/navigation_maps" %>
21
+ <%= javascript_pack_tag "decidim_navigation_maps" %>
@@ -42,6 +42,11 @@ module Decidim
42
42
 
43
43
  " class=\"#{class_string}\""
44
44
  end
45
+
46
+ def image_path(image, options = {})
47
+ options.merge!({ only_path: true })
48
+ Rails.application.routes.url_helpers.rails_blob_url(image, options)
49
+ end
45
50
  end
46
51
  end
47
52
  end
@@ -1,5 +1,5 @@
1
1
  <ul class="accordion" data-accordion>
2
- <li class="accordion-item<%= " is-active" unless form.image? %>" data-accordion-item>
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.thumbnail.url if 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 form.image? %>
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.url, blueprint: form.blueprint }) %>
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>
@@ -1,4 +1,3 @@
1
-
2
1
  <div class="tabs-content" data-tabs-content="navigation_maps-tabs">
3
2
  <% tabs.each_with_index do |item, index| %>
4
3
  <div class="tabs-panel<%= " is-active" if index.zero? %>" id="map<%= index %>">
@@ -33,5 +33,7 @@
33
33
  </div>
34
34
 
35
35
  <%= render partial: "modal" %>
36
- <%= javascript_include_tag "decidim/navigation_maps/admin/navigation_maps" %>
37
- <%= stylesheet_link_tag "decidim/navigation_maps/admin/navigation_maps" %>
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
@@ -13,7 +13,7 @@ module Decidim
13
13
  end
14
14
 
15
15
  def show
16
- render json: organization_blueprints.find(params[:id])
16
+ render json: organization_blueprints.find(params[:id]).to_json(except: :image)
17
17
  end
18
18
 
19
19
  def create
@@ -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
- mount_uploader :image, Decidim::NavigationMaps::BlueprintUploader
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,4 @@
1
+ import "src/decidim/navigation_maps/admin/navigation_maps.js"
2
+
3
+ // CSS
4
+ import "entrypoints/decidim_admin_navigation_maps.scss";
@@ -0,0 +1 @@
1
+ @import "stylesheets/decidim/navigation_maps/admin/navigation_maps";
@@ -0,0 +1,7 @@
1
+ import "src/decidim/navigation_maps/navigation_maps.js"
2
+
3
+ // Images
4
+ require.context("../images", true)
5
+
6
+ // CSS
7
+ import "entrypoints/decidim_navigation_maps.scss";
@@ -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
+