c80_estate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/CODE_OF_CONDUCT.md +49 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +67 -0
  7. data/Rakefile +2 -0
  8. data/app/admin/c80_estate/areas.rb +56 -0
  9. data/app/admin/c80_estate/atypes.rb +44 -0
  10. data/app/admin/c80_estate/prop_names.rb +48 -0
  11. data/app/admin/c80_estate/properties.rb +38 -0
  12. data/app/admin/c80_estate/role_types.rb +40 -0
  13. data/app/admin/c80_estate/uoms.rb +33 -0
  14. data/app/assets/javascript/c80_estate/backend/admin/areas.js +423 -0
  15. data/app/assets/javascript/c80_estate/backend/init.js +36 -0
  16. data/app/assets/javascript/c80_estate/backend/init_selectpicker.js +6 -0
  17. data/app/assets/javascript/c80_estate/lib/jalert.js +16 -0
  18. data/app/assets/javascript/c80_estate_active_admin.js.coffee +4 -0
  19. data/app/assets/stylesheets/c80_estate/backend/admin_areas.scss +109 -0
  20. data/app/assets/stylesheets/c80_estate/backend/admin_users.scss +27 -0
  21. data/app/assets/stylesheets/c80_estate/backend/common.scss +3 -0
  22. data/app/assets/stylesheets/c80_estate/lib/mixins.scss +17 -0
  23. data/app/assets/stylesheets/c80_estate_active_admin.scss +2 -0
  24. data/app/controllers/c80_estate/ajax_controller.rb +17 -0
  25. data/app/models/c80_estate/aphoto.rb +6 -0
  26. data/app/models/c80_estate/area.rb +26 -0
  27. data/app/models/c80_estate/astatus.rb +6 -0
  28. data/app/models/c80_estate/atphoto.rb +6 -0
  29. data/app/models/c80_estate/atype.rb +132 -0
  30. data/app/models/c80_estate/comment.rb +7 -0
  31. data/app/models/c80_estate/item_prop.rb +70 -0
  32. data/app/models/c80_estate/owner.rb +62 -0
  33. data/app/models/c80_estate/pphoto.rb +5 -0
  34. data/app/models/c80_estate/prop_name.rb +19 -0
  35. data/app/models/c80_estate/property.rb +15 -0
  36. data/app/models/c80_estate/role.rb +6 -0
  37. data/app/models/c80_estate/role_type.rb +5 -0
  38. data/app/models/c80_estate/uom.rb +5 -0
  39. data/app/uploaders/c80_estate/aphoto_uploader.rb +21 -0
  40. data/app/uploaders/c80_estate/atphoto_uploader.rb +21 -0
  41. data/app/uploaders/c80_estate/pphoto_uploader.rb +21 -0
  42. data/bin/console +14 -0
  43. data/bin/setup +8 -0
  44. data/c80_estate.gemspec +25 -0
  45. data/config/routes.rb +3 -0
  46. data/db/migrate/20160629033533_create_c80_estate_areas.rb +13 -0
  47. data/db/migrate/20160629033535_create_c80_estate_properties.rb +15 -0
  48. data/db/migrate/20160629034444_create_c80_prop_names.rb +12 -0
  49. data/db/migrate/20160629041414_create_c80_estate_uoms.rb +10 -0
  50. data/db/migrate/20160629090606_create_c80_estate_aphotos.rb +9 -0
  51. data/db/migrate/20160629091313_create_c80_estate_astatuses.rb +9 -0
  52. data/db/migrate/20160629092323_create_c80_item_props.rb +14 -0
  53. data/db/migrate/20160629093030_create_c80_estate_comments.rb +12 -0
  54. data/db/migrate/20160629100505_create_c80_atypes.rb +10 -0
  55. data/db/migrate/20160629205151_create_c80_estate_atphotos.rb +9 -0
  56. data/db/migrate/20160630012727_create_c80_estate_pphotos.rb +9 -0
  57. data/db/migrate/20160630013636_create_join_table_areas_astatuses.rb +12 -0
  58. data/db/migrate/20160630013737_create_join_table_atypes_prop_names.rb +12 -0
  59. data/db/migrate/20160704050000_create_c80_estate_role_types.rb +9 -0
  60. data/db/migrate/20160704063131_create_c80_estate_roles.rb +10 -0
  61. data/db/seeds/50_fill_uoms.rb.example +8 -0
  62. data/db/seeds/55_fill_prop_names.rb.example +51 -0
  63. data/db/seeds/60_fill_atypes.rb.example +29 -0
  64. data/lib/c80_estate.rb +8 -0
  65. data/lib/c80_estate/engine.rb +23 -0
  66. data/lib/c80_estate/version.rb +3 -0
  67. metadata +151 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: aca313a4bd48d2e8e5c1d37b1e0c7544a7e100bb
