decidim-navigation_maps 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +144 -0
- data/Rakefile +40 -0
- data/app/assets/config/admin/decidim_navigation_maps_manifest.css +3 -0
- data/app/assets/config/admin/decidim_navigation_maps_manifest.js +3 -0
- data/app/assets/config/decidim_navigation_maps_manifest.css +3 -0
- data/app/assets/config/decidim_navigation_maps_manifest.js +1 -0
- data/app/assets/images/decidim/navigation_maps/icon.svg +1 -0
- data/app/assets/javascripts/decidim/navigation_maps/admin/map_editor.js +88 -0
- data/app/assets/javascripts/decidim/navigation_maps/admin/navigation_maps.js +143 -0
- data/app/assets/javascripts/decidim/navigation_maps/map_view.js +123 -0
- data/app/assets/javascripts/decidim/navigation_maps/navigation_maps.js +44 -0
- data/app/assets/stylesheets/decidim/navigation_maps/_variables.scss +3 -0
- data/app/assets/stylesheets/decidim/navigation_maps/admin/navigation_maps.scss +102 -0
- data/app/assets/stylesheets/decidim/navigation_maps/navigation_maps.scss +58 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_styles.erb +18 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_tabs.erb +5 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_tabs_content.erb +8 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/_template.erb +13 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map/show.erb +21 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_cell.rb +22 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_form.erb +36 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_modal.erb +12 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_tabs.erb +6 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/_tabs_content.erb +11 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form/show.erb +35 -0
- data/app/cells/decidim/navigation_maps/content_blocks/navigation_map_settings_form_cell.rb +32 -0
- data/app/commands/decidim/navigation_maps/save_area.rb +58 -0
- data/app/commands/decidim/navigation_maps/save_blueprints.rb +72 -0
- data/app/controllers/decidim/navigation_maps/admin/application_controller.rb +13 -0
- data/app/controllers/decidim/navigation_maps/admin/areas_controller.rb +94 -0
- data/app/controllers/decidim/navigation_maps/admin/blueprints_controller.rb +64 -0
- data/app/forms/decidim/navigation_maps/area_form.rb +37 -0
- data/app/forms/decidim/navigation_maps/blueprint_form.rb +39 -0
- data/app/forms/decidim/navigation_maps/blueprint_forms.rb +9 -0
- data/app/models/decidim/navigation_maps/application_record.rb +10 -0
- data/app/models/decidim/navigation_maps/blueprint.rb +27 -0
- data/app/models/decidim/navigation_maps/blueprint_area.rb +32 -0
- data/app/queries/decidim/navigation_maps/organization_blueprints.rb +20 -0
- data/app/uploaders/decidim/navigation_maps/blueprint_uploader.rb +22 -0
- data/app/views/decidim/navigation_maps/admin/areas/_form.html.erb +39 -0
- data/app/views/decidim/navigation_maps/admin/areas/new.html.erb +17 -0
- data/app/views/decidim/navigation_maps/admin/areas/show.html.erb +14 -0
- data/config/i18n-tasks.yml +10 -0
- data/config/locales/ca.yml +45 -0
- data/config/locales/cs.yml +45 -0
- data/config/locales/en.yml +46 -0
- data/config/locales/es.yml +45 -0
- data/db/migrate/20191022092624_create_decidim_navigation_maps_blueprints.rb +13 -0
- data/db/migrate/20191120185739_add_title_to_navigation_maps_blueprints.rb +10 -0
- data/db/migrate/20191125142751_create_decidim_navigation_maps_blueprint_areas.rb +18 -0
- data/db/migrate/20191126045831_add_link_type_to_decidim_navigation_maps_blueprint_areas.rb +8 -0
- data/db/migrate/20191126154019_add_area_id_to_decidim_navigation_maps_blueprint_areas.rb +16 -0
- data/db/migrate/20191127093746_add_color_to_navigation_maps_blueprint_areas.rb +7 -0
- data/lib/decidim/navigation_maps.rb +13 -0
- data/lib/decidim/navigation_maps/admin.rb +10 -0
- data/lib/decidim/navigation_maps/admin_engine.rb +34 -0
- data/lib/decidim/navigation_maps/engine.rb +34 -0
- data/lib/decidim/navigation_maps/navigation_map_cell_helpers.rb +28 -0
- data/lib/decidim/navigation_maps/test/factories.rb +29 -0
- data/lib/decidim/navigation_maps/version.rb +9 -0
- data/vendor/assets/images/draw/layers-2x.png +0 -0
- data/vendor/assets/images/draw/layers.png +0 -0
- data/vendor/assets/images/draw/marker-icon-2x.png +0 -0
- data/vendor/assets/images/draw/marker-icon.png +0 -0
- data/vendor/assets/images/draw/marker-shadow.png +0 -0
- data/vendor/assets/images/draw/spritesheet-2x.png +0 -0
- data/vendor/assets/images/draw/spritesheet.png +0 -0
- data/vendor/assets/images/draw/spritesheet.svg +156 -0
- data/vendor/assets/images/images/layers-2x.png +0 -0
- data/vendor/assets/images/images/layers.png +0 -0
- data/vendor/assets/images/images/marker-icon-2x.png +0 -0
- data/vendor/assets/images/images/marker-icon.png +0 -0
- data/vendor/assets/images/images/marker-shadow.png +0 -0
- data/vendor/assets/javascripts/jquery.form.js +1277 -0
- data/vendor/assets/javascripts/jsrender.min.js +4 -0
- data/vendor/assets/javascripts/jsrender.min.js.map +1 -0
- data/vendor/assets/javascripts/leaflet-geoman.min.js +1 -0
- data/vendor/assets/javascripts/leaflet.js +5 -0
- data/vendor/assets/stylesheets/leaflet-geoman.css +164 -0
- metadata +183 -0
data/README.md
ADDED
@@ -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)
|
data/Rakefile
ADDED
@@ -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 @@
|
|
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
|
+
};
|