redmine_crm 0.0.37 → 0.0.38

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: 4b0ba370b2cc56fc7a7573ba6e7fa65f63a739a9
4
- data.tar.gz: 2e257839a165ba3ac9a35f1735d25721dd7ab4a6
3
+ metadata.gz: 5ade85cd3ada9dbdf2283e26488fc7a8ae0eeb93
4
+ data.tar.gz: 1c872961e53a3f1186ee4283cb08a15b264b3fe2
5
5
  SHA512:
6
- metadata.gz: 8166cb752f502d9b172c30bf781ea30313f2a2fc5b2d37b9eb2a7585f8bd5e169509e6ceeee2703def216331ce00ad391ffc2ddf1571773dd0ba6adea658a45c
7
- data.tar.gz: b2763d0e87a531654ce8fb73937becf3ddb1fb53a5702452c8ce83bcdfc7172a95a16e429e26192d8e2fff00cb97dd3ac8fdd95ec68c5752418090e7064e67ed
6
+ metadata.gz: 07c4211ffc5be1a3322a8eec1dc7ccfdaabe77b8edc8cade7a486b0a51852a728b78144c31c3f5c998c18ef11d954a24000f646f58f23bb98e57723dda3dca4d
7
+ data.tar.gz: 6527ee07dbcc1e52cd240e03c70dbf6ac00d32ef43b0af638940572896eb239e8cc7bb444927a74570845ca3501d474615a584fb126860fa52401499c9ef24bd
@@ -20,7 +20,7 @@ pipelines:
20
20
  definitions:
21
21
  services:
22
22
  mysql:
23
- image: mysql
23
+ image: mysql:5.7
24
24
  environment:
25
25
  MYSQL_DATABASE: redmine_crm_test
26
26
  MYSQL_ROOT_PASSWORD: password
data/lib/redmine_crm.rb CHANGED
@@ -32,6 +32,10 @@ require 'redmine_crm/helpers/external_assets_helper'
32
32
  require 'redmine_crm/helpers/form_tag_helper'
33
33
  require 'redmine_crm/assets_manager'
34
34
 
35
+ module RedmineCrm
36
+ GEM_NAME = 'redmine_crm'.freeze
37
+ end
38
+
35
39
  if defined?(ActiveRecord::Base)
36
40
  ActiveRecord::Base.send :include, RedmineCrm::ActsAsList::List
37
41
  ActiveRecord::Base.extend(RedmineCrm::ActsAsVotable::Voter)
@@ -87,8 +87,8 @@ module RedmineCrm
87
87
  unless Object.const_defined?(viewing_class)
88
88
  Object.class_eval <<-EOV
89
89
  class #{viewing_class} < ActiveRecord::Base
90
- belongs_to :viewed, :polymorphic => true
91
- belongs_to :viewer, :class_name => #{viewer_class}, :foreign_key => :viewer_id
90
+ belongs_to :viewed, polymorphic: true
91
+ belongs_to :viewer, class_name: '#{viewer_class}', foreign_key: :viewer_id
92
92
  end
93
93
  EOV
94
94
  end
@@ -114,7 +114,7 @@ module RedmineCrm
114
114
  viewer_as_class = viewer_class.constantize
115
115
  return if viewer_as_class.instance_methods.include?('find_in_viewings')
116
116
  viewer_as_class.class_eval <<-EOS
117
- has_many :viewings, :foreign_key => :viewer_id, :class_name => #{viewing_class.to_s}
117
+ has_many :viewings, foreign_key: :viewer_id, class_name: '#{viewing_class.to_s}', dependent: :delete_all
118
118
  EOS
119
119
  end
120
120
  end
@@ -1,9 +1,9 @@
1
1
  module RedmineCrm
2
2
  class AssetsManager
3
3
  def self.install_assets
4
- return unless Gem.loaded_specs['redmine_crm']
5
- source = File.join(Gem.loaded_specs['redmine_crm'].full_gem_path, 'vendor', 'assets')
6
- destination = File.join(Dir.pwd, 'public', 'plugin_assets', 'redmine_crm')
4
+ return unless Gem.loaded_specs[GEM_NAME]
5
+ source = File.join(Gem.loaded_specs[GEM_NAME].full_gem_path, 'vendor', 'assets')
6
+ destination = File.join(Dir.pwd, 'public', 'plugin_assets', GEM_NAME)
7
7
  return unless File.directory?(source)
8
8
 
9
9
  source_files = Dir[source + '/**/*']
@@ -5,13 +5,15 @@ module RedmineCrm
5
5
  def select2_assets
6
6
  return if @select2_tag_included
7
7
  @select2_tag_included = true
