decidim-navigation_maps 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +144 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/config/admin/decidim_navigation_maps_manifest.css +3 -0
  6. data/app/assets/config/admin/decidim_navigation_maps_manifest.js +3 -0
  7. data/app/assets/config/decidim_navigation_maps_manifest.css +3 -0
  8. data/app/assets/config/decidim_navigation_maps_manifest.js +1 -0
  9. data/app/assets/images/decidim/navigation_maps/icon.svg +1 -0
  10. data/app/assets/javascripts/decidim/navigation_maps/admin/map_editor.js +88 -0
  11. data/app/assets/javascripts/decidim/navigation_maps/admin/navigation_maps.js +143 -0
  12. data/app/assets/javascripts/decidim/navigation_maps/map_view.js +123 -0
  13. data/app/assets/javascripts/decidim/navigation_maps/navigation_maps.js +44 -0
  14. data/app/assets/stylesheets/decidim/navigation_maps/_variables.scss +3 -0
  15. data/app/assets/stylesheets/decidim/navigation_maps/admin/navigation_maps.scss +102 -0
  16. data/app/assets/stylesheets/decidim/navigation_maps/navigation_maps.scss +58 -0
  17. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_styles.erb +18 -0
  18. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_tabs.erb +5 -0
  19. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_tabs_content.erb +8 -0
  20. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_template.erb +13 -0
  21. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/show.erb +21 -0
  22. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_cell.rb +22 -0
  23. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_form.erb +36 -0
  24. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_modal.erb +12 -0
  25. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_tabs.erb +6 -0
  26. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_tabs_content.erb +11 -0
  27. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/show.erb +35 -0
  28. data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form_cell.rb +32 -0
  29. data/app/commands/decidim/navigation_maps/save_area.rb +58 -0
  30. data/app/commands/decidim/navigation_maps/save_blueprints.rb +72 -0
  31. data/app/controllers/decidim/navigation_maps/admin/application_controller.rb +13 -0
  32. data/app/controllers/decidim/navigation_maps/admin/areas_controller.rb +94 -0
  33. data/app/controllers/decidim/navigation_maps/admin/blueprints_controller.rb +64 -0
  34. data/app/forms/decidim/navigation_maps/area_form.rb +37 -0
  35. data/app/forms/decidim/navigation_maps/blueprint_form.rb +39 -0
  36. data/app/forms/decidim/navigation_maps/blueprint_forms.rb +9 -0
  37. data/app/models/decidim/navigation_maps/application_record.rb +10 -0
  38. data/app/models/decidim/navigation_maps/blueprint.rb +27 -0
  39. data/app/models/decidim/navigation_maps/blueprint_area.rb +32 -0
  40. data/app/queries/decidim/navigation_maps/organization_blueprints.rb +20 -0
  41. data/app/uploaders/decidim/navigation_maps/blueprint_uploader.rb +22 -0
  42. data/app/views/decidim/navigation_maps/admin/areas/_form.html.erb +39 -0
  43. data/app/views/decidim/navigation_maps/admin/areas/new.html.erb +17 -0
  44. data/app/views/decidim/navigation_maps/admin/areas/show.html.erb +14 -0
  45. data/config/i18n-tasks.yml +10 -0
  46. data/config/locales/ca.yml +45 -0
  47. data/config/locales/cs.yml +45 -0
  48. data/config/locales/en.yml +46 -0
  49. data/config/locales/es.yml +45 -0
  50. data/db/migrate/20191022092624_create_decidim_navigation_maps_blueprints.rb +13 -0
  51. data/db/migrate/20191120185739_add_title_to_navigation_maps_blueprints.rb +10 -0
  52. data/db/migrate/20191125142751_create_decidim_navigation_maps_blueprint_areas.rb +18 -0
  53. data/db/migrate/20191126045831_add_link_type_to_decidim_navigation_maps_blueprint_areas.rb +8 -0
  54. data/db/migrate/20191126154019_add_area_id_to_decidim_navigation_maps_blueprint_areas.rb +16 -0
  55. data/db/migrate/20191127093746_add_color_to_navigation_maps_blueprint_areas.rb +7 -0
  56. data/lib/decidim/navigation_maps.rb +13 -0
  57. data/lib/decidim/navigation_maps/admin.rb +10 -0
  58. data/lib/decidim/navigation_maps/admin_engine.rb +34 -0
  59. data/lib/decidim/navigation_maps/engine.rb +34 -0
  60. data/lib/decidim/navigation_maps/navigation_map_cell_helpers.rb +28 -0
  61. data/lib/decidim/navigation_maps/test/factories.rb +29 -0
  62. data/lib/decidim/navigation_maps/version.rb +9 -0
  63. data/vendor/assets/images/draw/layers-2x.png +0 -0
  64. data/vendor/assets/images/draw/layers.png +0 -0
  65. data/vendor/assets/images/draw/marker-icon-2x.png +0 -0
  66. data/vendor/assets/images/draw/marker-icon.png +0 -0
  67. data/vendor/assets/images/draw/marker-shadow.png +0 -0
  68. data/vendor/assets/images/draw/spritesheet-2x.png +0 -0
  69. data/vendor/assets/images/draw/spritesheet.png +0 -0
  70. data/vendor/assets/images/draw/spritesheet.svg +156 -0
  71. data/vendor/assets/images/images/layers-2x.png +0 -0
  72. data/vendor/assets/images/images/layers.png +0 -0
  73. data/vendor/assets/images/images/marker-icon-2x.png +0 -0
  74. data/vendor/assets/images/images/marker-icon.png +0 -0
  75. data/vendor/assets/images/images/marker-shadow.png +0 -0
  76. data/vendor/assets/javascripts/jquery.form.js +1277 -0
  77. data/vendor/assets/javascripts/jsrender.min.js +4 -0
  78. data/vendor/assets/javascripts/jsrender.min.js.map +1 -0
  79. data/vendor/assets/javascripts/leaflet-geoman.min.js +1 -0
  80. data/vendor/assets/javascripts/leaflet.js +5 -0
  81. data/vendor/assets/stylesheets/leaflet-geoman.css +164 -0
  82. metadata +183 -0
