c80_push 0.1.0.1 → 0.1.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc71bf6b52804cacd8264f3b6c11f871a0a98941
4
- data.tar.gz: fda41529b939dfb82b720d781a5e809fd346a96b
3
+ metadata.gz: b4d991e9e1a4d40ab4a2788f801fc5bda42e61d2
4
+ data.tar.gz: 37d7c1a99822e278f8b2b4db16255fdd29a187a8
5
5
  SHA512:
6
- metadata.gz: 1aaf65ac0642e9df24e8b7741e6f8a0f33d1d0d5c2c1ab7e9039f2af2ee132aeb546989ca1e20c6480d9323dfa171d02f7d0e260193e50b361dce565fe9adae5
7
- data.tar.gz: d968c22cf4ee2de729b71fa4caf2befb8685e2b536578dfb3bdd16aa18ff4d11446398caa769f1882423a07f83ef3ce494e68f885ba7bdbe64ed57cce9a2fae7
6
+ metadata.gz: c88589031569da99e0158285b792473c6b0c1a580106b6830ad1ffaee861546c219a760983054d5d126da6acf185fb4bdfb8060ad8c2a6eceb171381de09d5f1
7
+ data.tar.gz: 9a7b1e94d5105aed752b535222df57341519ae0e7fde738650edda28ccc362185b010eea44616551fbc6b039440b050f3d2bffdb2a59b05609be3d9bd67f595c
data/README.md CHANGED
@@ -56,15 +56,49 @@ Add these lines to host app's `active_admin.js.coffee`:
56
56
  Add these lines to host app's 'application.js.coffee':
57
57
 
58
58
  ```js
59
+ #= require bootstrap
60
+ #= require bootstrap-select
59
61
  #= require c80_push
60
62
  ```
61
63
 
62
64
  Add these lines to host app's 'application.scss':
63
65
 
64
66
  ```css
67
+ @import "bootstrap-sprockets";
68
+ @import "bootstrap";
69
+ @import "bootstrap-select";
65
70
  @include "c80_push";
66
71
  ```
67
72
 
73
+ ## Процесс разработки JS функционала
74
+
75
+ Теперь пора заняться js.
76
+
77
+ * [X] Прикрутить `selectpicker`: выводить туда только те регионы, в которых есть дилеры,
78
+ у которых есть офисы.
79
+
80
+ * [X] Вставить заголовок "Выберите Регион".
81
+
82
+ * [X] При первом входе на карту: должны отражаться все офисы.
83
+
84
+ - [X] Должен рассчитываться `bounding rectangle` и все точки должны быть видны
85
+ на рабочей области (никто не должен выходить за рамки)
86
+
87
+ * [ ] При наведении/клике на точку на карте:
88
+
89
+ - [X] должен появляться хинт с деталями офиса
90
+ - [ ] слева должен подсвечиваться соответствующий `.li_office`.
91
+
92
+ * [X] При наведении/клике на `.li_office` - должна подсвечиваться соответствующая
93
+ точка на карте.
94
+
95
+ * [ ] Вставить из `psd` синий маркер.
96
+
97
+ * [X] Когда меняется регион:
98
+
99
+ * [X] Должны отобразиться релевантные `.li_office`
100
+ * [X] Должны отобразиться релевантные точки на карте.
101
+
68
102
  ## Цитата из ТЗ
69
103
 