8
- javascript_include_tag('select2', :plugin => 'redmine_crm') + stylesheet_link_tag('select2', :plugin => 'redmine_crm')
8
+ javascript_include_tag('select2', plugin: GEM_NAME) +
9
+ stylesheet_link_tag('select2', plugin: GEM_NAME) +
10
+ javascript_include_tag('select2_helpers', plugin: GEM_NAME)
9
11
  end
10
12
 
11
13
  def chartjs_assets
12
14
  return if @chartjs_tag_included
13
15
  @chartjs_tag_included = true
14
- javascript_include_tag('Chart.bundle.min', :plugin => 'redmine_crm')
16
+ javascript_include_tag('Chart.bundle.min', plugin: GEM_NAME)
15
17
  end
16
18
  end
17
19
  end
@@ -15,6 +15,10 @@ module RedmineCrm
15
15
  # * <tt>:data</tt> Load dropdown options from a local array if +url+ option not set.
16
16
  # * <tt>:placeholder</tt> Supports displaying a placeholder value.
17
17
  # * <tt>:include_hidden</tt> Adds hidden field after select when +multiple+ option true. Default value true.
18
+ # * <tt>:allow_clear</tt> Provides support for clearable selections. Default value false.
19
+ # * <tt>:min_input_length</tt> Minimum number of characters required to start a search. Default value 0.
20
+ # * <tt>:format_state</tt> Defines template of search results in the drop-down.
21
+ # * <tt>:tags</tt> Used to enable tagging feature.
18
22
  #
19
23
  # <b>Note:</b> The HTML specification says when +multiple+ parameter passed to select and all options got deselected
20
24
  # web browsers do not send any value to server.
@@ -22,102 +26,51 @@ module RedmineCrm
22
26
  # In case if you don't want the helper to generate this hidden field you can specify
23
27
  # <tt>include_hidden: false</tt> option.
24
28
  #
29
+ # <b>Note:</b> Select2 assets must be available on a page.
30
+ # To include select2 assets to a page, you need to use the helper select2_assets.
31
+ # For example:
32
+ # <% content_for :header_tags do %>
33
+ # <%= select2_assets %>
34
+ # <% end %>
35
+ #
25
36
  # Also aliased as: select2
26
37
  #
27
38
  # select2 'city_id', options_for_select(...)
28
39
  #
29
40
  def select2_tag(name, option_tags = nil, options = {})
30
- id = sanitize_to_id(name)
31
- placeholder = options[:placeholder] || 'Select ...'
41
+ s = select_tag(name, option_tags, options)
32
42
 
33
- content_for(:header_tags) { select2_assets }
34
- result = select_tag(name, option_tags, options)
35
43
  if options[:multiple] && options.fetch(:include_hidden, true)
36
- result << hidden_field_tag("#{name}[]", '')
44
+ s << hidden_field_tag("#{name}[]", '')
37
45
  end
38
46
 
39
- result << javascript_tag(<<-JS)
40
- $(function () {
41
- $('select#' + '#{id}').select2({
42
- #{select2_data_source_options(options)},
43
- #{select2_tags_options(options)},
44
- placeholder: '#{placeholder}'
45
- });
46
- });
47
- JS
47
+ s + javascript_tag("select2Tag('#{sanitize_to_id(name)}', #{options.to_json});")
48
48
  end
49
49
 
50
50
  alias select2 select2_tag
51
51
 
52
- # Transforms select filter field into select2
52
+ # Transforms select filters of +type+ fields into select2
53
53
  #
54
54
  # ==== Examples
55
- # transform_to_select2 'issue_tags', url: auto_complete_tags_url
56
- # transform_to_select2 'manager_id', format_state: 'formatStateWithAvatar', min_input_length: 1, url: '/managers'
55
+ # transform_to_select2 'tags', url: auto_complete_tags_url
56
+ # transform_to_select2 'people', format_state: 'formatStateWithAvatar', min_input_length: 1, url: '/managers'
57
57
  #
58
58
  # ==== Options
59
59
  # * <tt>:url</tt> Defines URL to search remote data using the ajax.
60
60
  # * <tt>:format_state</tt> Defines template of search results in the drop-down.
61
61
  # * <tt>:min_input_length</tt> Minimum number of characters required to start a search. Default value 0.
62
62
  # * <tt>:width</tt> Sets the width of the control. Default value '60%'.
63
+ # * <tt>:multiple</tt> Supports multi-value select box. If set to false the selection will not allow multiple choices. Default value true.
63
64
  #