@@ -0,0 +1,144 @@
1
+ # Decidim::NavigationMaps
2
+
3
+ ![Test](https://github.com/Platoniq/decidim-module-navigation_maps/workflows/Test/badge.svg)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/f69b2b0ab0ffcd26f002/maintainability)](https://codeclimate.com/github/Platoniq/decidim-module-navigation_maps/maintainability)
5
+ [![Codecov](https://codecov.io/gh/Platoniq/decidim-module-navigation_maps/branch/master/graph/badge.svg?token=XhzWO0IiWt)](https://codecov.io/gh/Platoniq/decidim-module-navigation_maps)
6
+
7
+ Allows to map processes to image parts using maps.
8
+
9
+ > NOTE: This module is ready to use but in Beta status. Feel free to report any bug!
10
+
11
+ ## Usage
12
+
13
+ NavigationMaps is available as a Content Block widget (currently for the
14
+ homepage only).
15
+
16
+ 👉 [Check the usage guide here!](USAGE.md)
17
+
18
+ ![Admin editor](examples/admin.gif)
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem "decidim-navigation_maps", "~> 1.0.0"
26
+ ```
27
+
28
+ And then execute:
29
+
30
+ ```bash
31
+ bundle
32
+ bundle exec rails decidim_navigation_maps:install:migrations
33
+ bundle exec rails db:migrate
34
+ ```
35
+
36
+ Depending on your Decidim version, choose the corresponding Plugin version to ensure compatibility:
37
+
38
+ | Navigation Maps version | Compatible Decidim versions |
39
+ |---|---|
40
+ | 1.0.x | 0.18.x, 0.21.x |
41
+
42
+ ## Contributing
43
+
44
+ See [Decidim](https://github.com/decidim/decidim).
45
+
46
+ ### Developing
47
+
48
+ To start contributing to this project, first:
49
+
50
+ - Install the basic dependencies (such as Ruby and PostgreSQL)
51
+ - Clone this repository
52
+
53
+ Decidim's main repository also provides a Docker configuration file if you
54
+ prefer to use Docker instead of installing the dependencies locally on your
55
+ machine.
56
+
57
+ You can create the development app by running the following commands after
58
+ cloning this project:
59
+
60
+ ```bash
61
+ bundle
62
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake development_app
63
+ ```
64
+
65
+ Note that the database user has to have rights to create and drop a database in
66
+ order to create the dummy test app database.
67
+
68
+ Then to test how the module works in Decidim, start the development server:
69
+
70
+ ```bash
71
+ cd development_app
72
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rails s
73
+ ```
74
+
75
+ In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
76
+ [rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
77
+ can add the environment variables to the root directory of the project in a file
78
+ named `.rbenv-vars`. If these are defined for the environment, you can omit
79
+ defining these in the commands shown above.
80
+
81
+ #### Code Styling
82
+
83
+ Please follow the code styling defined by the different linters that ensure we
84
+ are all talking with the same language collaborating on the same project. This
85
+ project is set to follow the same rules that Decidim itself follows.
86
+
87
+ [Rubocop](https://rubocop.readthedocs.io/) linter is used for the Ruby language.
88
+
89
+ You can run the code styling checks by running the following commands from the
90
+ console:
91
+
92
+ ```
93
+ bundle exec rubocop
94
+ ```
95
+
96
+ To ease up following the style guide, you should install the plugin to your
97
+ favorite editor, such as:
98
+
99
+ - Atom - [linter-rubocop](https://atom.io/packages/linter-rubocop)
100
+ - Sublime Text - [Sublime RuboCop](https://github.com/pderichs/sublime_rubocop)
101
+ - Visual Studio Code - [Rubocop for Visual Studio Code](https://github.com/misogi/vscode-ruby-rubocop)
102
+
103
+ ### Testing
104
+
105
+ To run the tests run the following in the gem development path:
106
+
107
+ ```bash
108
+ bundle
109
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake test_app
110
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rspec
111
+ ```
112
+
113
+ Note that the database user has to have rights to create and drop a database in
114
+ order to create the dummy test app database.
115
+
116
+ In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
117
+ [rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
118
+ can add these environment variables to the root directory of the project in a
119
+ file named `.rbenv-vars`. In this case, you can omit defining these in the
120
+ commands shown above.
121
+
122
+ ### Test code coverage
123
+
124
+ If you want to generate the code coverage report for the tests, you can use
125
+ the `SIMPLECOV=1` environment variable in the rspec command as follows:
126
+
127
+ ```bash
128
+ SIMPLECOV=1 bundle exec rspec
129
+ ```
130
+
131
+ This will generate a folder named `coverage` in the project root which contains
132
+ the code coverage report.
133
+
134
+ ## License
135
+
136
+ This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
137
+
138
+ ## Credits
139
+
140
+ This plugin has been developed by ![Platoniq](examples/platoniq-logo.png)
141
+
142
+ > Amb el suport de l'Ajuntament de Barcelona - Direcció de Serveis d'Innovació Democràtica
143
+ >
144
+ > ![Logo Barcelona](examples/bcn-logo.png)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
4
+
5
+ def install_module(path)
6
+ Dir.chdir(path) do
7
+ system("bundle exec rake decidim_navigation_maps:install:migrations")
8
+ system("bundle exec rake db:migrate")
9
+ end
10
+ end
11
+
12
+ def seed_db(path)
13
+ Dir.chdir(path) do
14
+ system("bundle exec rake db:seed")
15
+ end
16
+ end
17
+
18
+ desc "Generates a dummy app for testing"
19
+ task test_app: "decidim:generate_external_test_app" do
20
+ ENV["RAILS_ENV"] = "test"
21
+ install_module("spec/decidim_dummy_app")
22
+ end
23
+
24
+ desc "Generates a development app"
25
+ task :development_app do
26
+ Bundler.with_original_env do
27
+ generate_decidim_app(
28
+ "development_app",
29
+ "--app_name",
30
+ "#{base_app_name}_development_app",
31
+ "--path",
32
+ "..",
33
+ "--recreate_db",
34
+ "--demo"
35
+ )
36
+ end
37
+
38
+ install_module("development_app")
39
+ seed_db("development_app")
40
+ end
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= link decidim/navigation_maps/admin/navigation_maps.css
3
+ */
@@ -0,0 +1,3 @@
1
+ //= link decidim/navigation_maps/admin/navigation_maps.js
2
+ //= require jquery.form
3
+ //= require leaflet
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= link decidim/navigation_maps/navigation_maps.css
3
+ */
@@ -0,0 +1 @@
1
+ //= link decidim/navigation_maps/navigation_maps.js
@@ -0,0 +1 @@
1
+ <svg height="35px" width="35px" fill="#000000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 1 511 511" style="enable-background:new 0 1 511 511;" xml:space="preserve"><g><path d="M205.6,146.9c-22.2,0-40.2,18-40.2,40.2c0,22.2,18,40.2,40.2,40.2c22.2,0,40.2-18,40.2-40.2 C245.9,165,227.8,146.9,205.6,146.9z M205.6,206.6c-10.7,0-19.3-8.7-19.3-19.3c0-10.7,8.7-19.3,19.3-19.3 c10.6,0,19.3,8.7,19.3,19.3C225,197.9,216.3,206.6,205.6,206.6z"/><path d="M406.6,178V70.3c0-5.8-4.2-10.1-10-10.1H10.6C4.8,60.3,0,64.6,0,70.3v304.9c0,5.8,4.8,10.9,10.6,10.9h242 c24.5,39.8,68.7,66.7,119.1,66.7c77,0,139.4-62.8,139.4-139.7C511,248.4,467.4,193.7,406.6,178z M21,365.2v-284h364.7v92.9 c-4.2-0.5-9.1-0.7-14-0.7c-0.3,0-0.6,0-0.6,0v-66.4c0-5.8-5-10-10.9-10H47.2c-5.8,0-10.5,4.2-10.5,10v231.8 c0,5.8,4.7,10.8,10.5,10.8h189.7c1.5,5.2,3.1,10.5,5.2,15.7H21z M232.9,328.6H57.6v-40.4l61.5-54.3c2.8-2.5,7-2.6,10-0.2l63.3,50.6 c10.7,8.6,26,8.4,36.5-0.5l7.6-6.5c-3,11.4-4.6,23.6-4.6,35.8C232,318.3,232.3,323.3,232.9,328.6z M215.7,267.8 c-2.8,2.4-7,2.4-10,0.1l-63.4-50.6c-10.9-8.7-26.5-8.4-37,0.9l-47.7,42V117.9H350v57.2c-37.7,6-70.1,26.8-91.4,56.4L215.7,267.8z M371.6,431.7C306.2,431.7,253,378.4,253,313s53.2-118.6,118.6-118.6c65.4,0,118.6,53.2,118.6,118.6 C490.4,378.4,437.1,431.7,371.6,431.7z"/><path d="M435.4,234c-34.8-34.6-91-34.6-125.6,0c-13.7,13.7-22.4,31.2-25,50.4c-2.5,18.5,0.9,37.8,9.9,54.4c0,0,0,0.1,0.1,0.1 c4.4,8,9.4,14.7,15.2,20.4l55.1,55.1c2,2,4.6,3,7.4,3s5.5-1.2,7.4-3l55.1-55.1c16.9-16.9,26.2-39.2,26.2-62.8 C461.4,273,452.2,250.7,435.4,234z M420.1,344.6l-47.7,47.7l-47.7-47.7c-4.4-4.4-8.2-9.5-11.6-15.7c-14.2-26.6-9.6-58.8,11.6-80.1 c26.4-26.4,69.4-26.4,95.8,0c12.8,12.8,19.8,29.8,19.7,47.7C440.2,314.6,433,331.7,420.1,344.6z"/><path d="M372.3,241.7c-29,0-52.7,23.7-52.7,52.7c0,29,23.7,52.7,52.7,52.7s52.7-23.7,52.7-52.7 C425.1,265.4,401.5,241.7,372.3,241.7z M372.3,326c-17.5,0-31.8-14.2-31.8-31.8c0-17.5,14.3-31.8,31.8-31.8 c17.5,0,31.8,14.3,31.8,31.8C404.1,311.8,389.9,326,372.3,326z"/></g></svg>
@@ -0,0 +1,88 @@
1
+ // Creates a map
2
+ //= require decidim/navigation_maps/map_view
3
+
4
+ function NavigationMapEditor(map_object, table_object) {
5
+ var self = this;
6
+ // Call constructor of superclass to initialize superclass-derived members.
7
+ NavigationMapView.call(self, map_object, function() {
8
+ self.createControls();
9
+ if(self.blueprint) {
10
+ self.createAreas();
11
+ }
12
+ });
13
+ self.table_object = table_object;
14
+ this.createAreaCallback = function () {};
15
+ this.editAreaCallback = function () {};
16
+ this.removeAreaCallback = function () {};
17
+ }
18
+
19
+ // NavigationMapEditor derives from NavigationMapView
20
+ NavigationMapEditor.prototype = Object.create(NavigationMapView.prototype);
21
+ NavigationMapEditor.prototype.constructor = NavigationMapEditor;
22
+
23
+ NavigationMapEditor.prototype.createControls = function() {
24
+ var self = this;
25
+ self.map.pm.addControls({
26
+ position: 'topleft',
27
+ drawCircle: false,
28
+ drawMarker: false,
29
+ drawCircleMarker: false,
30
+ drawPolyline: false,
31
+ cutPolygon: false
32
+ });
33
+
34
+ self.map.on('pm:create', function(e) {
35
+ var geojson = e.layer.toGeoJSON();
36
+ self.blueprint[e.layer._leaflet_id] = geojson;
37
+ self.attachEditorEvents(e.layer);
38
+ self.createAreaCallback(e.layer._leaflet_id, e.layer, self);
39
+ });
40
+
41
+ self.map.on('pm:remove', function(e) {
42
+ delete self.blueprint[e.layer._leaflet_id];
43
+ self.removeAreaCallback(e.layer._leaflet_id, e.layer, self);
44
+ });
45
+ };
46
+
47
+ NavigationMapEditor.prototype.editing = function() {
48
+ var pm = this.map.pm;
49
+ return pm.globalRemovalEnabled() || pm.globalDragModeEnabled() || pm.globalEditEnabled();
50
+ };
51
+
52
+ // register callback to handle area edits,removals and creations
53
+ NavigationMapView.prototype.onCreateArea = function(callback) {
54
+ this.createAreaCallback = callback;
55
+ };
56
+ NavigationMapView.prototype.onEditArea = function(callback) {
57
+ this.editAreaCallback = callback;
58
+ };
59
+ NavigationMapView.prototype.onRemoveArea = function(callback) {
60
+ this.removeCreateCallback = callback;
61
+ };
62
+
63
+ NavigationMapEditor.prototype.attachEditorEvents = function (layer) {
64
+ var self = this;
65
+
66
+ layer.on('mouseover', function(e) {
67
+ e.target.getElement().classList.add('selected')
68
+ });
69
+
70
+ layer.on('mouseout', function(e) {
71
+ e.target.getElement().classList.remove('selected')
72
+ });
73
+
74
+ layer.on('pm:edit', function(e) {
75
+ self.blueprint[e.target._leaflet_id] = e.target.toGeoJSON();
76
+ self.editAreaCallback(e.target._leaflet_id, e.target, self);
77
+ });
78
+
79
+ layer.on('click', function(e) {
80
+ if(!self.editing()) {
81
+ self.clickAreaCallback(e.target._leaflet_id, e.target, self);
82
+ }
83
+ });
84
+ };
85
+
86
+ NavigationMapEditor.prototype.getBlueprint = function () {
87
+ return this.blueprint;
88
+ };
@@ -0,0 +1,143 @@
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
+ //= require jquery.form
4
+ //= require decidim/navigation_maps/admin/map_editor
5
+ //= require_self
6
+
7
+ $(function() {
8
+
9
+ var $maps = $('.navigation_maps.admin .map');
10
+ var $progress = $('.navigation_maps.admin .progress');
11
+ var $bar = $('.navigation_maps.admin .progress-meter');
12
+ var $loading = $('.navigation_maps.admin .loading');
13
+ var $callout = $('.navigation_maps.admin .callout');
14
+ var $modal = $('#mapEditModal');
15
+ var $form = $('form');
16
+ var $tabs = $('#navigation_maps-tabs');
17
+ var $accordion = $('.navigation_maps.admin .accordion');
18
+ var editors = {};
19
+ var new_areas = {};
20
+
21
+ $maps.each(function() {
22
+ var id = $(this).data('id');
23
+ var table = document.getElementById("navigation_maps-table-" + id);
24
+ editors[id] = new NavigationMapEditor(this, table);
25
+ editors[id].onCreateArea(function(area_id) {
26
+ new_areas[area_id] = true;
27
+ });
28
+
29
+ editors[id].onClickArea(function(area_id, area) {
30
+ $modal.find('.modal-content').html('');
31
+ $modal.addClass('loading').foundation('open');
32
+ $callout.hide();
33
+ $callout.removeClass('alert success');
34
+ // "new" form insted of editing
35
+ var rel = new_areas[area_id] ? 'new' : area_id;
36
+ $modal.find('.modal-content').load(`/admin/navigation_maps/blueprints/${id}/areas/${rel}`, function() {
37
+ var $input1 = $modal.find('input[name="blueprint_area[area_id]"]');
38
+ var $input2 = $modal.find('input[name="blueprint_area[area_type]"]');
39
+ var $input3 = $modal.find('input[name="blueprint_area[area]"]');
40
+ var a = area.toGeoJSON();
41
+ $modal.removeClass('loading');
42
+ if($input1.length) $input1.val(area_id);
43
+ if($input2.length) $input2.val(a.type);
44
+ if($input3.length) $input3.val(JSON.stringify(a));
45
+ $modal.find('ul[data-tabs=true]').each(function() {
46
+ new Foundation.Tabs($(this));
47
+ });
48
+ });
49
+ });
50
+ });
51
+
52
+ // Rails AJAX events
53
+ document.body.addEventListener('ajax:error', function(responseText) {
54
+ $callout.contents('p').html(responseText.detail[0].message + ": <strong>" + responseText.detail[0].error + "</strong>");
55
+ $callout.addClass('alert');
56
+ });
57
+
58
+ document.body.addEventListener('ajax:success', function(responseText) {
59
+ if(new_areas[responseText.detail[0].area]) {
60
+ delete new_areas[responseText.detail[0].area]
61
+ }
62
+ var blueprint_id = responseText.detail[0].blueprint_id;
63
+ var area_id = responseText.detail[0].area_id;
64
+ var area = responseText.detail[0].area;
65
+ editors[blueprint_id].setLayerProperties(editors[blueprint_id].map._layers[area_id], area);
66
+ editors[blueprint_id].blueprint[area_id] = area;
67
+ $callout.contents('p').html(responseText.detail[0].message);
68
+ $callout.addClass('success');
69
+ });
70
+
71
+ document.body.addEventListener('ajax:complete', function() {
72
+ $callout.show();
73
+ $modal.foundation('close');
74
+ })
75
+
76
+ $tabs.on('change.zf.tabs', function(e, $tab, $content) {
77
+ var id = $content.find('.map').data('id');
78
+ if(id) {
79
+ editors[id].reload();
80
+ }
81
+ });
82
+
83
+ $accordion.on('down.zf.accordion', function(e, $accordion) {
84
+ var id = $accordion.find('.map').data('id');
85
+ if(id) {
86
+ editors[id].reload();
87
+ }
88
+ });
89
+
90
+ // If a new item si going to be created o the image is changed a reload is needed
91
+ var needsReload = function() {
92
+ var reload = false;
93
+ if($form.find('#map-new input:checked').length) return true;
94
+ if($form.find('.delete-tab input[type=checkbox]:checked').length) return true;
95
+
96
+ $form.find('input[type=file],input[tabs_id=blueprints___title]').each(function() {
97
+ if($(this).val()) {
98
+ reload = true;
99
+ return false;
100
+ }
101
+ });
102
+ return reload;
103
+ };
104
+
105
+ $form.ajaxForm({
106
+ url: $form.find('[name=action]').val(),
107
+ beforeSerialize: function() {
108
+ Object.keys(editors).forEach(function(key) {
109
+ var editor = editors[key];
110
+ $(`#blueprints_${editor.id}_blueprint`).val(JSON.stringify(editor.getBlueprint()));
111
+ });
112
+ },
113
+ beforeSend: function() {
114
+ var percentVal = '0%';
115
+ $bar.width(percentVal).html(percentVal);
116
+ $progress.show();
117
+ $callout.hide();
118
+ $callout.removeClass('alert success');
119
+ $loading.show();
120
+ },
121
+ uploadProgress: function(event, position, total, percentComplete) {
122
+ var percentVal = percentComplete + '%';
123
+ $bar.width(percentVal).html(percentVal);
124
+ },
125
+ success: function(responseText) {
126
+ $callout.show();
127
+ $progress.hide();
128
+ $callout.contents('p').html(responseText);
129
+ $callout.addClass('success');
130
+ $loading.hide();
131
+ if(needsReload()) {
132
+ $loading.show();
133
+ location.reload();
134
+ }
135
+ },
136
+ error: function(xhr) {
137
+ $loading.hide();
138
+ $callout.show();
139
+ $callout.contents('p').html(xhr.responseText);
140
+ $callout.addClass('alert');
141
+ }
142
+ });
143
+ });
@@ -0,0 +1,123 @@
1
+ // Creates a map view
2
+ //= require leaflet
3
+ //= require leaflet-geoman.min
4
+
5
+ function NavigationMapView(map_object, callback) {
6
+ var self = this;
7
+ self.features = {};
8
+ self.map_object = map_object;
9
+ self.id = map_object.dataset.id;
10
+ self.image_path = map_object.dataset.image;
11
+ self.blueprint = map_object.dataset.blueprint ? JSON.parse(map_object.dataset.blueprint) : {};
12
+ self.image = new Image();
13
+ self.image.onload = function() {
14
+ self.createMap();
15
+ if(typeof callback === "function") {
16
+ callback(self);
17
+ } else {
18
+ if(self.blueprint) {
19
+ self.createAreas();
20
+ }
21
+ }
22
+ };
23
+ self.image.src = self.image_path;
24
+ this.clickAreaCallback = function () {};
25
+ this.setLayerPropertiesCallback = function () {};
26
+ }
27
+
28
+ NavigationMapView.prototype.createMap = function() {
29
+ var bounds = [[0,0], [this.image.height,this.image.width]];
30
+
31
+ this.map = L.map(this.map_object, {
32
+ minZoom: -1,
33
+ maxZoom: 2,
34
+ crs: L.CRS.Simple,
35
+ noWrap: true,
36
+ zoomSnap: 0,
37
+ // zoomDelta: 0.1,
38
+ maxBounds: [[0,0], [this.image.height,this.image.width]],
39
+ center: [this.image.height/2, this.image.width/2],
40
+ zoom: -1,
41
+ scrollWheelZoom: false
42
+ });
43
+
44
+ L.imageOverlay(this.image.src, bounds).addTo(this.map);
45
+ this.fitBounds();
46
+ };
47
+
48
+ NavigationMapView.prototype.fitBounds = function() {
49
+ var image_ratio = this.image.height / this.image.width;
50
+ var map_ratio = this.map_object.offsetHeight / this.map_object.offsetWidth;
51
+
52
+ if(image_ratio > map_ratio) {
53
+ this.map.fitBounds([[0,0], [0,this.image.width]]);
54
+ }
55
+ else {
56
+ this.map.fitBounds([[0,0], [this.image.height,0]]);
57
+ }
58
+ this.map.setView([this.image.height/2, this.image.width/2]);
59
+ };
60
+
61
+ NavigationMapView.prototype.createAreas = function() {
62
+ var self = this;
63
+ self.forEachBlueprint(function(id, geoarea) {
64
+ new L.GeoJSON(geoarea, {
65
+ onEachFeature: function(feature, layer) {
66
+ layer._leaflet_id = id;
67
+ self.setLayerProperties(layer, geoarea);
68
+ self.attachEditorEvents(layer);
69
+ }
70
+ }).addTo(self.map);
71
+ });
72
+ };
73
+
74
+ NavigationMapView.prototype.setLayerProperties = function (layer, area) {
75
+ var props = area.properties;
76
+ if(props) {
77
+ if(props.color) {
78
+ layer.setStyle({fillColor: props.color, color: props.color});
79
+ }
80
+ this.setLayerPropertiesCallback(layer, props);
81
+ }
82
+ };
83
+
84
+ NavigationMapView.prototype.attachEditorEvents = function (layer) {
85
+ var self = this;
86
+
87
+ layer.on('mouseover', function(e) {
88
+ e.target.getElement().classList.add('selected')
89
+ });
90
+
91
+ layer.on('mouseout', function(e) {
92
+ e.target.getElement().classList.remove('selected')
93
+ });
94
+
95
+ layer.on('click', function(e) {
96
+ self.clickAreaCallback(e.target, self);
97
+ });
98
+ };
99
+
100
+ // register callback to handle area clicks
101
+ NavigationMapView.prototype.onClickArea = function(callback) {
102
+ this.clickAreaCallback = callback;
103
+ };
104
+
105
+ NavigationMapView.prototype.onSetLayerProperties = function(callback) {
106
+ this.setLayerPropertiesCallback = callback;
107
+ };
108
+
109
+ NavigationMapView.prototype.forEachBlueprint = function (callback) {
110
+ for (var id in this.blueprint) {
111
+ var geoarea = this.blueprint[id];
112
+ // avoid non-polygons for the moment
113
+ if(!geoarea.geometry || geoarea.geometry.type !== 'Polygon') continue;
114
+ callback(id, geoarea);
115
+ }
116
+ };
117
+
118
+ NavigationMapView.prototype.reload = function () {
119
+ if(this.map) {
120
+ this.map.invalidateSize(true);
121
+ this.fitBounds();
122
+ }
123
+ };