70
104
  > Данный раздел представляет собой список компаний, у которых указаны
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Сфокусироваться на точке на карте.
3
+ * Если надо - открыть balloon.
4
+ * @param id : id офиса.
5
+ */
6
+ function _item_toggle(id) {
7
+ //console.log('<_item_toggle> id: ' + id);
8
+
9
+ var it = dealers_map.geoObjects.getIterator(),
10
+ group;
11
+
12
+ while(group = it.getNext()) {
13
+ //console.log(group.properties);
14
+ if (group.properties !== undefined) {
15
+ for (var i = 0, len = group.getLength(); i < len; i++) {
16
+ var placemark = group.get(i);
17
+ //console.log(placemark.properties.get('id'));
18
+ if (placemark.properties.get('id') === id) {
19
+ //console.log('+ ' + placemark.balloon.isOpen());
20
+ if (placemark.balloon.isOpen()) {
21
+ placemark.balloon.close();
22
+ }
23
+ else {
24
+ dealers_map.panTo(placemark.geometry.getCoordinates(), {
25
+ delay: 0
26
+ }).then(function () {
27
+ placemark.balloon.open();
28
+ });
29
+ }
30
+ return;
31
+ }
32
+ }
33
+ break;
34
+ }
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Начинаем слушать клики по .li_office.
40
+ * При клике - вызовется _item_toggle.
41
+ */
42
+ function _dealers_left_list_clicks() {
43
+ $('.li_office').on("click", function (e) {
44
+ e.preventDefault();
45
+ var office_id = $(this).data('id');
46
+ _item_toggle(office_id);
47
+ });
48
+ }
49
+
50
+ $(document).ready(_dealers_left_list_clicks);
@@ -0,0 +1,14 @@
1
+ /**
2
+ * В списке дилеров слева от карты оставить только тех,
3
+ * кто принадлежит указанному региону.
4
+ *
5
+ * @param region_id
6
+ */
7
+ function dealers_left_list_filter(region_id) {
8
+ if (region_id === 'all') {
9
+ $('.li_region').css('display', 'block');
10
+ } else {
11
+ $('.li_region').css('display', 'none');
12
+ $('.li_region#region_' + region_id).css('display','block');
13
+ }
14
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ var dealers_map;
4
+
5
+ $(document).ready(function() {
6
+
7
+ if ($('#dealers_map_container').length) {
8
+ //noinspection JSUnresolvedVariable
9
+ ymaps.ready(function() {
10
+
11
+ //noinspection JSUnresolvedVariable,JSUnresolvedFunction
12
+ dealers_map = new ymaps.Map('dealers_map_container', {
13
+ center: [55, 37],
14
+ zoom: 10,
15
+ controls: ['zoomControl']
16
+ });
17
+
18
+ map_set_objects('all');
19
+
20
+ });
21
+ }
22
+
23
+ });
@@ -0,0 +1,26 @@
1
+ // нарисовать на карте объекты из указанного
2
+ // хэша offices[region_id]
3
+
4
+ function map_set_objects(region_id) {
5
+
6
+ var arr = offices[region_id];
7
+ // console.log(arr);
8
+ var n = arr['count'];
9
+
10
+ // соберём коллекцию точек
11
+ var c = new ymaps.GeoObjectCollection();
12
+ var icoords, iprops; // loop vars
13
+ for (var i = 0; i < n; i++) {
14
+ icoords = arr['coords'][i];
15
+ iprops = arr['props'][i];
16
+ c.add(new ymaps.Placemark(icoords, iprops));
17
+ }
18
+
19
+ // сначала уберём все точки
20
+ dealers_map.geoObjects.each(function(o) {
21
+ dealers_map.geoObjects.remove(o)
22
+ });
23
+
24
+ dealers_map.geoObjects.add(c);
25
+ dealers_map.setBounds(c.getBounds());
26
+ }
@@ -0,0 +1,20 @@
1
+ var $select_region;
2
+
3
+ /**
4
+ * Когда меняется регион:
5
+ * - Должны отобразиться релевантные `.li_office`
6
+ * - Должны отобразиться релевантные точки на карте.
7
+ */
8
+ var _select_region_on_change = function() {
9
+ var region_id = $(this).val();
10
+ // console.log('<_select_region_on_change> region_id = ' + region_id);
11
+ map_set_objects(region_id);
12
+ dealers_left_list_filter(region_id);
13
+ };
14
+
15
+ var select_region_init = function() {
16
+ //noinspection JSUnresolvedFunction
17
+ $select_region = $('#select_region').selectpicker();
18
+ $select_region.change(_select_region_on_change);
19
+ };
20
+ $(document).ready(select_region_init);
@@ -8,7 +8,12 @@ div.c80_push_page_dealers {
8
8
 
9
9
  div.select_region_row {
10
10
  height: 53px;
11
- margin-bottom: 25px;
11
+ margin-bottom: 15px;
12
+ padding: 9px;
13
+
14
+ div.select_wrapper {
15
+ float: right;
16
+ }
12
17
  }
13
18
 
14
19
  div.bottom_row {
@@ -5,9 +5,22 @@ div.c80_push_page_dealers {
5
5
 
6
6
  div.select_region_row {
7
7
  background-color: #E0001A;
8
+ div.select_wrapper {
9
+
10
+ }
8
11
  }
9
12
 
10
- div#dealers_map_container {
13
+ div.bottom_row {
14
+
15
+ > div {
16
+ }
17
+
18
+ div.dealers_list {
19
+ background-color: #f5f5f5;
20
+ }
21
+
22
+ div#dealers_map_container {
23
+ }
11
24
 
12
25
  }
13
26
 
@@ -2,6 +2,8 @@
2
2
  margin: 0;
3
3
  padding: 0;
4
4
  list-style: none;
5
+ border-top: 1px #B2B2B2 solid;
6
+ background-color: #ffffff;
5
7
 
6
8
  .li_region {
7
9
 
@@ -16,6 +18,8 @@
16
18
  padding: 0; //5px 5px 10px 15px;
17
19
  list-style: none;
18
20
  border: 1px #B2B2B2 solid;
21
+ border-bottom: none;
22
+ border-top: none;
19
23
 
20
24
  .li_dealer {
21
25
  padding: 15px;
@@ -74,6 +78,7 @@
74
78
 
75
79
  &:hover {
76
80
  border-bottom: 1px transparent solid;
81
+ z-index: 1;
77
82
  &:after {
78
83
  display: block;
79
84
  background-color: #e8e8e8;
@@ -84,6 +89,7 @@
84
89
  border-bottom: 1px transparent solid;
85
90
  color: #e4e0e0;
86
91
  position: relative;
92
+ z-index: 1;
87
93
 
88
94
  &:after {
89
95
  display: block;
@@ -6,10 +6,103 @@ module C80Push
6
6
  module ApplicationHelper
7
7
 
8
8
  def c80_push_render_page_dealers
9
+
10
+ # список регионов, включая дилеры и офисы
11
+ region_dealer_office_list = Region.includes(dealers: :offices)
12
+
13
+ # хэш для построения точек на Yandex карте
14
+ ymap_hash = prepare_ymap_hash(region_dealer_office_list)
15
+
16
+ # список регионов для select-а "Выберите регион"
17
+ r = prepare_regions_hash(region_dealer_office_list)
18
+
9
19
  render partial: 'c80_push/shared/page_dealers',
10
20
  locals: {
21
+ rdo_list: region_dealer_office_list,
22
+ regions_list: r,
23
+ ymap_hash: ymap_hash
11
24
  }
12
25
  end
13
26
 
27
+ private
28
+
29
+ # специально для яваскрипта, работающего с yandex картой,
30
+ # на основе +rdo+ собираем координаты всех офисов
31
+ # в хеше вида:
32
+ #
33
+ # {
34
+ # all: { - здесь собираем все офисы всех регионов (для лаконичности js)
35
+ # coords: [],
36
+ # props: []
37
+ # }
38
+ # <region_id>: [ - данные офисов разложены по регионам
39
+ # coords: [],
40
+ # props: []
41
+ # ]
42
+ # }
43
+ #
44
+ # noinspection RubyResolve
45
+ def prepare_ymap_hash(rdo)
46
+ res = {
47
+ all: {
48
+ coords: [],
49
+ props: []
50
+ }
51
+ }
52
+
53
+ rdo.each do |region|
54
+ region.dealers.each do |dealer|
55
+ dealer.offices.each do |office|
56
+ res[region.id] = { coords:[], props:[] } if res[region.id].nil?
57
+
58
+ # координаты точки (это массив двух точек)
59
+ gps = office.gps_arr
60
+
61
+ # соберём свойства офиса для балуна
62
+ props = {
63
+ balloonContentHeader: t = "#{office.title} (#{dealer.title})",
64
+ balloonContentBody: b = "#{office.addr}<br>#{office.tel}<br>GPS: #{office.gps}",
65
+ hintContent: "#{t}<br>#{b}",
66
+ id: office.id
67
+ }
68
+
69
+ # фиксируем в хэше региона
70
+ res[region.id][:coords] << gps
71
+ res[region.id][:props] << props
72
+
73
+ # фиксируем в all-хэше
74
+ res[:all][:coords] << gps
75
+ res[:all][:props] << props
76
+
77
+ end
78
+ # для удобства в js: зафиксируем кол-во офисов региона
79
+ res[region.id][:count] = res[region.id][:coords].size
80
+ end
81
+ end
82
+
83
+ # для удобства в js: зафиксируем кол-во всех офисов
84
+ res[:all][:count] = res[:all][:coords].size
85
+
86
+ res
87
+ end
88
+
89
+ # соберёт хэш только тех регионов, в которых есть офисы
90
+ # например: {4=>{:id=>4, :title=>"Санкт-Петербург"}}
91
+ def prepare_regions_hash(rdo)
92
+ res = {}
93
+ rdo.each do |region|
94
+ region.dealers.each do |dealer|
95
+ dealer.offices.each do |office|
96
+ if res[region.id].nil?
97
+ res[region.id] = { id:region.id, title:region.title }
98
+ else
99
+ break
100
+ end
101
+ end
102
+ end
103
+ end
104
+ res
105
+ end
106
+
14
107
  end
15
108
  end
@@ -1,12 +1,14 @@
1
1
  module C80Push
2
2
  module PageDealers
3
- module PageDealersHelper
3
+ module DealersLeftListHelper
4
4
 
5
- # Выдать список Дилеров (включая Офисы),
6
- # разложенный по Регионам.
5
+ # Выдать html unordered nested list Дилеров (включая Офисы),
6
+ # разложенный по Регионам, построенный
7
+ # на основе данных +rdo+ - Regions-Dealers-Offices.
7
8
  # Список выводится слева от карты.
8
9
  # (**) Не выводим регионы, у которых нет дилеров.
9
10
  #
11
+ # Структура списка:
10
12
  # * Регион
11
13
  # * Дилер
12
14
  # * Офис 1
@@ -18,11 +20,11 @@ module C80Push
18
20
  # * сайт дилера
19
21
  # * email дилера
20
22
  #
21
- def render_ul_dealers_list
23
+ def render_ul_dealers_list(rdo)
22
24
 
23
25
  res = ''
24
26
 
25
- Region.includes(dealers: :offices).each do |region|
27
+ rdo.each do |region|
26
28
  r = "<h2 class='region_title'>#{region.title}</h2>"
27
29
  ds = ul_region_dealers(region)
28
30
  next if ds.blank? # (**)
@@ -57,7 +59,7 @@ module C80Push
57
59
  dealer.offices.each_with_index do |office|
58
60
  o = "<h4 class='office_title'>#{office.title}</h4>"
59
61
  o += ul_office_props(office)
60
- res += "<li class='li_office' id='office_#{office.id}'>#{o}</li>"
62
+ res += "<li class='li_office' id='office_#{office.id}' data-id='#{office.id}'>#{o}</li>"
61
63
  end
62
64
  res += "<li class='dealer_email'>#{dealer.email}</li>"
63
65
  res += "<li class='dealer_site'>#{dealer.site}</li>"
@@ -19,5 +19,9 @@ module C80Push
19
19
 
20
20
  validates :tel,
21
21
  :presence => true
22
+
23
+ def gps_arr
24
+ self.gps.split(',').map! { |c| c.to_f }
25
+ end
22
26
  end
23
27
  end
@@ -1,13 +1,15 @@
1
1
  <div class="c80_push_page_dealers">
2
2
 
3
3
  <div class="select_region_row">
4
-
4
+ <div class="select_wrapper">
5
+ <%= render 'c80_push/shared/select_region', regions: regions_list %>
6
+ </div>
5
7
  </div>
6
8
 
7
9
  <div class="bottom_row">
8
10
 
9
11
  <div class="dealers_list">
10
- <%= render_ul_dealers_list %>
12
+ <%= render_ul_dealers_list(rdo_list) %>
11
13
  </div>
12
14
 
13
15
  <div id="dealers_map_container">
@@ -18,4 +20,8 @@
18
20
 
19
21
  </div>
20
22
 
23
+ <script>
24
+ var offices = <%= ymap_hash.to_json.html_safe %>;
25
+ </script>
26
+
21
27
  <script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
@@ -0,0 +1,7 @@
1
+ <select id='select_region' class="selectpicker" data-width="400px" data-size="10">
2
+ <option value="all">Выберите регион</option>
3
+ <% regions.each_key do |k| %>
4
+ <% region = regions[k] %>
5
+ <option value="<%= region[:id] %>"><%= region[:title] %></option>
6
+ <% end %>
7
+ </select>
@@ -1,3 +1,3 @@
1
1
  module C80Push
2
- VERSION = '0.1.0.1'
2
+ VERSION = '0.1.0.2'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: c80_push
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.1
4
+ version: 0.1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - C80609A
@@ -40,7 +40,11 @@ files:
40
40
  - app/assets/config/c80_push_manifest.js
41
41
  - app/assets/javascripts/c80_push.js.coffee
42
42
  - app/assets/javascripts/c80_push/backend/dealers.js
43
- - app/assets/javascripts/c80_push/frontend/c80_push_page_dealers/init_yandex_map.js
43
+ - app/assets/javascripts/c80_push/frontend/c80_push_page_dealers/_dealers_left_list_clicks.js
44
+ - app/assets/javascripts/c80_push/frontend/c80_push_page_dealers/_dealers_left_list_filter.js
45
+ - app/assets/javascripts/c80_push/frontend/c80_push_page_dealers/_map_init.js
46
+ - app/assets/javascripts/c80_push/frontend/c80_push_page_dealers/_map_set_objects.js
47
+ - app/assets/javascripts/c80_push/frontend/c80_push_page_dealers/_select_region_init.js
44
48
  - app/assets/javascripts/c80_push/lib_backend/init.js
45
49
  - app/assets/javascripts/c80_push/lib_backend/init_select_picker.js
46
50
  - app/assets/javascripts/c80_push_backend.js.coffee
@@ -51,12 +55,13 @@ files:
51
55
  - app/assets/stylesheets/c80_push_backend.scss
52
56
  - app/helpers/c80_push/admin_helper.rb
53
57
  - app/helpers/c80_push/application_helper.rb
54
- - app/helpers/c80_push/page_dealers/page_dealers_helper.rb
58
+ - app/helpers/c80_push/page_dealers/dealers_left_list_helper.rb
55
59
  - app/models/c80_push/application_record.rb
56
60
  - app/models/c80_push/dealer.rb
57
61
  - app/models/c80_push/office.rb
58
62
  - app/models/c80_push/region.rb
59
63
  - app/views/c80_push/shared/_page_dealers.html.erb
64
+ - app/views/c80_push/shared/_select_region.html.erb
60
65
  - config/locales/dealer/ru.yml
61
66
  - config/locales/office/ru.yml
62
67
  - config/locales/region/ru.yml
@@ -1,13 +0,0 @@
1
- $(document).ready(function() {
2
-
3
- var dealers_map;
4
-
5
- ymaps.ready(function() {
6
- dealers_map = new ymaps.Map('dealers_map_container', {
7
- center: [55, 37],
8
- zoom: 10,
9
- controls: ['zoomControl']
10
- });
11
- });
12
-
13
- });