64
- def transform_to_select2(field, options = {})
65
- return if field.empty?
66
-
67
- result = ''.html_safe
68
- unless @transform_to_select2_included
69
- result << javascript_include_tag('select2_helpers', plugin: 'redmine_crm')
70
- @transform_to_select2_included = true
71
- end
72
-
73
- result << javascript_tag(<<-JS)
74
- select2Filters['#{field}'] = {
75
- url: '#{options[:url].to_s}',
76
- formatState: #{options.fetch(:format_state, 'undefined')},
77
- minimumInputLength: #{options.fetch(:min_input_length, 0)},
78
- width: '#{options.fetch(:with, '60%')}'
79
- };
80
- JS
81
- end
82
-
83
- private
84
-
85
- def select2_data_source_options(options = {})
86
- if options[:url].to_s.empty?
87
- "data: #{options.fetch(:data, []).to_json}"
88
- else
89
- "ajax: {
90
- url: '#{options[:url]}',
91
- dataType: 'json',
92
- delay: 250,
93
- data: function (params) {
94
- return { q: params.term };
95
- },
96
- processResults: function (data, params) {
97
- return { results: data };
98
- },
99
- cache: true
100
- }"
101
- end
102
- end
103
-
104
- def select2_tags_options(options = {})
105
- if options.fetch(:tags, false)
106
- "tags: true,
107
- tokenSeparators: [','],
108
- createTag: function (params) {
109
- var term = $.trim(params.term);
110
- if (term === '' || term.indexOf(',') > -1) {
111
- return null; // Return null to disable tag creation
112
- }
113
- return {
114
- id: term,
115
- text: term
116
- }
117
- }"
118
- else
119
- 'tags: false'
120
- end
65
+ # <b>Note:</b> Select2 assets must be available on a page.
66
+ # To include select2 assets to a page, you need to use the helper select2_assets.
67
+ # For example:
68
+ # <% content_for :header_tags do %>
69
+ # <%= select2_assets %>
70
+ # <% end %>
71
+ #
72
+ def transform_to_select2(type, options = {})
73
+ javascript_tag("setSelect2Filter('#{type}', #{options.to_json});") unless type.empty?
121
74
  end
122
75
  end
123
76
  end
@@ -1,3 +1,3 @@
1
1
  module RedmineCrm
2
- VERSION = "0.0.37"
2
+ VERSION = '0.0.38'
3
3
  end
@@ -1,39 +1,168 @@
1
- var oldToggleFilter = window.toggleFilter;
1
+ var SELECT2_DELAY = 250;
2
2
 