4
+ data.tar.gz: fed41c35fe08c402368bda60135399b817b6e482
5
+ SHA512:
6
+ metadata.gz: 689a4c55920d460c884c02172edb1b4116069fc4fa90309cedb228e1fbc0b5676c29898c89eff48fb48acb1e9309cb2af643e0af87b023575a3e0aad516ec4b1
7
+ data.tar.gz: 3c0a30e95776515cf627c85f6dfc8339f2ec0a17b1b6445a2a430d081071c5a8a73b1e78eb59ff1e63e7523b517d042aa83fb0d29978c7cee9ec35548835c950
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at c080609a@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in c80_estate.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 C80609A
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # C80Estate
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/c80_estate`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'c80_estate'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install c80_estate
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ #= require c80_estate_active_admin
27
+ ```
28
+
29
+
30
+ ### Requires
31
+
32
+ ```
33
+ @import "bootstrap";
34
+ ```
35
+
36
+ ```
37
+ #= require bootstrap/dropdown
38
+ #= require bootstrap-select
39
+ ```
40
+
41
+
42
+ ```
43
+ gem 'friendly_id'
44
+ gem 'babosa'
45
+ gem 'bootstrap-select-rails'
46
+ ```
47
+
48
+ ### Seeds
49
+
50
+ Copy and rename example seeds files.
51
+
52
+
53
+ ## Development
54
+
55
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
56
+
57
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
58
+
59
+ ## Contributing
60
+
61
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/c80_estate. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
62
+
63
+
64
+ ## License
65
+
66
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
67
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,56 @@
1
+ ActiveAdmin.register C80Estate::Area, as: 'Area' do
2
+
3
+ # scope_to :current_admin_user, association_method: :sites_list
4
+
5
+ menu :label => "Площади"
6
+
7
+ permit_params :title,
8
+ :desc,
9
+ :owner_id,
10
+ :owner_type,
11
+ :atype_id,
12
+ :property_id,
13
+ :aphotos_attributes => [:id,:image,:_destroy],
14
+ :item_props_attributes => [:value, :_destroy, :prop_name_id, :id]
15
+
16
+ config.sort_order = 'id_asc'
17
+
18
+ index do
19
+ column :title
20
+ column :atype do |area|
21
+ area.atype.title
22
+ end
23
+ actions
24
+ end
25
+
26
+ form(:html => {:multipart => true}) do |f|
27
+
28
+ f.inputs 'Свойства' do
29
+ f.input :title
30
+ f.input :atype, :input_html => { :class => 'selectpicker', 'data-size' => "5", 'data-width' => '300px'}
31
+ f.input :property, :input_html => { :class => 'selectpicker', 'data-size' => "5", 'data-width' => '300px'}
32
+ f.input :desc, :as => :ckeditor
33
+
34
+ f.inputs "Характеристики" do
35
+
36
+ f.has_many :item_props, :allow_destroy => true do |item_prop|
37
+ item_prop.input :prop_name
38
+ item_prop.input :value
39
+ end
40
+
41
+ end
42
+
43
+ f.has_many :aphotos, :allow_destroy => true do |gp|
44
+ gp.input :image,
45
+ :as => :file,
46
+ :hint => image_tag(gp.object.image.thumb512)
47
+ end
48
+
49
+ f.input :owner_id, :input_html => { :value => current_admin_user.id }, as: :hidden
50
+ f.input :owner_type, :input_html => { :value => "AdminUser" }, as: :hidden
51
+ end
52
+
53
+ f.actions
54
+ end
55
+
56
+ end
@@ -0,0 +1,44 @@
1
+ # ПОДкатегории строительных материалов
2
+ ActiveAdmin.register C80Estate::Atype, :as => 'Atype' do
3
+
4
+ menu :label => "Типы", :parent => "Настройки"
5
+
6
+ permit_params :title,
7
+ :slug,
8
+ :prop_name_ids => []
9
+
10
+ config.sort_order = 'id_asc'
11
+
12
+ # controller do
13
+ # cache_sweeper :strsubcat_sweeper, :only => [:update,:create,:destroy]
14
+ # end
15
+
16
+ # before_filter :skip_sidebar!, :only => :index
17
+
18
+ filter :title
19
+
20
+ # controller do
21
+ # cache_sweeper :suit_sweeper, :only => [:update,:create,:destroy]
22
+ # end
23
+
24
+ index do
25
+ selectable_column
26
+ id_column
27
+ column :title
28
+ actions
29
+ end
30
+
31
+ form(:html => {:multipart => true}) do |f|
32
+
33
+ f.inputs "Свойства" do
34
+ f.input :title
35
+ end
36
+
37
+ f.inputs "Характеристики, которыми описываются объекты недвижимости и площади этого типа", :class => 'collapsed' do
38
+ f.input :prop_names, :as => :check_boxes
39
+ end
40
+
41
+ f.actions
42
+ end
43
+
44
+ end
@@ -0,0 +1,48 @@
1
+ ActiveAdmin.register C80Estate::PropName, as: 'PropName' do
2
+
3
+ menu :label => "Имена свойств", :parent => "Настройки"
4
+
5
+ permit_params :title,
6
+ :uom_id,
7
+ :is_excluded_from_filtering,
8
+ :is_normal_price
9
+
10
+ config.sort_order = 'title_asc'
11
+
12
+ filter :title
13
+ filter :atypes
14
+ filter :is_excluded_from_filtering
15
+ filter :is_normal_price
16
+
17
+ # controller do
18
+ # cache_sweeper :suit_sweeper, :only => [:update,:create,:destroy]
19
+ # end
20
+
21
+ index do
22
+ # selectable_column
23
+ id_column
24
+
25
+ column :title
26
+ column :uom
27
+ column :is_excluded_from_filtering
28
+ column :is_normal_price
29
+
30
+ actions
31
+ end
32
+
33
+ form(:html => {:multipart => true}) do |f|
34
+
35
+ f.inputs "Свойства" do
36
+ f.input :title
37
+ f.input :uom, :input_html => { :class => 'selectpicker', 'data-size' => "5", 'data-width' => '300px'}
38
+ f.input :is_excluded_from_filtering,
39
+ :hint => "Если да, то это свойство не будет фигурировать в списке фильтрации".html_safe
40
+
41
+ f.input :is_normal_price,
42
+ :hint => "Является ли свойство ценой".html_safe
43
+
44
+ end
45
+ f.actions
46
+ end
47
+
48
+ end
@@ -0,0 +1,38 @@
1
+ ActiveAdmin.register C80Estate::Property, as: 'Property' do
2
+
3
+ # scope_to :current_admin_user, association_method: :sites_list
4
+
5
+ menu :label => "Объекты недвижимости"
6
+
7
+ permit_params :title,
8
+ :desc,
9
+ :address,
10
+ :latitude,
11
+ :longitude,
12
+ :atype_id,
13
+ :owner_id,
14
+ :owner_type
15
+
16
+ config.sort_order = 'id_asc'
17
+
18
+ index do
19
+ column :title
20
+ column :atype do |prop|
21
+ prop.atype.title
22
+ end
23
+ actions
24
+ end
25
+
26
+ form(:html => {:multipart => true}) do |f|
27
+
28
+ f.inputs 'Свойства' do
29
+ f.input :title
30
+ f.input :atype, :input_html => { :class => 'selectpicker', 'data-size' => "5", 'data-width' => '300px'}
31
+ f.input :owner_id, :input_html => { :value => current_admin_user.id }, as: :hidden
32
+ f.input :owner_type, :input_html => { :value => "AdminUser" }, as: :hidden
33
+ end
34
+
35
+ f.actions
36
+ end
37
+
38
+ end
@@ -0,0 +1,40 @@
1
+ # ПОДкатегории строительных материалов
2
+ ActiveAdmin.register C80Estate::RoleType, :as => 'RoleType' do
3
+
4
+ menu :label => "Роли", :parent => "Настройки"
5
+
6
+ permit_params :title,
7
+ :desc
8
+
9
+ config.sort_order = 'id_asc'
10
+
11
+ # controller do
12
+ # cache_sweeper :strsubcat_sweeper, :only => [:update,:create,:destroy]
13
+ # end
14
+
15
+ # before_filter :skip_sidebar!, :only => :index
16
+
17
+ filter :title
18
+
19
+ # controller do
20
+ # cache_sweeper :suit_sweeper, :only => [:update,:create,:destroy]
21
+ # end
22
+
23
+ index do
24
+ selectable_column
25
+ id_column
26
+ column :title
27
+ actions
28
+ end
29
+
30
+ form(:html => {:multipart => true}) do |f|
31
+
32
+ f.inputs "Свойства" do
33
+ f.input :title
34
+ f.input :desc, input_html: { rows: 3 }
35
+ end
36
+
37
+ f.actions
38
+ end
39
+
40
+ end
@@ -0,0 +1,33 @@
1
+ # единицы измерения
2
+ ActiveAdmin.register C80Estate::Uom, :as => 'Uom' do
3
+
4
+ menu :label => "Единицы измерения", :parent => "Настройки"
5
+
6
+ permit_params :title, :comment, :is_number
7
+
8
+ config.sort_order = 'title_desc'
9
+
10
+ filter :title
11
+
12
+ index do
13
+ # selectable_column
14
+ # id_column
15
+
16
+ column :title
17
+ column :comment
18
+ column :is_number
19
+
20
+ # actions
21
+ end
22
+
23
+ form(:html => {:multipart => true}) do |f|
24
+
25
+ f.inputs "Свойства" do
26
+ f.input :title
27
+ f.input :comment
28
+ f.input :is_number
29
+ end
30
+ f.actions
31
+ end
32
+
33
+ end
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+
3
+ // защита от неправильных данных
4
+ var fCheckItemProperties = function () {
5
+
6
+ var result = true;
7
+
8
+ // - название
9
+ if ($("input#area_title").val().length == 0) {
10
+ jAlert('Укажите название.');
11
+ result = false;
12
+ }
13
+
14
+ // - тип
15
+ if ($("select#area_atype_id").val() == "") {
16
+ jAlert('Укажите тип.');
17
+ result = false;
18
+ }
19
+
20
+ var item_props_input_list = $("li.item_props").find("input");
21
+ var inputs_count = item_props_input_list.length;
22
+
23
+ // - заполнение всех свойств
24
+ if (inputs_count == 0) {
25
+ result = false;
26
+ jAlert('Не получится создать площадь без свойств.');
27
+ } else {
28
+ item_props_input_list.each(function () {
29
+ if ($(this).val() != '') {
30
+ inputs_count--;
31
+ }
32
+ });
33
+ if (inputs_count > 0) {
34
+ result = false;
35
+ jAlert('Заполните все свойства площади.');
36
+ }
37
+ }
38
+
39
+ return result;
40
+ };
41
+
42
+ var jsinit = {
43
+
44
+ _debug:true,
45
+ $select_atype: null,
46
+ $btn_add_area_prop: null, // кнопка "Добавить "
47
+ $item_props_container: null, // в этом контейнере живут fieldset-ы, каждый из которых соответствует одному свойству предмета
48
+ $item_props_container_span: null, // заголовок контейнера, в котором живут fieldset-ы свойств предмета
49
+
50
+ // допишем поясняющий текст "сначала выберите подкатегорию"
51
+ _fWelcomeTextAdd: function () {
52
+ jsinit.$item_props_container_span.text("Характеристики [сначала выберите подкатегорию, тогда появятся свойства, присущие выбранной категории]");
53
+ },
54
+
55
+ // удалим поясняющий текст "сначала выберите подкатегорию"
56
+ _fWelcomeTextRemove: function () {
57
+ jsinit.$item_props_container_span.text("Характеристики");
58
+ },
59
+
60
+ go: function () {
61
+ //jsinit._log("[go]");
62
+ alert('go');
63
+
64
+ // фиксируем селект "Тип площади"
65
+ jsinit.$select_atype = $("select#area_atype_id");
66
+
67
+ // фиксируем контейнер, в котором находятся компоненты для управления свойством C80Estate::Area
68
+ jsinit.$item_props_container = $("li.item_props");
69
+
70
+ jsinit.$item_props_container.parent().parent().addClass('fieldset_item_props');
71
+
72
+ // фиксируем надпись "Характеристики"
73
+ jsinit.$item_props_container_span = jsinit.$item_props_container.parent().parent().find("> legend > span");
74
+
75
+ // фиксируем кнопку "Добавить свойство"
76
+ jsinit.$btn_add_area_prop = jsinit.$item_props_container.find("a.has_many_add");
77
+
78
+ // фиксируем кнопку "Update/Create"
79
+ jsinit.$btn_submin = $("fieldset.actions").find("input[name=commit]");
80
+
81
+ // начинаем слушать изменение селекта "тип" -
82
+ jsinit.$select_atype.on("change", jsinit._onSelectStrSubcatChange);
83
+ jsinit._onSelectStrSubcatChange();
84
+
85
+ // в момент нажатия кнопки "отправить" - "разлачиваем" все селекты
86
+ jsinit.$btn_submin.click(function (e) {
87
+ if (fCheckItemProperties()) {
88
+ jsinit.$item_props_container.find("select").attr("disabled", false);
89
+ fLoadingShow();
90
+ } else {
91
+ e.preventDefault();
92
+ }
93
+ });
94
+
95
+ // пока пользователь не выбрал подкатегорию - допишем поясняющий текст "сначала выберите подкатегорию"
96
+ jsinit._fWelcomeTextAdd();
97
+
98
+ },
99
+
100
+ // слушает изменения селекта с типами
101
+ // инициирует запрос за "Именами Свойств" выбранного в селекте "Типа"
102
+ // показывает загрузчик
103
+ _onSelectStrSubcatChange: function () {
104
+ var atype_id = jsinit.$select_atype[0].value;
105
+ //jsinit._log("[_onSelectStrSubcatChange]: atype_id = " + atype_id);
106
+ if (atype_id == '') {
107
+ jsinit._removeMayBeAddedProps();
108
+ jsinit._fWelcomeTextAdd();
109
+ } else {
110
+ fLoadingShow();
111
+ jsinit._reqStrsubcatPropnames(atype_id);
112
+ jsinit._fWelcomeTextRemove();
113
+ }
114
+ },
115
+
116
+ // запрашиваем список имён свойств указанной подкатегории
117
+ _reqStrsubcatPropnames: function (atype_id) {
118
+ //jsinit._log("[_reqStrsubcatPropnames]: atype_id = " + atype_id);
119
+
120
+ $.ajax({
121
+ url: "/estate/get_atype_propnames",
122
+ data: { atype_id:atype_id },
123
+ dataType: "json",
124
+ type: 'POST'
125
+ }).done(function(data,result) {
126
+ //jsinit._log( data );
127
+
128
+ if (result == "success") {
129
+ jsinit._log( "Кол-во свойств: " + data.length );
130
+
131
+ // удалим, возможно уже добавленные в форму, свойства
132
+ jsinit._removeMayBeAddedProps();
133
+
134
+ // количество свойств
135
+ var n = data.length;
136
+
137
+ // "цикловые" переменные
138
+ var $ifs, // fieldset,
139
+ $iselprop, // очередной селект "имя свойства"
140
+ $iinputprop, // очередной input "значение свойства"
141
+ $ifindbyid, // вспомогательная переменная: содержит результат поиска по id с помощью регулярки
142
+ ielem; // очередной элемент из data
143
+
144
+ for (var i=0; i<n; i++) {
145
+
146
+ // фиксируем объект с данными, описывающий свойство предмета
147
+ ielem = data[i];
148
+
149
+ // нажмём кнопку "Добавить Item prop"
150
+ jsinit.$btn_add_area_prop.click();
151
+
152
+ // фиксируем добавленный в форму fieldset
153
+
154
+ //<fieldset class="inputs has_many_fields processed">
155
+ // <ol>
156
+ // <li id="area_item_props_attributes_37_prop_name_input">
157
+ // <select id="area_item_props_attributes_37_prop_name_id">
158
+ // <option value="37">Артикул</option>
159
+ // </select>
160
+ // </li>
161
+ // <li id="area_item_props_attributes_37_value_input">
162
+ // <input id="area_item_props_attributes_37_value" type="text">
163
+ // </li>
164
+ // </ol>
165
+ //</fieldset>
166
+
167
+ $ifs = jsinit.$item_props_container.find("fieldset").not(".processed");
168
+ $ifs.addClass("processed");
169
+
170
+ $ifindbyid = $ifs.find('[id^="area_item_props_attributes_"]');
171
+
172
+ // находим в ifs селект, отвечающий за имя свойства
173
+ $iselprop = $ifindbyid.find('select');
174
+ //console.log(iselprop);
175
+
176
+ // находим в ifs input, отвечающий за значение свойства
177
+ $iinputprop = $ifindbyid.find('input');
178
+
179
+ // в этот селект жестоко предустанавливаем значение из data, дописываем единицу измерения
180
+ $iselprop.find("option")
181
+ .filter(function () {
182
+ //console.log($(this).val() + " vs " + ielem["id"]);
183
+ return $(this).val() == ielem["id"]; //return $(this).text() == ielem["title"];
184
+ })
185
+ .prop('selected', true)
186
+ .text(function () {
187
+ var t = $(this).text();
188
+ if (ielem["uom_title"] != null) {
189
+ t += ", " + ielem["uom_title"];
190
+ }
191
+ return t;
192
+ }); // дописываем в конец единицу измерения
193
+
194
+ //делаем его readonly
195
+ $iselprop.attr("disabled", true); // NOTE:: но в момент нажатия кнопки "Отправить" мы "разлачиваем" селект, чтобы параметры формы "правильно" отправлялись;
196
+
197
+ // в input "производитель" - ставим "-1" и прячем его от пользователя
198
+ if (ielem["id"] == 36) {
199
+ $iinputprop.val("-1");
200
+ $ifs.css("display",'none');
201
+ }
202
+
203
+ }
204
+
205
+ fLoadingHide();
206
+
207
+ } else {
208
+ alert( "done: не удалось получить данные о свойствах выбранной подкатегории." );
209
+ }
210
+
211
+ })
212
+ .fail(function(jqXHR, textStatus) {
213
+ alert( "fail: не удалось получить данные о свойствах выбранной подкатегории: " + textStatus );
214
+ })
215
+ .always(function() {
216
+ //alert( "complete" );
217
+ });
218
+ },
219
+
220
+ // удалим, возможно уже добавленные в форму, свойства
221
+ _removeMayBeAddedProps: function () {
222
+ $("a.has_many_remove").click();
223
+ },
224
+
225
+ _log: function () {
226
+ if (jsinit._debug) {
227
+ //console.log(arguments[0]);
228
+ }
229
+ }
230
+
231
+ };
232
+
233
+ var fEdit = function () {
234
+
235
+ var $select_area_atype; // селект подкатегории, которой принадлежит редактируемый предмет
236
+ var $item_props_container; // здесь живут селекты свойств
237
+ var $btn_submit;
238
+ var atype_id; // id подкатегории, которой принадлежит редактируемый предмет, извлекается из селекта $select_area_atype
239
+ var $btn_add_area_prop; // кнопка "добавить свойство"
240
+
241
+ // вернёт true, если найдёт в $item_props_container селект свойства atype_id
242
+ var _fCheckSelect = function (atype_id) {
243
+ var result = false;
244
+ var $selects = $item_props_container.find("fieldset").find('select');
245
+ $selects.each(function () {
246
+ if ($(this).val() == atype_id) {
247
+ result = true;
248
+ }
249
+ });
250
+ return result;
251
+ };
252
+
253
+ var fReqPropList = function (atype_id) {
254
+ $.ajax({
255
+ url: "/estate/get_atype_propnames",
256
+ data: { atype_id:atype_id },
257
+ dataType: "json",
258
+ type: 'POST'
259
+ }).done(function (data,result) {
260
+ //data - это список свойств, которые должны быть у предмета
261
+ if (result == "success") {
262
+
263
+ /* обходим data, ищем соответствующие селекты,
264
+ * по ходу формируем список toAdd - индексы массива data
265
+ * отсутствующих свойств. Затем обрабатываем
266
+ * получившийся список и добавляем отсутствующие селекты. */
267
+
268
+ var toAdd = [];
269
+
270
+ // количество свойств
271
+ var n = data.length;
272
+
273
+ var ielem;
274
+
275
+ // обходим список свойств, которые должны быть у предмета
276
+ // и выясняем, кто отсутствует в форме
277
+ for (var i=0; i<n; i++) {
278
+
279
+ // фиксируем объект с данными
280
+ ielem = data[i];
281
+
282
+ // если такой селекта нет в форме - запомним id свойства
283
+ if (_fCheckSelect(ielem["id"])) {
284
+
285
+ } else {
286
+ toAdd.push(i);
287
+ }
288
+ }
289
+
290
+ var $ifs, $iselprop;
291
+
292
+ // теперь добавляем отсутствующие селекты
293
+ n = toAdd.length;
294
+ for (i = 0; i<n; i++) {
295
+ ielem = data[ toAdd[i] ];
296
+
297
+ // нажмём кнопку "Добавить Item prop"
298
+ $btn_add_area_prop.click();
299
+
300
+ // фиксируем добавленный в форму fieldset
301
+ $ifs = $item_props_container.find("fieldset").not(".was_before");
302
+ $ifs.addClass("was_before");
303
+
304
+ // находим в ifs селект, отвечающий за имя свойства
305
+ $iselprop = $ifs.find('[id^="area_item_props_attributes_"]').find('select');
306
+
307
+ // в этот селект жестоко предустанавливаем значение из data и делаем его readonly
308
+ $iselprop.find("option").filter(function () {
309
+ //console.log(this);
310
+ return $(this).val() == ielem["id"]; //return $(this).text() == ielem["title"];
311
+ }).prop('selected', true);
312
+ $iselprop.attr("disabled", true); // NOTE:: но в момент нажатия кнопки "Отправить" мы "разлачиваем" селект, чтобы параметры формы "правильно" отправлялись
313
+
314
+ }
315
+
316
+ /*дописываем единицы измерения всем селектам*/
317
+
318
+ // перед циклом: фиксируем все fieldset
319
+ $ifs = $item_props_container.find("fieldset");
320
+
321
+ // перед циклом: фиксируем все интерактивные элементы с таким id
322
+ var $ifindbyid = $ifs.find('[id^="area_item_props_attributes_"]');
323
+ $iselprop = $ifindbyid.find('select');
324
+
325
+ n = data.length;
326
+ for (i = 0; i<n; i++) {
327
+ ielem = data[i];
328
+
329
+ // находим селект, отвечающий за имя свойства и дописываем единицу измерения
330
+ $iselprop.find("option").filter(function () {
331
+ //console.log(this);
332
+ return $(this).val() == ielem["id"]; //return $(this).text() == ielem["title"];
333
+ }).text(function () {
334
+ var t = $(this).text();
335
+ if (ielem["uom_title"] != null) {
336
+ t += ", " + ielem["uom_title"]
337
+ }
338
+ return t;
339
+ });
340
+
341
+ // в input "производитель" - ставим "-1" и прячем весь fieldset от пользователя
342
+ if (ielem["id"] == 36) {
343
+ // находим опцию id=36 селекта "имя свойства"
344
+ var $opt = $iselprop.find("option").filter(function () {
345
+ var $t = $(this);
346
+ return $t.val() == 36 && $t.prop('selected');
347
+ });
348
+ // из этой опции добираемся до fieldset, который её содержит
349
+ var $fieldset = $opt.parent().parent().parent();
350
+ // а затем уже находим input
351
+ $fieldset.find("input").val("-1");
352
+ // прячем
353
+ $fieldset.css('display','none');
354
+
355
+ }
356
+
357
+ }
358
+
359
+ fLoadingHide();
360
+
361
+ } else {
362
+ alert( "done: не удалось получить данные о свойствах выбранной подкатегории." );
363
+ }
364
+ }).fail(function(jqXHR, textStatus) {
365
+ alert( "fail: не удалось получить данные о свойствах выбранной подкатегории: " + textStatus );
366
+ });
367
+ };
368
+
369
+ $(document).ready(function () {
370
+
371
+ // инициализация
372
+
373
+ // фиксируем селект "Тип площади"
374
+ $select_area_atype = $('select#area_atype_id');
375
+ // заодно запомним, какой тип установленен для текущей редактируемой площади
376
+ atype_id = $select_area_atype[0].value;
377
+
378
+ // фиксируем кнопку "Update/Create"
379
+ $btn_submit = $("fieldset.actions").find("input[name=commit]");
380
+
381
+ // фиксируем контейнер, в котором находятся компоненты для управления свойством C80Estate::Area
382
+ $item_props_container = $("li.item_props");
383
+
384
+ $item_props_container.parent().parent().addClass('fieldset_item_props');
385
+
386
+ // фиксируем кнопку "Добавить свойство"
387
+ $btn_add_area_prop = $item_props_container.find("a.has_many_add");
388
+
389
+ // блокируем селект "тип"
390
+ $select_area_atype.attr("disabled", true);
391
+
392
+ // блокируем селекты "свойства товара"
393
+ $item_props_container.find("select").attr("disabled", true);
394
+
395
+ // отмечаем уже имеющиеся fieldsets
396
+ $item_props_container.find("fieldset").each(function () {
397
+ $(this).addClass("was_before");
398
+ });
399
+
400
+ //совершаем запрос за свойствами, которые присущи данному типу
401
+ fReqPropList(atype_id);
402
+
403
+ // в момент нажатия кнопки "отправить" - "разлачиваем" все селекты
404
+ // и добавляем модальный предзагрузчик
405
+ $btn_submit.click(function (e) {
406
+ if (fCheckItemProperties()) {
407
+ $item_props_container.find("select").attr("disabled", false);
408
+ fLoadingShow();
409
+ //e.preventDefault(); // for debug
410
+ } else {
411
+ e.preventDefault();
412
+ }
413
+ });
414
+
415
+ });
416
+
417
+ fLoadingShow();
418
+ };
419
+
420
+ YOUR_APP.areas = {
421
+ edit: fEdit,
422
+ "new": jsinit.go
423
+ };