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 +4 -4
- data/bitbucket-pipelines.yml +1 -1
- data/lib/redmine_crm.rb +4 -0
- data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +3 -3
- data/lib/redmine_crm/assets_manager.rb +3 -3
- data/lib/redmine_crm/helpers/external_assets_helper.rb +4 -2
- data/lib/redmine_crm/helpers/form_tag_helper.rb +27 -74
- data/lib/redmine_crm/version.rb +1 -1
- data/vendor/assets/javascripts/select2_helpers.js +161 -32
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ade85cd3ada9dbdf2283e26488fc7a8ae0eeb93
|
4
|
+
data.tar.gz: 1c872961e53a3f1186ee4283cb08a15b264b3fe2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07c4211ffc5be1a3322a8eec1dc7ccfdaabe77b8edc8cade7a486b0a51852a728b78144c31c3f5c998c18ef11d954a24000f646f58f23bb98e57723dda3dca4d
|
7
|
+
data.tar.gz: 6527ee07dbcc1e52cd240e03c70dbf6ac00d32ef43b0af638940572896eb239e8cc7bb444927a74570845ca3501d474615a584fb126860fa52401499c9ef24bd
|
data/bitbucket-pipelines.yml
CHANGED
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, :
|
91
|
-
belongs_to :viewer, :
|
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, :
|
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[
|
5
|
-
source = File.join(Gem.loaded_specs[
|
6
|
-
destination = File.join(Dir.pwd, 'public', 'plugin_assets',
|
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', :
|
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', :
|
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
|
-
|
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
|
-
|
44
|
+
s << hidden_field_tag("#{name}[]", '')
|
37
45
|
end
|
38
46
|
|
39
|
-
|
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
|
52
|
+
# Transforms select filters of +type+ fields into select2
|
53
53
|
#
|
54
54
|
# ==== Examples
|
55
|
-
# transform_to_select2 '
|
56
|
-
# transform_to_select2 '
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
data/lib/redmine_crm/version.rb
CHANGED
@@ -1,39 +1,168 @@
|
|
1
|
-
var
|
1
|
+
var SELECT2_DELAY = 250;
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
-
|
9
|
-
|
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
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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 + ' ' + 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.
|
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-
|
11
|
+
date: 2018-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|