3
- window.toggleFilter = function (field) {
4
- oldToggleFilter(field);
5
- return transform_to_select2(field);
3
+ var select2Filters = {};
4
+
5
+ function setSelect2Filter(type, options) {
6
+ if (typeof operatorByType === 'undefined') { return }
7
+
8
+ operatorByType[type] = operatorByType[type] || operatorByType['list_optional'];
9
+ select2Filters[type] = options;
6
10
  };
7
11
 
8
- function formatStateWithAvatar(opt) {
9
- return $('<span>' + opt.avatar + '&nbsp;' + opt.text + '</span>');
12
+
13
+ var originBuildFilterRow = buildFilterRow;
14
+ buildFilterRow = function (field, operator, values) {
15
+ originBuildFilterRow(field, operator, values);
16
+
17
+ var options = select2Options(field);
18
+ if (options) {
19
+ setSelect2FilterValues(field, options, values);
20
+ transformToSelect2(field, options);
21
+ }
10
22
  };
11
23
 
12
- var select2Filters = {};
13
24
 
14
- function transform_to_select2(field) {
15
- field = field.replace('.', '_');
16
- var filter = select2Filters[field];
17
- if (filter !== undefined && $('#tr_' + field + ' .values .select2').size() == 0) {
18
- $('#tr_' + field + ' .toggle-multiselect').hide();
19
- $('#tr_' + field + ' .values .value').attr('multiple', 'multiple');
20
- $('#tr_' + field + ' .values .value').select2({
21
- ajax: {
22
- url: filter['url'],
23
- dataType: 'json',
24
- delay: 250,
25
- data: function (params) {
26
- return {q: params.term};
27
- },
28
- processResults: function (data, params) {
29
- return {results: data};
30
- },
31
- cache: true
32
- },
33
- placeholder: ' ',
34
- minimumInputLength: filter['minimumInputLength'],
35
- width: filter['width'],
36
- templateResult: filter['formatState']
37
- });
25
+ function select2Options(field) {
26
+ var filter = availableFilters[field];
27
+ var options = select2Filters[filter['type']];
28
+
29
+ if (!options && filter['field_format']) {
30
+ options = select2Filters[field]
31
+ }
32
+
33
+ return options;
34
+ };
35
+
36
+
37
+ function setSelect2FilterValues(field, options, values) {
38
+ var needAddValues = !rowHasSelectTag(field);
39
+ if (needAddValues) { addSelectTag(field) }
40
+
41
+ var $select = findSelectTagInRowBy(field);
42
+ if (options['multiple'] !== false) { $select.attr('multiple', true) }
43
+
44
+ if (needAddValues) { addOptionTags($select, field, values); }
45
+ };
46
+
47
+
48
+ function addSelectTag(field) {
49
+ var fieldId = sanitizeToId(field);
50
+ $('#tr_' + fieldId).find('td.values').append(
51
+ '<span style="display:none;"><select class="value" id="values_'+fieldId+'_1" name="v['+field+'][]"></select></span>'
52
+ );
53
+ };
54
+
55
+
56
+ function addOptionTags($select, field, values) {
57
+ var filterValues = availableFilters[field]['values'];
58
+
59
+ for (var i = 0; i < filterValues.length; i++) {
60
+ var filterValue = filterValues[i];
61
+ var option = $('<option>');
62
+
63
+ if ($.isArray(filterValue)) {
64
+ option.val(filterValue[1]).text(filterValue[0]);
65
+ if ($.inArray(filterValue[1], values) > -1) { option.attr('selected', true); }
66
+ } else {
67
+ option.val(filterValue).text(filterValue);
68
+ if ($.inArray(filterValue, values) > -1) { option.attr('selected', true); }
38
69
  }
39
- };
70
+
71
+ $select.append(option);
72
+ }
73
+ };
74
+
75
+
76
+ function sanitizeToId(field) { return field.replace('.', '_') };
77
+
78
+ function findSelectTagInRowBy(field) {
79
+ return findInRowBy(field, '.values select.value');
80
+ };
81
+
82
+ function rowHasSelectTag(field) {
83
+ return findInRowBy(field, '.values select.value').size() > 0;
84
+ };
85
+
86
+ function rowHasSelect2(field) {
87
+ return findInRowBy(field, '.values .select2').size() > 0;
88
+ };
89
+
90
+ function findInRowBy(field, selector) {
91
+ return $('#tr_' + sanitizeToId(field) + ' ' + selector);
92
+ };
93
+
94
+ function formatStateWithAvatar(opt) {
95
+ return $('<span>' + opt.avatar + '&nbsp;' + opt.text + '</span>');
96
+ };
97
+
98
+
99
+ function transformToSelect2(field, options) {
100
+ if (rowHasSelect2(field)) { return }
101
+
102
+ findInRowBy(field, '.toggle-multiselect').hide();
103
+ findSelectTagInRowBy(field).select2(buildSelect2Options(options));
104
+ };
105
+
106
+
107
+ function select2Tag(id, options) {
108
+ $(function () {
109
+ $('select#' + id).select2(buildSelect2Options(options));
110
+ });
111
+ };
112
+
113
+
114
+ function buildSelect2Options(options) {
115
+ result = {
116
+ placeholder: options['placeholder'] || '',
117
+ allowClear: !!options['allow_clear'],
118
+ minimumInputLength: options['min_input_length'] || 0,
119
+ templateResult: window[options['format_state']],
120
+ width: options['width'] || '60%'
121
+ };
122
+
123
+ addDataSourceOptions(result, options);
124
+ addTagsOptions(result, options);
125
+
126
+ return result;
127
+ };
128
+
129
+
130
+ function addDataSourceOptions(target, options) {
131
+ if (options['url']) {
132
+ target['ajax'] = {
133
+ url: options['url'],
134
+ dataType: 'json',
135
+ delay: SELECT2_DELAY,
136
+ data: function (params) {
137
+ return { q: params.term };
138
+ },
139
+ processResults: function (data, params) {
140
+ return { results: data };
141
+ },
142
+ cache: true
143
+ };
144
+ } else {
145
+ target['data'] = options['data'] || [];
146
+ }
147
+ };
148
+
149
+
150
+ function addTagsOptions(target, options) {
151
+ if (options['tags']) {
152
+ target['tags'] = true;
153
+ target['tokenSeparators'] = [','];
154
+ target['createTag'] = createTag;
155
+ } else {
156
+ target['tags'] = false;
157
+ }
158
+ };
159
+
160
+
161
+ function createTag(params) {
162
+ var term = $.trim(params.term);
163
+ if (term === '' || term.indexOf(',') > -1) {
164
+ return null; // Return null to disable tag creation
165
+ }
166
+
167
+ return { id: term, text: term };
168
+ };
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redmine_crm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.37
4
+ version: 0.0.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - RedmineUP
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-28 00:00:00.000000000 Z
11
+ date: 2018-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails