c80_map_floors 0.1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +3 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +67 -0
  8. data/Rakefile +1 -0
  9. data/app/admin/c80_map_floors/floors.rb +57 -0
  10. data/app/admin/c80_map_floors/map_buildings.rb +49 -0
  11. data/app/admin/c80_map_floors/settings.rb +32 -0
  12. data/app/assets/javascripts/buttons/admin_buttons/button_area_link.js +91 -0
  13. data/app/assets/javascripts/buttons/admin_buttons/button_building_link.js +91 -0
  14. data/app/assets/javascripts/buttons/admin_buttons/button_cancel_create.js +21 -0
  15. data/app/assets/javascripts/buttons/admin_buttons/button_cancel_remove.js +23 -0
  16. data/app/assets/javascripts/buttons/admin_buttons/button_complete_create.js +22 -0
  17. data/app/assets/javascripts/buttons/admin_buttons/button_edit.js +96 -0
  18. data/app/assets/javascripts/buttons/admin_buttons/button_new.js +46 -0
  19. data/app/assets/javascripts/buttons/admin_buttons/button_remove.js +23 -0
  20. data/app/assets/javascripts/buttons/admin_buttons/button_save.js +111 -0
  21. data/app/assets/javascripts/buttons/button_back_to_map.js +84 -0
  22. data/app/assets/javascripts/buttons/zoom_buttons.js +78 -0
  23. data/app/assets/javascripts/c80_map_floors.js.coffee +23 -0
  24. data/app/assets/javascripts/events/app_event.js +15 -0
  25. data/app/assets/javascripts/map_objects/area.js +251 -0
  26. data/app/assets/javascripts/map_objects/building.js +294 -0
  27. data/app/assets/javascripts/map_objects/dot.js +14 -0
  28. data/app/assets/javascripts/map_objects/floor.js +10 -0
  29. data/app/assets/javascripts/src/main.js +1421 -0
  30. data/app/assets/javascripts/src/state_controller.js +322 -0
  31. data/app/assets/javascripts/src/utils/map_utils.js +23 -0
  32. data/app/assets/javascripts/src/utils/opacity_buttons_utils.js +15 -0
  33. data/app/assets/javascripts/src/utils/utils.js +140 -0
  34. data/app/assets/javascripts/svg_elements/area_label.js +25 -0
  35. data/app/assets/javascripts/svg_elements/building_label.js +65 -0
  36. data/app/assets/javascripts/svg_elements/helper.js +36 -0
  37. data/app/assets/javascripts/svg_elements/polygon.js +194 -0
  38. data/app/assets/javascripts/view/save_preloader.js +30 -0
  39. data/app/assets/stylesheets/c80_map_floors.scss +4 -0
  40. data/app/assets/stylesheets/map.scss +1464 -0
  41. data/app/assets/stylesheets/view/buttons/area_order_button.scss +16 -0
  42. data/app/assets/stylesheets/view/buttons/back_to_map_button.scss +28 -0
  43. data/app/assets/stylesheets/view/elems/building_info.scss +54 -0
  44. data/app/assets/stylesheets/view/elems/free_areas_label.scss +116 -0
  45. data/app/assets/stylesheets/view/elems/map_objects/map_object_image_bg.scss +10 -0
  46. data/app/assets/stylesheets/view/modal_window.scss +13 -0
  47. data/app/assets/stylesheets/view/save_preloader.scss +206 -0
  48. data/app/controllers/c80_map_floors/ajax_controller.rb +65 -0
  49. data/app/controllers/c80_map_floors/application_controller.rb +6 -0
  50. data/app/controllers/c80_map_floors/map_ajax_controller.rb +70 -0
  51. data/app/helpers/c80_map_floors/application_helper.rb +28 -0
  52. data/app/models/c80_map_floors/area.rb +20 -0
  53. data/app/models/c80_map_floors/area_representator.rb +75 -0
  54. data/app/models/c80_map_floors/base_map_object.rb +41 -0
  55. data/app/models/c80_map_floors/building_representator.rb +72 -0
  56. data/app/models/c80_map_floors/floor.rb +37 -0
  57. data/app/models/c80_map_floors/map_building.rb +45 -0
  58. data/app/models/c80_map_floors/map_json.rb +35 -0
  59. data/app/models/c80_map_floors/setting.rb +32 -0
  60. data/app/uploaders/c80_map_floors/building_image_uploader.rb +31 -0
  61. data/app/uploaders/c80_map_floors/floor_image_uploader.rb +33 -0
  62. data/app/uploaders/c80_map_floors/map_image_uploader.rb +31 -0
  63. data/app/views/c80_map_floors/_map_row_index.html.erb +40 -0
  64. data/app/views/c80_map_floors/ajax/fetch_unlinked_areas.js.erb +7 -0
  65. data/app/views/c80_map_floors/ajax/fetch_unlinked_buildings.js.erb +7 -0
  66. data/app/views/c80_map_floors/ajax/map_edit_buttons.js.erb +36 -0
  67. data/app/views/c80_map_floors/ajax/shared/_map_creating.html.erb +6 -0
  68. data/app/views/c80_map_floors/ajax/shared/_map_editing.html.erb +4 -0
  69. data/app/views/c80_map_floors/ajax/shared/_map_removing.html.erb +5 -0
  70. data/app/views/c80_map_floors/ajax/shared/_select_list_unlinked_areas.html.erb +6 -0
  71. data/app/views/c80_map_floors/ajax/shared/_select_list_unlinked_buildings.html.erb +10 -0
  72. data/app/views/c80_map_floors/shared/_modal_window.html.erb +28 -0
  73. data/app/views/c80_map_floors/shared/_save_preloader.html.erb +3 -0
  74. data/app/views/c80_map_floors/shared/map_row/_area_order_button.html.erb +7 -0
  75. data/app/views/c80_map_floors/shared/map_row/_building_info.html.erb +17 -0
  76. data/bin/console +14 -0
  77. data/bin/setup +7 -0
  78. data/c80_map_floors.gemspec +28 -0
  79. data/config/routes.rb +4 -0
  80. data/db/migrate/20161015190000_create_c80_map_floors_settings.rb +8 -0
  81. data/db/migrate/20161015190001_create_c80_map_floors_map_buildings.rb +10 -0
  82. data/db/migrate/20161015190002_create_c80_map_floors_areas.rb +12 -0
  83. data/db/migrate/20161015190003_add_building_representator_to_c80_map_floors_buildings.rb +6 -0
  84. data/db/migrate/20161015190004_create_c80_map_floors_floors.rb +16 -0
  85. data/db/migrate/20161019111010_add_title_to_c80_map_floors_buildings.rb +5 -0
  86. data/db/migrate/20161020184040_add_coords_img_to_c80_map_floors_buildings.rb +5 -0
  87. data/db/seeds/c80_map_floors_01_fill_map_settings.rb +6 -0
  88. data/db/seeds/c80_map_floors_02_create_test_area.rb +7 -0
  89. data/lib/c80_map_floors.rb +8 -0
  90. data/lib/c80_map_floors/engine.rb +23 -0
  91. data/lib/c80_map_floors/version.rb +3 -0
  92. metadata +218 -0
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+
3
+ function StateController() {
4
+
5
+ var _map = null;
6
+ var _this = this;
7
+
8
+ _this.left_side = $("#left_side");
9
+ _this.right_side = $("#right_side");
10
+ _this.remove_button = $('.mapplic-remove-button');
11
+ _this.new_button = $('.mapplic-new-button');
12
+ _this.mzoom_buttons = $('.mzoom_buttons');
13
+ _this.map_creating = $('#map_creating');
14
+ _this.map_editing = $('#map_editing');
15
+ _this.map_removing = $('#map_removing');
16
+ _this.main_map = $('.main_map'); /*qwwqq*/
17
+ _this.svg_overlay = $('#svg_overlay');
18
+ _this.building_info = $('.building_info');
19
+ _this.area_order_button = $('.area_order_button');
20
+ _this.edit_button = $('.mapplic-edit-button');
21
+ _this.masked = $('#masked');
22
+
23
+ _this.setMode = function (mode) {
24
+
25
+ // Должен быть учёт, из какого состояния пришли в состояние рисования, и возвращаться в него
26
+ // * При рисовании, находясь внутри здания, возвращаться в 'edit_building'
27
+ // * При рисовании, находясь внутри площади, возвращаться в 'edit_area'
28
+ // За исключением ситуации, когда начали редактировать, находясь на карте
29
+ if (mode == 'editing' && _map.prev_mode != 'viewing') {
30
+ mode = _map.prev_mode;
31
+ }
32
+
33
+ clog('<StateController.setMode> mode = ' + mode);
34
+
35
+ _map.prev_mode = _map.mode;
36
+ _map.mode = mode;
37
+
38
+ // этот код коррелирует с [x9cs7]. Возможно, нужен рефакторинг.
39
+ _map.container.removeClass("viewing");
40
+ _map.container.removeClass("editing");
41
+ _map.container.removeClass("creating");
42
+ _map.container.removeClass("removing");
43
+ _map.container.removeClass("view_building");
44
+ _map.container.removeClass("edit_building");
45
+ _map.container.removeClass("view_area");
46
+ _map.container.removeClass("edit_area");
47
+ _map.container.addClass(mode);
48
+
49
+ _this.checkMode();
50
+ };
51
+
52
+ _this.checkMode = function () {
53
+
54
+ if (_this.new_button.length == 0) _this.new_button = $('.mapplic-new-button');
55
+ if (_this.remove_button.length == 0) _this.remove_button = $('.mapplic-remove-button');
56
+ if (_this.edit_button.length == 0) _this.edit_button = $('.mapplic-edit-button');
57
+ if (_this.right_side.length == 0) _this.right_side = $('#right_side');
58
+ if (_this.left_side.length == 0) _this.left_side = $('#left_side');
59
+ if (_this.mzoom_buttons.length == 0) _this.mzoom_buttons = $('.mzoom_buttons');
60
+ if (_this.map_creating.length == 0) _this.map_creating = $('#map_creating');
61
+ if (_this.map_editing.length == 0) _this.map_editing = $('#map_editing');
62
+ if (_this.map_removing.length == 0) _this.map_removing = $('#map_removing');
63
+ if (_this.main_map.length == 0) _this.main_map = $('.main_map'); /*qwwqq*/
64
+ if (_this.svg_overlay.length == 0) _this.svg_overlay = $('#svg_overlay');
65
+ if (_this.building_info.length == 0) _this.building_info = $('.building_info');
66
+ if (_this.area_order_button.length == 0) _this.area_order_button = $('.area_order_button');
67
+ if (_this.masked.length == 0) _this.masked = $("#masked");
68
+
69
+ switch (_map.mode) {
70
+
71
+ // перешли в состояние
72
+ // редактирования карты
73
+ case "editing":
74
+
75
+ // спрячем надписи "цена за метр" и адрес с телефоном
76
+ _this.left_side.css("top", -300);
77
+ _this.right_side.css("top", -300);
78
+
79
+ // покажем кнопку "добавить фигуру"
80
+ OpacityButtonsUtils.show(_this.new_button);
81
+ _map.new_button_klass.resetState();
82
+
83
+ // покажем кнопку "удалить фигуру"
84
+ OpacityButtonsUtils.show(_this.remove_button);
85
+
86
+ // спрячем статусную область
87
+ _this.map_creating.css('display', 'none');
88
+ _this.map_editing.css('display', 'block');
89
+ _this.map_removing.css('display', 'none');
90
+
91
+ // покажем кнопки, присущие этому режиму
92
+ _this.mzoom_buttons.css('opacity', '1');
93
+
94
+ _this.main_map.css('opacity', '1');
95
+
96
+ _map.save_button_klass.show();
97
+ _map.save_button_klass.check_and_enable();
98
+
99
+ // скроем подсказки - сколько свободных площадей где есть
100
+ _map.hide_free_areas_hint();
101
+
102
+ break;
103
+
104
+ // перешли в состояние
105
+ // просмотра карты, все здания с крышами
106
+ case "viewing":
107
+ //clog("_this.left_side.data('init') = " + _this.left_side.data('init'));
108
+
109
+ // покажем надписи "цена за метр" и адрес с телефоном
110
+ if (_this.left_side.data('init') == undefined) {
111
+ _this.left_side.data('init', _this.left_side.css("top"));
112
+ }
113
+ if (_this.right_side.data('init') == undefined) {
114
+ _this.right_side.data('init', _this.right_side.css("top"));
115
+ }
116
+ _this.left_side.css("top", _this.left_side.data('init'));
117
+ _this.right_side.css("top", _this.right_side.data('init'));
118
+
119
+ // спрячем кнопки редактора
120
+ OpacityButtonsUtils.hide(_this.new_button);
121
+ OpacityButtonsUtils.hide(_this.remove_button);
122
+ _this.map_creating.css('display', 'none');
123
+ _this.map_editing.css('display', 'none');
124
+ _this.map_removing.css('display', 'none');
125
+
126
+ // покажем кнопки zoom
127
+ _this.mzoom_buttons.css('opacity', '1');
128
+
129
+ // покажем главную карту(?)
130
+ _this.main_map.css('opacity', '1');
131
+
132
+ // скроем svg_overlay слой, который нужен только когда внутри здания
133
+ _this.svg_overlay.css('display', 'none');
134
+
135
+ // скроем слой, в котором рисуем анимацию по маске, который нужен только когда внутри здания\площади
136
+ _this.masked.addClass('hiddn');
137
+
138
+ // скроем табличку с данными о здании
139
+ if (_this.building_info.data("init") == undefined) {
140
+ _this.building_info.data('init', _this.building_info.css("top"));
141
+ }
142
+ _this.building_info.css("top", -300);
143
+ _this.building_info.css("display", "block");
144
+
145
+ // скроем кнопку "забронировать площадь"
146
+ _this.area_order_button.css('display', 'none');
147
+
148
+ // скроем кнопку "обратно на карту"
149
+ _map.back_to_map_button_klass.hide();
150
+
151
+ // актуально, когда входим в это состояние
152
+ // из здания\площади, нажав кнопку "обратно на карту"
153
+ _map.edit_button_klass.setState('viewing', true); // [a1x7]
154
+
155
+ if (_map.save_button_klass) {
156
+ _map.save_button_klass.hide();
157
+ }
158
+
159
+ // покажем подсказки - сколько свободных площадей где есть
160
+ _map.show_free_areas_hint();
161
+
162
+ break;
163
+
164
+ // перешли в состояние рисования полигона
165
+ case "creating":
166
+ //_this.mzoom_buttons.css('opacity', '0');
167
+ _this.map_creating.css('display', 'block');
168
+ _this.map_editing.css('display', 'none');
169
+ _this.map_removing.css('display', 'none');
170
+
171
+ _this.main_map.css('opacity', '1');
172
+
173
+ break;
174
+
175
+ // перешли в состояние удаления полигона
176
+ case "removing":
177
+ //_this.mzoom_buttons.css('opacity', '0');
178
+ _this.map_creating.css('display', 'none');
179
+ _this.map_editing.css('display', 'none');
180
+ _this.map_removing.css('display', 'block');
181
+
182
+ _this.main_map.css('opacity', '1');
183
+
184
+ _map.save_button_klass.hide();
185
+
186
+ // прячем кнопку "создать полигон"
187
+ OpacityButtonsUtils.hide(_this.new_button);
188
+ OpacityButtonsUtils.hide(_this.remove_button);
189
+ OpacityButtonsUtils.hide(_this.edit_button);
190
+
191
+ break;
192
+
193
+ // вошли в здание
194
+ case "view_building":
195
+
196
+ // покажем кнопку "обратно на карту"
197
+ _map.back_to_map_button_klass.show();
198
+
199
+ // скроем кнопку "связать здание с полигоном"
200
+ _map.building_link_button_klass.hide();
201
+
202
+ // спрячем надписи "цена за метр" и адрес с телефоном
203
+ _this.left_side.css("top", -300);
204
+ _this.right_side.css("top", -300);
205
+
206
+ //_this.main_map.css('opacity','0.7');
207
+ _this.svg_overlay.css('display', 'block');
208
+
209
+ _this.building_info.css("top", _this.building_info.data("init"));
210
+ _this.masked.addClass('hiddn');
211
+
212
+ _this.area_order_button.css('display', 'none');
213
+ _map.edit_button_klass.setState('view_building', true); // [a1x7]
214
+ if (_map.current_building != undefined) _map.current_building.resetOverlayZindex();
215
+ _map.save_button_klass.hide();
216
+
217
+ OpacityButtonsUtils.hide(_this.new_button);
218
+ OpacityButtonsUtils.hide(_this.remove_button);
219
+
220
+ _this.mzoom_buttons.css('opacity', '1');
221
+
222
+ // скроем подсказки - сколько свободных площадей где есть
223
+ _map.hide_free_areas_hint();
224
+
225
+ break;
226
+
227
+ // редактируем, находясь в здании
228
+ case "edit_building":
229
+
230
+ // спрячем кнопку "обратно на карту"
231
+ _map.back_to_map_button_klass.hide();
232
+
233
+ // покажем кнопку "связать здание с полигоном"
234
+ _map.building_link_button_klass.show();
235
+
236
+ // т.к. этот слой используется испключительно в помощь при рисовании обводки площадей
237
+ // и перехватывает клики при dnd, то тут он нам не нужен
238
+ _this.svg_overlay.css('display', 'none');
239
+
240
+ // заодно поменяем z-index слоёв с колоннами и слоя с svg
241
+ // полигонами площадей, чтобы можно было добраться мышкой
242
+ // до этих полигонов и редактировать их
243
+ if (_map.current_building != undefined) _map.current_building.changeOverlayZindex();
244
+
245
+ // покажем кнопку "добавить фигуру"
246
+ OpacityButtonsUtils.show(_this.new_button);
247
+ _map.new_button_klass.resetState();
248
+
249
+ // покажем кнопку "удалить фигуру"
250
+ OpacityButtonsUtils.show(_this.remove_button);
251
+
252
+ // покажем кнопку "ред"
253
+ OpacityButtonsUtils.show(_this.edit_button);
254
+
255
+ // спрячем инфу о здании
256
+ _this.building_info.css("top", -300);
257
+
258
+ // спрячем статус строку "вы создаёте полигон"
259
+ _this.map_creating.css('display', 'none');
260
+ _this.map_removing.css('display', 'none');
261
+
262
+ // покажем, возможно спрятанные, zoom кнопки
263
+ _this.mzoom_buttons.css('opacity', '1');
264
+
265
+ _map.save_button_klass.show();
266
+ _map.save_button_klass.check_and_enable();
267
+
268
+ break;
269
+
270
+ // вошли в площадь
271
+ case "view_area":
272
+ _map.back_to_map_button_klass.show();
273
+ _this.masked.removeClass('hiddn');
274
+ var t = _this.building_info.height() + _this.building_info.offset().top;
275
+ var tt = _this.building_info.css("left");
276
+ var tq = (_this.building_info.width() + 40) + "px";
277
+ _this.area_order_button.css("top", t + "px");
278
+ // _this.area_order_button.css("bottom","400px");
279
+ _this.area_order_button.css("left", tt);
280
+ _this.area_order_button.css("width", tq);
281
+ _this.area_order_button.css('display', 'block');
282
+ _map.edit_button_klass.setState('view_area', true); // [a1x7]
283
+
284
+ // скроем кнопку "связать площадь с полигоном"
285
+ _map.area_link_button_klass.hide();
286
+
287
+ OpacityButtonsUtils.hide(_this.new_button);
288
+ OpacityButtonsUtils.hide(_this.remove_button);
289
+
290
+ _this.mzoom_buttons.css('opacity', '1');
291
+
292
+ break;
293
+
294
+ // начали редактировать площадь
295
+ case 'edit_area':
296
+
297
+ // спрячем кнопку "обратно на карту"
298
+ _map.back_to_map_button_klass.hide();
299
+
300
+ // покажем кнопку "связать площадь с полигоном"
301
+ _map.area_link_button_klass.show();
302
+
303
+ // покажем кнопку "сохранить изменения"
304
+ _map.save_button_klass.show();
305
+
306
+ // спрячем кнопку "создать полигон"
307
+ OpacityButtonsUtils.hide(_this.new_button);
308
+
309
+ // покажем кнопку "ред"
310
+ OpacityButtonsUtils.show(_this.edit_button);
311
+
312
+ _map.edit_button_klass.setState('edit_area', true); // [a1x7]
313
+
314
+ break;
315
+ }
316
+ };
317
+
318
+ _this.init = function (link_to_map) {
319
+ _map = link_to_map;
320
+ }
321
+
322
+ }
@@ -0,0 +1,23 @@
1
+ var MapUtils = {
2
+
3
+ svgOverlayHideAllExcept: function ($g) {
4
+ if ($g != null) {
5
+ console.log("<MapUtils.svgOverlayHideAllExcept>");
6
+
7
+ // убираем у всех g из svg_overlay класс viewing_area
8
+ $g.parent().find('g').css('display','none');
9
+
10
+ // а редактируемому полигону добавим класс viewing_area
11
+ $g.css('display','block');
12
+ }
13
+
14
+ },
15
+
16
+ svgOverlayRestore: function ($g) {
17
+ if ($g != null) {
18
+ console.log("<MapUtils.svgOverlayRestore>");
19
+ $g.parent().find('g').css('display','block');
20
+ }
21
+ }
22
+
23
+ };
@@ -0,0 +1,15 @@
1
+ var OpacityButtonsUtils = {
2
+
3
+ hide: function ($button) {
4
+ $button.css('opacity', '0');
5
+ setTimeout(function () { $button.css('display', 'none'); }, 200); // see map.scss: %ebutton
6
+ $button.addClass('mapplic-disabled');
7
+ },
8
+
9
+ show: function ($button) {
10
+ $button.css('display', 'block');
11
+ $button.css('opacity', '1');
12
+ $button.removeClass('mapplic-disabled');
13
+ }
14
+
15
+ };
@@ -0,0 +1,140 @@
1
+
2
+ var utils = {
3
+
4
+ // выдать из массива arr элемент с указанным id
5
+ getById: function (id,arr) {
6
+ var i;
7
+ var iel;
8
+ for (i=0; i<arr.length; i++) {
9
+ iel = arr[i];
10
+ if (iel.hasOwnProperty('id') && iel['id'] == id) {
11
+ return iel;
12
+ }
13
+ }
14
+ return null;
15
+ },
16
+
17
+ offsetX: function (node) {
18
+ var box = node.getBoundingClientRect(),
19
+ scroll = window.pageXOffset;
20
+
21
+ return Math.round(box.left + scroll);
22
+ },
23
+ offsetY: function (node) {
24
+ var box = node.getBoundingClientRect(),
25
+ scroll = window.pageYOffset;
26
+
27
+ return Math.round(box.top + scroll);
28
+ },
29
+
30
+ trim: function (str) {
31
+ return str.replace(/^\s+|\s+$/g, '');
32
+ },
33
+ id: function (str) {
34
+ return document.getElementById(str);
35
+ },
36
+ hide: function (node) {
37
+ node.style.display = 'none';
38
+
39
+ return this;
40
+ },
41
+ show: function (node) {
42
+ node.style.display = 'block';
43
+
44
+ return this;
45
+ },
46
+ encode: function (str) {
47
+ return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
48
+ },
49
+ decode: function (str) {
50
+ return str.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
51
+ },
52
+ foreach: function (arr, func) {
53
+ for (var i = 0, count = arr.length; i < count; i++) {
54
+ func(arr[i], i);
55
+ }
56
+ },
57
+ foreachReverse: function (arr, func) {
58
+ for (var i = arr.length - 1; i >= 0; i--) {
59
+ func(arr[i], i);
60
+ }
61
+ },
62
+ debug: (function () {
63
+ var output = document.getElementById('debug');
64
+ return function () {
65
+ output.innerHTML = [].join.call(arguments, ' ');
66
+ }
67
+ })(),
68
+ stopEvent: function (e) {
69
+ e.stopPropagation();
70
+ e.preventDefault();
71
+
72
+ return this;
73
+ },
74
+ addClass: function (node, str) {
75
+ // node.className.baseVal for SVG-elements
76
+ // or
77
+ // node.className for HTML-elements
78
+ var is_svg = node.className.baseVal !== undefined ? true : false,
79
+ arr = is_svg ? node.className.baseVal.split(' ') : node.className.split(' '),
80
+ isset = false;
81
+
82
+ utils.foreach(arr, function (x) {
83
+ if (x === str) {
84
+ isset = true;
85
+ }
86
+ });
87
+
88
+ if (!isset) {
89
+ arr.push(str);
90
+ is_svg ? node.className.baseVal = arr.join(' ') : node.className = arr.join(' ');
91
+ }
92
+
93
+ return this;
94
+ },
95
+ removeClass: function (node, str) {
96
+ var is_svg = node.className.baseVal !== undefined ? true : false,
97
+ arr = is_svg ? node.className.baseVal.split(' ') : node.className.split(' '),
98
+ isset = false;
99
+
100
+ utils.foreach(arr, function (x, i) {
101
+ if (x === str) {
102
+ isset = true;
103
+ arr.splice(i--, 1);
104
+ }
105
+ });
106
+
107
+ if (isset) {
108
+ is_svg ? node.className.baseVal = arr.join(' ') : node.className = arr.join(' ');
109
+ }
110
+
111
+ return this;
112
+ },
113
+ hasClass: function (node, str) {
114
+ var is_svg = node.className.baseVal !== undefined ? true : false,
115
+ arr = is_svg ? node.className.baseVal.split(' ') : node.className.split(' '),
116
+ isset = false;
117
+
118
+ utils.foreach(arr, function (x) {
119
+ if (x === str) {
120
+ isset = true;
121
+ }
122
+ });
123
+
124
+ return isset;
125
+ },
126
+ extend: function (obj, options) {
127
+ var target = {};
128
+
129
+ for (var name in obj) {
130
+ if (obj.hasOwnProperty(name)) {
131
+ target[name] = options[name] ? options[name] : obj[name];
132
+ }
133
+ }
134
+
135
+ return target;
136
+ },
137
+ supportFileReader: (function () {
138
+ return (typeof FileReader !== 'undefined');
139
+ })()
140
+ };